Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
9084e18
Updated .gitignore and installed hardhat on local repo
zodiacbuilds Jun 15, 2023
ad5e9d2
Updated .gitignore and installed hardhat on local machine
zodiacbuilds Jun 15, 2023
e236359
Installed dotenv
zodiacbuilds Jun 15, 2023
9b1bda0
Installed dotenv
zodiacbuilds Jun 16, 2023
1612d21
Created array for Shard IDs, Added functions for minting individual e…
zodiacbuilds Jun 18, 2023
19127eb
Added mapping of Shard ID to enclave, Event Emitter for FE handler.
zodiacbuilds Jun 19, 2023
ea81bdf
Removed TemplarMetadata.sol
zodiacbuilds Jun 19, 2023
f1450d1
Made tweaks to basic syntax errors.
zodiacbuilds Jun 20, 2023
88297c0
Added .DS_Store to .gitignore. Addressed queries and
zodiacbuilds Jun 21, 2023
11a429b
Adding new comments on each line and continuing to debug type definit…
zodiacbuilds Jun 22, 2023
2e2d8aa
Added Hash Constant for each Enclave Shard.
zodiacbuilds Jun 22, 2023
ec66841
Corrected chainid
zodiacbuilds Jun 22, 2023
dbdab93
Added mapping for ENCLAVE and SHARD_ID.
zodiacbuilds Jun 23, 2023
206e10f
Shortened code.
zodiacbuilds Jun 24, 2023
10423cd
Added comments to every line
zodiacbuilds Jun 24, 2023
6396911
Added intended contract specs in commentary
zodiacbuilds Jun 24, 2023
92da525
Removed grantRole and used onlyOwner.
zodiacbuilds Jun 25, 2023
1682efb
Removed redundant imported libraries.
zodiacbuilds Jun 25, 2023
d654aff
Updated Hardhat
zodiacbuilds Jun 26, 2023
123f84d
Testing adding v18 to .nvmrc to fix node version error
zodiacbuilds Jun 26, 2023
8849dc3
Reset package.json
zodiacbuilds Jun 27, 2023
fce9a25
Fixed dependencies in package.json.
zodiacbuilds Jun 27, 2023
a891e9a
//TODO complete draft of unit tests for PathOfTheTemplarShard.
zodiacbuilds Jun 30, 2023
21d3c00
Added files to .gitignore
zodiacbuilds Jun 30, 2023
649b1c1
//TODO complete the test draft.
zodiacbuilds Jul 1, 2023
ad4abd1
Revert to original
zodiacbuilds Jul 1, 2023
af999d6
Switched Greeter to Initialize in deploy.js
zodiacbuilds Jul 3, 2023
4cd44f4
Added constants and signature reversion test case
zodiacbuilds Jul 3, 2023
c3ed623
update to yarn, hardhat
frontier159 Jul 3, 2023
ea04fa0
Initialised repo. Installed yarn.
zodiacbuilds Jul 7, 2023
0edf11d
Added goerli to hardhat.config.ts
zodiacbuilds Jul 7, 2023
1b4b2ee
Renamed contract
zodiacbuilds Jul 7, 2023
2462295
Updated branch with _shardIndex
zodiacbuilds Jul 7, 2023
64ab0f8
//TODO Fix test case for signer calling mint and signer obtaining min…
zodiacbuilds Jul 7, 2023
a8733fb
Declared new constants for signMessage from _signTypedData from wagmi…
zodiacbuilds Jul 11, 2023
f3e3c65
Correct contract name typo in deploy.js. Added await to signature const
zodiacbuilds Jul 12, 2023
fe068d1
Updated right address for minter and message signer
zodiacbuilds Jul 12, 2023
da08997
Removed package-lock.json and reinstalled yarn
zodiacbuilds Jul 12, 2023
4c86452
Fix nonce declaration and MintRequestStruct reference
zodiacbuilds Jul 14, 2023
70af4eb
Fix add2 as signer and add3 as minter
zodiacbuilds Jul 14, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .DS_Store
Binary file not shown.
29 changes: 24 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,28 @@
node_modules
.vscode
.env
coverage
coverage.json
typechain
.DS_Store
node_modules
venv
getPrivateKeys.js

# Hardhat files
artifacts-hardhat
cache-hardhat

#Hardhat files
# Forge files
artifacts-foundry
cache-foundry

# Slither cache
cache
artifacts

# autogenerated types
typechain
dist

# Coverage
coverage
coverage.json
lcov.info
report
4 changes: 4 additions & 0 deletions .mocharc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"require": "ts-node/register/files",
"timeout": 20000
}
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v18
6 changes: 6 additions & 0 deletions .solcover.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
skipFiles: [
'util/ABDKMath', // ABDKMath has issues compiling in solcover
'fakes', // Ignore fakes
]
};
8 changes: 8 additions & 0 deletions .solhint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "solhint:recommended",
"rules": {
"func-visibility": ["warn",{"ignoreConstructors":true}],
"compiler-version": ["error","^0.8.17"],
"reason-string": ["warn",{"maxLength":32}]
}
}
5 changes: 3 additions & 2 deletions contracts/PartnerMinter.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pragma solidity ^0.8.0;
pragma solidity 0.8.18;
// SPDX-License-Identifier: AGPL-3.0-or-later

import "@openzeppelin/contracts/access/Ownable.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

interface IRelic {
function balanceOf(address) external returns (uint256);
Expand Down
240 changes: 240 additions & 0 deletions contracts/PathofTheTemplarShard.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
pragma solidity 0.8.18;
// SPDX-License-Identifier: AGPL-3.0-or-later

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {Counters} from "@openzeppelin/contracts/utils/Counters.sol";

/**
* @notice interfaced from Relic.sol to obtain
* information from Relic.sol regarding enclave type.
*/
interface IRelic {
function getRelicInfos(uint256 enclaves) external returns (uint256);
}

/**
Intended contract specs:
* 1) Interface with Relic and Shards
* 2) Implement EIP 712 to concatenate signed message, expected deadline and expected nonce into a hash
* 3) Recover the address of the account calling the function using the digest and signature through this hash
* 4) Map Shards to each enclave
* 5) Allow a verified signer to mint the chosen Enclave Shard

*/
/**
* @notice interfaced from Shards.sol to obtain address, token Id, amount owned and stored data
* for future use
*/
interface IShards {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: put interfaces in an external file

function partnerMint(
address account,
uint256 id,
uint256 amount,
bytes memory data
) external;
}

/**
* @title This contract aims to allow a user to mint
* an Enclave Shard corresponding to the Enclave quest
* upon reaching the winning state of Path of the Temple.
* It uses EIP712 to verify that a user has signed the hashed message
*/
contract PathOfTheTemplarShard is Ownable {
IShards private SHARDS;
IRelic private RELIC;
//Mapping SHARD_ID to the individual enclaves
uint256[] public SHARD_ID = [2, 3, 4, 5, 6];
string[] public ENCLAVE = [
"",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the empty string for?

"chaosEnclave",
"mysteryEnclave",
"logicEnclave",
"structureEnclave",
"orderEnclave"
];

using Counters for Counters.Counter;

// Defining the CONSTANTS which are of bytes32 type
bytes32 constant MINTREQUEST_TYPEHASH =
keccak256("MintRequest(address signer,uint256 deadline,uint256 nonce)");
bytes32 constant EIP712DOMAIN_TYPEHASH =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add address verifyingContract

bytes32 private constant EIP712DOMAIN_TYPEHASH =
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as seen here

keccak256("EIP712Domain(string name,string version,uint256 chainId)");
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public immutable DOMAIN_SEPARATOR;

// MintRequest struct has variables of account, deadline and nonce types.
struct MintRequest {
address account;
uint256 deadline;
uint256 nonce;
}

// Defining EIP712 Domain struct with variables of name, version and chain id.
struct EIP712Domain {
string name;
string version;
uint256 chainId;
}

//error definition for when msg.sender is not signer
error MintForbidden();
error InvalidMint(address account);

// error definitions for passing checks related to the hashed message and signature
error DeadlineExpired(uint256 lateBy);
error InvalidNonce(address account);
error InvalidSignature(address account);

// MinterSet event takes the minter and value as parameters once an address calling the setMinter function
// passes the check to be updated with the minter role
event MinterSet(address indexed minter, bool value);

// modifier applied so that if the account calling the function is not the minter, the tx will
// revert with the Mint Forbidden message.
modifier canMint() {
if (!minters[msg.sender]) {
revert MintForbidden();
}

_;
}
//mapping role for minting to the address calling mint function if check is passed
mapping(address => bool) public minters;
//mapping the Shard ID from its declared array to the Enclave names
mapping(uint256 => string) public shardToEnclave;
// mapping address to nonces for incremental counter
mapping(address => Counters.Counter) public nonces;

// Constructor occurs just once during deployment of contract
// original deployer is granted the default admin role
// Shards and domain separator constant is initialised
// using name, version and Arbitrum Goerli chainID.
constructor() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you have not set SHARDS or RELIC

if (msg.sender != owner()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't think this check is necessary

revert("Only contract owner can deploy");
}

DOMAIN_SEPARATOR = hash(
EIP712Domain({
name: "PathOfTheTemplarShard",
version: "1",
chainId: 421613
})
);
}

// setMintRequest grants the address calling this function the ability to mint if the check
// using EIP712 standard below are passed (with signature verification, deadline and nonce)
function mintShard(
MintRequest calldata request,
bytes calldata signature,
uint256 _shardIndex
) external {
_relayMintRequestFor(request, signature);
if (_shardIndex < SHARD_ID.length || _shardIndex > SHARD_ID.length) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you choose to maintain establishMapping, also have a bool mapped variable that you set to true after mapping.
In which case:

if (!mapped || shardToEnclave[_shardIndex] == "") {
  revert ...
}

revert InvalidMint(msg.sender);
}
SHARDS.partnerMint(msg.sender, SHARD_ID[_shardIndex], 1, "");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you have not set SHARDS to an address

}

//for loop checks if the Enclave name matches the Shard ID
function establishMapping() public {
// Establish the mapping between SHARD_ID and ENCLAVE
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gas: uint256 _length = SHARD_ID.length;. and then use _length in the for loop

for (uint256 i = 2; i < SHARD_ID.length; i++) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this for loop doesn't map all values. starting from 2, you miss chaosEnclave.

uint256 _length = SHARD_ID.length;
for(uint i=0; i<_length) {
  shardToEnclave[SHARD_ID[i]] = ENCLAVE[i+1];
  unchecked {
    ++i;
  }
} 

You could also do this in the constructor as it's a one-time thing

shardToEnclave[SHARD_ID[i]] = ENCLAVE[i];
}
}

// Shard Id corresponding to Enclave can be viewed publically by anyone calling this function
function getEnclaveForShard(
uint256 shardId
) public view returns (string memory) {
return shardToEnclave[shardId];
}

// Only contract owner may call the minter role for an account that has passed the check.
// the minter role corresponding to the account that passed is stored in value.
function setMinter(address account, bool value) external onlyOwner {
minters[account] = value;
//emit the new role for the account
emit MinterSet(account, value);
}

// Function takes two parameters request and signature
function _relayMintRequestFor(
MintRequest calldata request,
bytes calldata signature
) internal {
//concatenates the three values into a hash readable as a digest via a keccak256 hash function
bytes32 digest = keccak256(
abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, hash(request))
);
// stores address into signer and error recovery in err and use recover to verify digest and signature
// is from address calling function
(address signer, ECDSA.RecoverError err) = ECDSA.tryRecover(
digest,
signature
);
// Check for error in signature recovery process
if (err != ECDSA.RecoverError.NoError) {
revert InvalidSignature(request.account);
}
// Check for error if deadline is expired
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I would put checks at beginning of function

if (block.timestamp > request.deadline)
revert DeadlineExpired(block.timestamp - request.deadline);
// Check for error if signer is whitelisted minter
if (!minters[signer]) revert InvalidSignature(request.account);
// Checks for error if nonce is valid for requesting address
if (_useNonce(request.account) != request.nonce)
revert InvalidNonce(request.account);
}

/**
* "Consume a nonce": return the current value and increment. This would be done by the dev wallet
* which is owner of the contract (ie trusted TEMPLE EOA)
*/
function _useNonce(address _owner) internal returns (uint256 current) {
Counters.Counter storage nonce = nonces[_owner];
current = nonce.current();
nonce.increment();
}

/**
* @dev hash function stores custom data type QuestCompletedMessageReq as input
* in a bytes32 hash from data input values of name, version and chainId.
*/
function hash(EIP712Domain memory _input) internal pure returns (bytes32) {
return
keccak256(
abi.encode(
EIP712DOMAIN_TYPEHASH,
keccak256(bytes(_input.name)),
keccak256(bytes(_input.version)),
_input.chainId
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add verifyingAddress address(this). see link from previous comment

);
}

/**
* @dev functions creates a hash from signer, deadline and nonce and returns it as a bytes32 hash.
*/
function hash(MintRequest memory _input) internal pure returns (bytes32) {
return
keccak256(
abi.encode(
MINTREQUEST_TYPEHASH,
_input.account,
_input.deadline,
_input.nonce
)
);
}

// function creates a hash from input and returns it as a bytes32 hash
function hash(uint256[] memory _input) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(_input));
}
}
32 changes: 18 additions & 14 deletions contracts/Relic.sol
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
pragma solidity 0.8.18;
// SPDX-License-Identifier: AGPL-3.0-or-later

// &@@#
// @@@@@@ @@@@@@@
// (@@@@@@@, &@@@@@@@@@@@
Expand All @@ -17,17 +20,17 @@
// #@@@@@@@@@@@@@@@@@@@@@@@*
// (@@@@@@@@@@@(

pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import { ERC721URIStorage } from "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import { ERC721Enumerable } from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import { Pausable } from "@openzeppelin/contracts/security/Pausable.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { ERC721Burnable } from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import { Counters } from "@openzeppelin/contracts/utils/Counters.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import { IERC1155Receiver } from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";

interface IShards {
function equipShard(
Expand Down Expand Up @@ -169,7 +172,7 @@ contract Relic is
function supportsInterface(bytes4 interfaceId)
public
view
override(IERC165, ERC721, ERC721Enumerable)
override(IERC165, ERC721, ERC721Enumerable, ERC721URIStorage)
returns (bool)
{
return super.supportsInterface(interfaceId);
Expand Down Expand Up @@ -264,9 +267,10 @@ contract Relic is
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
uint256 firstTokenId,
uint256 batchSize
) internal override(ERC721, ERC721Enumerable) whenNotPaused {
super._beforeTokenTransfer(from, to, tokenId);
super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
}

function _burn(uint256 tokenId)
Expand Down
18 changes: 9 additions & 9 deletions contracts/Shards.sol
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
pragma solidity 0.8.18;
// SPDX-License-Identifier: AGPL-3.0-or-later

// .@@@@@@@@@@@@@@@
// .@@ @@
// .@@ @@
Expand All @@ -18,15 +21,12 @@
// @@ @@
// @@@@@@@@@@@@@@@

pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

import { ERC1155 } from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { Pausable } from "@openzeppelin/contracts/security/Pausable.sol";
import { ERC1155Burnable } from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol";
import { ERC1155Supply } from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol";

interface IRelic {
function getRelicId(address _owner) external view returns (uint256);
Expand Down
Loading