diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..1385806 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,15 @@ +{ + "overrides": [ + { + "files": "*.sol", + "options": { + "printWidth": 80, + "tabWidth": 2, + "useTabs": false, + "singleQuote": false, + "bracketSpacing": false, + "explicitTypes": "always" + } + } + ] +} \ No newline at end of file diff --git a/contracts/Migrations.sol b/contracts/Migrations.sol index 4a77984..da6be22 100644 --- a/contracts/Migrations.sol +++ b/contracts/Migrations.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.10; contract Migrations { address public owner = msg.sender; - uint public last_completed_migration; + uint256 public last_completed_migration; modifier restricted() { require( @@ -13,7 +13,7 @@ contract Migrations { _; } - function setCompleted(uint completed) external restricted { + function setCompleted(uint256 completed) external restricted { last_completed_migration = completed; } diff --git a/contracts/core/BETimelockController.sol b/contracts/core/BETimelockController.sol index 44d1a45..87720c3 100644 --- a/contracts/core/BETimelockController.sol +++ b/contracts/core/BETimelockController.sol @@ -7,39 +7,51 @@ contract BETimelockController is TimelockController { uint256 public constant MAX_DELAY = 16 days; uint256 private _minDelay; - constructor( - address[] memory proposers, - address[] memory executors) - TimelockController(MIN_DELAY, proposers, executors){ - _minDelay = MIN_DELAY; + constructor(address[] memory proposers, address[] memory executors) + TimelockController(MIN_DELAY, proposers, executors) + { + _minDelay = MIN_DELAY; } + /** + * @dev Returns the minimum delay for an operation to become valid. + * + * This value can be changed by executing an operation that calls `updateDelay`. + */ + function getMinDelay() + public + view + virtual + override + returns (uint256 duration) + { + return _minDelay; + } /** - * @dev Returns the minimum delay for an operation to become valid. - * - * This value can be changed by executing an operation that calls `updateDelay`. - */ - function getMinDelay() public view virtual override returns (uint256 duration) { - return _minDelay; - } - - /** - * @dev Changes the minimum timelock duration for future operations. - * - * Emits a {MinDelayChange} event. - * - * Requirements: - * - * - the caller must be the timelock itself. This can only be achieved by scheduling and later executing - * an operation where the timelock is the target and the data is the ABI-encoded call to this function. - */ - function updateDelay(uint256 newDelay) external virtual override { - require(msg.sender == address(this), "BETimelockController: caller must be timelock"); - require(newDelay >= MIN_DELAY, "BETimelockController: newDelay must greater than or equal to MIN_DELAY"); - require(newDelay <= MAX_DELAY, "BETimelockController: newDelay must less than or equal to MAX_DELAY"); - emit MinDelayChange(_minDelay, newDelay); - _minDelay = newDelay; - } + * @dev Changes the minimum timelock duration for future operations. + * + * Emits a {MinDelayChange} event. + * + * Requirements: + * + * - the caller must be the timelock itself. This can only be achieved by scheduling and later executing + * an operation where the timelock is the target and the data is the ABI-encoded call to this function. + */ + function updateDelay(uint256 newDelay) external virtual override { + require( + msg.sender == address(this), + "BETimelockController: caller must be timelock" + ); + require( + newDelay >= MIN_DELAY, + "BETimelockController: newDelay must greater than or equal to MIN_DELAY" + ); + require( + newDelay <= MAX_DELAY, + "BETimelockController: newDelay must less than or equal to MAX_DELAY" + ); + emit MinDelayChange(_minDelay, newDelay); + _minDelay = newDelay; + } } - diff --git a/contracts/core/HasSignature.sol b/contracts/core/HasSignature.sol index 0398d71..169dbee 100644 --- a/contracts/core/HasSignature.sol +++ b/contracts/core/HasSignature.sol @@ -4,136 +4,123 @@ import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "../utils/Approval.sol"; -contract HasSignature is Ownable, Approval{ - bytes32 private immutable _CACHED_DOMAIN_SEPARATOR; - uint256 private immutable _CACHED_CHAIN_ID; - address private immutable _CACHED_THIS; +contract HasSignature is Ownable, Approval { + bytes32 private immutable _CACHED_DOMAIN_SEPARATOR; + uint256 private immutable _CACHED_CHAIN_ID; + address private immutable _CACHED_THIS; - bytes32 private immutable _HASHED_NAME; - bytes32 private immutable _HASHED_VERSION; - bytes32 private immutable _TYPE_HASH; - mapping(bytes => bool) private _usedSignatures; + bytes32 private immutable _HASHED_NAME; + bytes32 private immutable _HASHED_VERSION; + bytes32 private immutable _TYPE_HASH; + mapping(bytes => bool) private _usedSignatures; - constructor(string memory name, string memory version) { - bytes32 hashedName = keccak256(bytes(name)); - bytes32 hashedVersion = keccak256(bytes(version)); - bytes32 typeHash = keccak256( - "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" - ); - _HASHED_NAME = hashedName; - _HASHED_VERSION = hashedVersion; - _CACHED_CHAIN_ID = block.chainid; - _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator( - typeHash, - hashedName, - hashedVersion - ); - _CACHED_THIS = address(this); - _TYPE_HASH = typeHash; - } + constructor(string memory name, string memory version) { + bytes32 hashedName = keccak256(bytes(name)); + bytes32 hashedVersion = keccak256(bytes(version)); + bytes32 typeHash = keccak256( + "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" + ); + _HASHED_NAME = hashedName; + _HASHED_VERSION = hashedVersion; + _CACHED_CHAIN_ID = block.chainid; + _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator( + typeHash, + hashedName, + hashedVersion + ); + _CACHED_THIS = address(this); + _TYPE_HASH = typeHash; + } - function _buildDomainSeparator( - bytes32 typeHash, - bytes32 nameHash, - bytes32 versionHash - ) private view returns (bytes32) { - return - keccak256( - abi.encode( - typeHash, - nameHash, - versionHash, - block.chainid, - address(this) - ) - ); - } + function _buildDomainSeparator( + bytes32 typeHash, + bytes32 nameHash, + bytes32 versionHash + ) private view returns (bytes32) { + return + keccak256( + abi.encode( + typeHash, + nameHash, + versionHash, + block.chainid, + address(this) + ) + ); + } - /** - * @dev Returns the domain separator for the current chain. - */ - function _domainSeparatorV4() internal view returns (bytes32) { - if ( - address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID - ) { - return _CACHED_DOMAIN_SEPARATOR; - } else { - return - _buildDomainSeparator( - _TYPE_HASH, - _HASHED_NAME, - _HASHED_VERSION - ); - } + /** + * @dev Returns the domain separator for the current chain. + */ + function _domainSeparatorV4() internal view returns (bytes32) { + if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) { + return _CACHED_DOMAIN_SEPARATOR; + } else { + return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION); } + } - /** - * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this - * function returns the hash of the fully encoded EIP712 message for this domain. - * - * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: - * - * ```solidity - * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( - * keccak256("Mail(address to,string contents)"), - * mailTo, - * keccak256(bytes(mailContents)) - * ))); - * address signer = ECDSA.recover(digest, signature); - * ``` - */ - function _hashTypedDataV4(bytes32 structHash) - internal - view - virtual - returns (bytes32) - { - return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash); - } + /** + * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this + * function returns the hash of the fully encoded EIP712 message for this domain. + * + * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: + * + * ```solidity + * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( + * keccak256("Mail(address to,string contents)"), + * mailTo, + * keccak256(bytes(mailContents)) + * ))); + * address signer = ECDSA.recover(digest, signature); + * ``` + */ + function _hashTypedDataV4(bytes32 structHash) + internal + view + virtual + returns (bytes32) + { + return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash); + } - function checkSigner712( - address signer, - bytes32 structHash, - bytes memory signature - ) public view{ - bytes32 digest = _hashTypedDataV4(structHash); - address recovered = ECDSA.recover(digest, signature); - require(recovered == signer, "[BE] invalid signature"); - require(signer != address(0), "ECDSA: invalid signature"); - } + function checkSigner712( + address signer, + bytes32 structHash, + bytes memory signature + ) public view { + bytes32 digest = _hashTypedDataV4(structHash); + address recovered = ECDSA.recover(digest, signature); + require(recovered == signer, "[BE] invalid signature"); + require(signer != address(0), "ECDSA: invalid signature"); + } - function checkSigner( - address signer, - bytes32 hash, - bytes memory signature - ) public pure { - require(signature.length == 65, "[BE] invalid signature length"); - bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash( - hash - ); - - address recovered = ECDSA.recover(ethSignedMessageHash, signature); - require(recovered == signer, "[BE] invalid signature"); + function checkSigner( + address signer, + bytes32 hash, + bytes memory signature + ) public pure { + require(signature.length == 65, "[BE] invalid signature length"); + bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(hash); + + address recovered = ECDSA.recover(ethSignedMessageHash, signature); + require(recovered == signer, "[BE] invalid signature"); + } + + modifier signatureValid(bytes calldata signature) { + require( + !_usedSignatures[signature], + "signature used. please send another transaction with new signature" + ); + _; + } + + /** + * @dev mark signature used + */ + function useSignature(bytes calldata signature) public approvaled { + if (!_usedSignatures[signature]) { + _usedSignatures[signature] = true; } - - modifier signatureValid( - bytes calldata signature - ) { - require( - !_usedSignatures[signature], - "signature used. please send another transaction with new signature" - ); - _; - } - /** - * @dev mark signature used - */ - function useSignature( - bytes calldata signature - ) public approvaled { - if (!_usedSignatures[signature]) { - _usedSignatures[signature] = true; - } - } - + } } diff --git a/contracts/interfaces/IBEERC1155.sol b/contracts/interfaces/IBEERC1155.sol index a120830..474a31a 100644 --- a/contracts/interfaces/IBEERC1155.sol +++ b/contracts/interfaces/IBEERC1155.sol @@ -4,20 +4,23 @@ pragma solidity 0.8.10; import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; interface IBEERC1155 is IERC1155 { - function mintBatch( - address to, - uint256[] memory ids, - uint256[] memory amounts, - bytes memory data - ) external; + function mintBatch( + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) external; - function burnBatch( - address owner, - uint256[] memory ids, - uint256[] memory values - ) external; + function burnBatch( + address owner, + uint256[] memory ids, + uint256[] memory values + ) external; - function balanceOf(address account, uint256 id) external view returns (uint256); + function balanceOf(address account, uint256 id) + external + view + returns (uint256); - function canMint(uint256 id) external view returns (bool); + function canMint(uint256 id) external view returns (bool); } diff --git a/contracts/interfaces/IBEERC721.sol b/contracts/interfaces/IBEERC721.sol index 2887012..a48ddf8 100644 --- a/contracts/interfaces/IBEERC721.sol +++ b/contracts/interfaces/IBEERC721.sol @@ -3,10 +3,10 @@ pragma solidity 0.8.10; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; - - interface IBEERC721 is IERC721 { - function mint(address to, uint256 tokenId) external; - function burn(address owner, uint256 tokenId) external; - function ownerOf(uint256 tokenId) external view returns (address owner); + function mint(address to, uint256 tokenId) external; + + function burn(address owner, uint256 tokenId) external; + + function ownerOf(uint256 tokenId) external view returns (address owner); } diff --git a/contracts/interfaces/IEvolveFactory.sol b/contracts/interfaces/IEvolveFactory.sol index af350ca..4613cc2 100644 --- a/contracts/interfaces/IEvolveFactory.sol +++ b/contracts/interfaces/IEvolveFactory.sol @@ -19,9 +19,7 @@ interface IEvolveFactory { uint256 startTime, uint256 saltNonce, bytes calldata signature - ) external; - - function useSignature( - bytes calldata signature ) external; + + function useSignature(bytes calldata signature) external; } diff --git a/contracts/logic/EvolveFactory.sol b/contracts/logic/EvolveFactory.sol index 0c5b18e..e3cfe95 100644 --- a/contracts/logic/EvolveFactory.sol +++ b/contracts/logic/EvolveFactory.sol @@ -18,14 +18,9 @@ contract EvolveFactory is Ownable, TimeChecker, Initializable, HasSignature { address public executor; - event TokenEvolved( - address indexed owner, - uint256[] tokenIds - ); + event TokenEvolved(address indexed owner, uint256[] tokenIds); - constructor() - HasSignature("EvolveFactory", "1"){ - } + constructor() HasSignature("EvolveFactory", "1") {} function init(address chipAddress) external initializer onlyOwner { chip = IBEERC1155(chipAddress); @@ -35,7 +30,7 @@ contract EvolveFactory is Ownable, TimeChecker, Initializable, HasSignature { * @dev update executor */ function updateExecutor(address account) external onlyOwner { - require(account != address(0), 'address can not be zero'); + require(account != address(0), "address can not be zero"); executor = account; } @@ -46,9 +41,9 @@ contract EvolveFactory is Ownable, TimeChecker, Initializable, HasSignature { uint256 saltNonce, bytes calldata signature, IBEERC721 nft - ) external signatureValid(signature) timeValid(startTime){ + ) external signatureValid(signature) timeValid(startTime) { require( - tokenIds[0] > 0 && tokenIds[1] > 0, + tokenIds[0] > 0 && tokenIds[1] > 0, "EvolveFactory: token to evolve and burn can not be 0" ); @@ -69,7 +64,7 @@ contract EvolveFactory is Ownable, TimeChecker, Initializable, HasSignature { } uint256[] memory signArray = new uint256[](3); - for (uint256 i = 0; i < tokenIds.length; ++ i) { + for (uint256 i = 0; i < tokenIds.length; ++i) { uint256 _id = tokenIds[i]; signArray[i] = _id; } @@ -83,15 +78,14 @@ contract EvolveFactory is Ownable, TimeChecker, Initializable, HasSignature { nft.burn(to, tokenIds[1]); if (tokenIds[2] > 0) { uint256 amount = 1; - chip.burnBatch(to, - tokenIds[2].asSingletonArray(), - amount.asSingletonArray()); + chip.burnBatch( + to, + tokenIds[2].asSingletonArray(), + amount.asSingletonArray() + ); } useSignature(signature); - emit TokenEvolved( - to, - signArray - ); + emit TokenEvolved(to, signArray); } function evolveChip( @@ -100,14 +94,14 @@ contract EvolveFactory is Ownable, TimeChecker, Initializable, HasSignature { uint256 startTime, uint256 saltNonce, bytes calldata signature - ) external signatureValid(signature) timeValid(startTime){ + ) external signatureValid(signature) timeValid(startTime) { require(to != address(0), "EvolveFacrory: address is zero address"); uint256 len = tokenIds.length; - uint256[] memory amounts = new uint256[](len -1); + uint256[] memory amounts = new uint256[](len - 1); uint256[] memory idsForBurn = new uint256[](len - 1); - for (uint256 i = 0; i < len; ++ i) { + for (uint256 i = 0; i < len; ++i) { require( - chip.balanceOf(to, tokenIds[i]) > 0, + chip.balanceOf(to, tokenIds[i]) > 0, "EvolveFacrory: Chip specified not exists" ); if (i > 0) { @@ -115,15 +109,17 @@ contract EvolveFactory is Ownable, TimeChecker, Initializable, HasSignature { amounts[i - 1] = 1; } } - bytes32 criteriaMessageHash = getMessageHash(to, startTime, saltNonce, tokenIds); + bytes32 criteriaMessageHash = getMessageHash( + to, + startTime, + saltNonce, + tokenIds + ); checkSigner(executor, criteriaMessageHash, signature); chip.burnBatch(to, idsForBurn, amounts); useSignature(signature); - emit TokenEvolved( - to, - tokenIds - ); - } + emit TokenEvolved(to, tokenIds); + } function getMessageHash( address _to, @@ -138,5 +134,4 @@ contract EvolveFactory is Ownable, TimeChecker, Initializable, HasSignature { } return keccak256(encoded); } - } diff --git a/contracts/logic/MinterFactory.sol b/contracts/logic/MinterFactory.sol index 37f9e59..1e04cee 100644 --- a/contracts/logic/MinterFactory.sol +++ b/contracts/logic/MinterFactory.sol @@ -12,285 +12,299 @@ import "../utils/TimeChecker.sol"; import "../core/HasSignature.sol"; import "./FactoryBase.sol"; -contract MinterFactory is Ownable, FactoryBase, TimeChecker, Initializable, HasSignature { - using UInt for uint256; - using SafeERC20 for IERC20; - address public executor; - // NFT contract - IBEERC721 public hero; - IBEERC721 public equip; - IBEERC1155 public chip; - IBEERC1155 public shard; +contract MinterFactory is + Ownable, + FactoryBase, + TimeChecker, + Initializable, + HasSignature +{ + using UInt for uint256; + using SafeERC20 for IERC20; + address public executor; + // NFT contract + IBEERC721 public hero; + IBEERC721 public equip; + IBEERC1155 public chip; + IBEERC1155 public shard; - address public feeToAddress; + address public feeToAddress; - event TokenMinted( - address contractAddress, - address to, - uint256 indexed tokenId + event TokenMinted( + address contractAddress, + address to, + uint256 indexed tokenId + ); + + event TokenMintedBatch( + address contractAddress, + address indexed to, + uint256[] ids, + uint256[] amounts + ); + + constructor() HasSignature("MinterFactory", "1") {} + + function init(address[4] calldata _erc721s) external initializer onlyOwner { + hero = IBEERC721(_erc721s[0]); + equip = IBEERC721(_erc721s[1]); + chip = IBEERC1155(_erc721s[2]); + shard = IBEERC1155(_erc721s[3]); + } + + /** + * @dev update executor + */ + function updateExecutor(address account) external onlyOwner { + require(account != address(0), "address can not be zero"); + executor = account; + } + + function setFeeToAddress(address _feeToAddress) external onlyOwner { + require( + _feeToAddress != address(0), + "fee received address can not be zero" + ); + feeToAddress = _feeToAddress; + } + + /** + * @dev mint function to distribute Hero NFT to user + */ + function mintHeroTo(address to, uint256 tokenId) external onlyOwner { + mint721NFT(to, tokenId, hero); + } + + /** + * @dev mint function to distribute Equipment NFT to user + */ + function mintEquipTo(address to, uint256 tokenId) external onlyOwner { + mint721NFT(to, tokenId, equip); + } + + /** + * @dev mint function to distribute Chip NFT to user + */ + function mintChipTo(address to, uint256 tokenId) external onlyOwner { + mint1155NFT(to, tokenId, 1, chip); + } + + /** + * @dev mint function to distribute Shard NFT to user + */ + function mintShardTo(address to, uint256 tokenId) external onlyOwner { + mint1155NFT(to, tokenId, 1, shard); + } + + /** + * @dev batch mint 1155 Chip to user + */ + function mintChipBatch(address to, uint256[] memory ids) external onlyOwner { + require( + to != address(0), + "MinterFactory::mintChipBatch: to address can not be zero" + ); + require( + ids.length > 0, + "MinterFactory::mintChipBatch: ids cannot be empty" + ); + uint256[] memory amounts = new uint256[](ids.length); + uint256 len = ids.length; + for (uint256 i = 0; i < len; ++i) { + amounts[i] = 1; + } + mint1155NFTBatch(to, ids, amounts, chip); + } + + /** + * @dev batch mint 1155 Shard to user + */ + function mintShardBatch( + address to, + uint256[] memory ids, + uint256[] memory amounts + ) external onlyOwner { + require(to != address(0), "MinterFactory: to address can not be zero"); + require(ids.length > 0, "MinterFactory: ids cannot be empty"); + require( + ids.length == amounts.length, + "MinterFactory: ids and amounts length mismatch" + ); + mint1155NFTBatch(to, ids, amounts, shard); + } + + function mint721ByUser( + address to, + uint256 id, + uint256 startTime, + uint256 saltNonce, + bytes calldata signature, + IBEERC721 nft + ) external signatureValid(signature) timeValid(startTime) { + uint256[] memory signArray = new uint256[](1); + signArray[0] = id; + bytes32 criteriaMessageHash = getMessageHash( + to, + address(nft), + startTime, + saltNonce, + signArray + ); + checkSigner(executor, criteriaMessageHash, signature); + mint721NFT(to, id, nft); + useSignature(signature); + } + + function mint1155BatchByUser( + address to, + uint256[] memory ids, + uint256[] memory amounts, + uint256 startTime, + uint256 saltNonce, + bytes calldata signature, + IBEERC1155 nft + ) external signatureValid(signature) timeValid(startTime) { + uint256 len = ids.length; + require(len > 0, "MinterFactory: ids cannot be empty"); + require( + len == amounts.length, + "MinterFactory: ids and amounts length mismatch" + ); + uint256[] memory signArray = new uint256[](len * 2); + for (uint256 i = 0; i < len; ++i) { + require( + nft.canMint(ids[i]), + "MinterFactory: can not mint for current nft rule setting" + ); + signArray[i * 2] = ids[i]; + signArray[i * 2 + 1] = amounts[i]; + } + bytes32 criteriaMessageHash = getMessageHash( + to, + address(nft), + startTime, + saltNonce, + signArray + ); + checkSigner(executor, criteriaMessageHash, signature); + mint1155NFTBatch(to, ids, amounts, nft); + useSignature(signature); + } + + function shardMixByUser( + ShardParam memory param, + uint256[] memory ids, + uint256[] memory amounts, + bytes calldata signature, + IBEERC721 nft + ) external signatureValid(signature) timeValid(param.startTime) { + require(ids.length > 0, "MinterFactory: ids cannot be empty"); + require( + ids.length == amounts.length, + "MinterFactory: ids and amounts length mismatch" ); - - event TokenMintedBatch( - address contractAddress, - address indexed to, - uint256[] ids, - uint256[] amounts + uint256[] memory signArray = new uint256[](ids.length * 2); + for (uint256 i = 0; i < ids.length; ++i) { + require( + shard.balanceOf(param.to, ids[i]) > 0, + "MinterFactory: not enough shard" + ); + signArray[i * 2] = ids[i]; + signArray[i * 2 + 1] = amounts[i]; + } + bytes32 criteriaMessageHash = getShardMixHash( + param, + address(nft), + signArray ); + checkSigner(executor, criteriaMessageHash, signature); + // Check payment approval and buyer balance + IERC20 paymentContract = IERC20(param.payToken); + require( + paymentContract.balanceOf(param.to) >= param.payAmount, + "MinterFactory: doesn't have enough token to mix shard" + ); + require( + paymentContract.allowance(param.to, address(this)) >= param.payAmount, + "MinterFactory: doesn't approve MinterFactory to spend payment amount" + ); + // transfer money to address + paymentContract.safeTransferFrom(param.to, feeToAddress, param.payAmount); + shard.burnBatch(param.to, ids, amounts); + mint721NFT(param.to, param.nftId, nft); + useSignature(signature); + } + function mint721NFT( + address to, + uint256 tokenId, + IBEERC721 nft + ) internal { + require(to != address(0), "MinterFactory: to address can not be zero"); + nft.mint(to, tokenId); + emit TokenMinted(address(nft), to, tokenId); + } - constructor() HasSignature("MinterFactory", "1") {} + function mint1155NFT( + address to, + uint256 id, + uint256 amount, + IBEERC1155 nft + ) internal { + require(to != address(0), "MinterFactory: to address can not be zero"); + nft.mintBatch(to, id.asSingletonArray(), amount.asSingletonArray(), ""); + emit TokenMinted(address(chip), to, id); + } - function init(address[4] calldata _erc721s) external initializer onlyOwner { - hero = IBEERC721(_erc721s[0]); - equip = IBEERC721(_erc721s[1]); - chip = IBEERC1155(_erc721s[2]); - shard = IBEERC1155(_erc721s[3]); + function mint1155NFTBatch( + address to, + uint256[] memory ids, + uint256[] memory amounts, + IBEERC1155 nft + ) internal { + nft.mintBatch(to, ids, amounts, ""); + emit TokenMintedBatch(address(nft), to, ids, amounts); + } + + function getMessageHash( + address _to, + address _nftAddress, + uint256 _startTime, + uint256 _saltNonce, + uint256[] memory _ids + ) public pure returns (bytes32) { + bytes memory encoded = abi.encodePacked( + _to, + _nftAddress, + _startTime, + _saltNonce + ); + uint256 len = _ids.length; + for (uint256 i = 0; i < len; ++i) { + encoded = bytes.concat(encoded, abi.encodePacked(_ids[i])); } - + return keccak256(encoded); + } - /** - * @dev update executor - */ - function updateExecutor(address account) external onlyOwner { - require(account != address(0), "address can not be zero"); - executor = account; - } - - function setFeeToAddress(address _feeToAddress) external onlyOwner { - require(_feeToAddress != address(0), 'fee received address can not be zero'); - feeToAddress = _feeToAddress; - } - - /** - * @dev mint function to distribute Hero NFT to user - */ - function mintHeroTo(address to, uint256 tokenId) external onlyOwner { - mint721NFT(to, tokenId, hero); - } - - /** - * @dev mint function to distribute Equipment NFT to user - */ - function mintEquipTo(address to, uint256 tokenId) external onlyOwner { - mint721NFT(to, tokenId, equip); - } - - /** - * @dev mint function to distribute Chip NFT to user - */ - function mintChipTo(address to, uint256 tokenId) external onlyOwner { - mint1155NFT(to, tokenId, 1, chip); - } - - /** - * @dev mint function to distribute Shard NFT to user - */ - function mintShardTo(address to, uint256 tokenId) external onlyOwner { - mint1155NFT(to, tokenId, 1, shard); - } - - /** - * @dev batch mint 1155 Chip to user - */ - function mintChipBatch(address to, uint256[] memory ids) - external - onlyOwner - { - require( - to != address(0), - "MinterFactory::mintChipBatch: to address can not be zero" - ); - require( - ids.length > 0, - "MinterFactory::mintChipBatch: ids cannot be empty" - ); - uint256[] memory amounts = new uint256[](ids.length); - uint256 len = ids.length; - for (uint256 i = 0; i < len; ++i) { - amounts[i] = 1; - } - mint1155NFTBatch(to, ids, amounts, chip); - } - - /** - * @dev batch mint 1155 Shard to user - */ - function mintShardBatch( - address to, - uint256[] memory ids, - uint256[] memory amounts - ) external onlyOwner { - require(to != address(0), "MinterFactory: to address can not be zero"); - require(ids.length > 0, "MinterFactory: ids cannot be empty"); - require( - ids.length == amounts.length, - "MinterFactory: ids and amounts length mismatch" - ); - mint1155NFTBatch(to, ids, amounts, shard); - } - - function mint721ByUser( - address to, - uint256 id, - uint256 startTime, - uint256 saltNonce, - bytes calldata signature, - IBEERC721 nft - ) external signatureValid(signature) timeValid(startTime){ - uint256[] memory signArray = new uint256[](1); - signArray[0] = id; - bytes32 criteriaMessageHash = - getMessageHash(to, address(nft), startTime, saltNonce, signArray); - checkSigner(executor, criteriaMessageHash, signature); - mint721NFT(to, id, nft); - useSignature(signature); - } - - function mint1155BatchByUser( - address to, - uint256[] memory ids, - uint256[] memory amounts, - uint256 startTime, - uint256 saltNonce, - bytes calldata signature, - IBEERC1155 nft - ) external signatureValid(signature) timeValid(startTime){ - uint256 len = ids.length; - require(len > 0, "MinterFactory: ids cannot be empty"); - require( - len == amounts.length, - "MinterFactory: ids and amounts length mismatch" - ); - uint256[] memory signArray = new uint256[](len * 2); - for (uint256 i = 0; i < len; ++i) { - require( - nft.canMint(ids[i]), - "MinterFactory: can not mint for current nft rule setting" - ); - signArray[i * 2] = ids[i]; - signArray[i * 2 + 1] = amounts[i]; - } - bytes32 criteriaMessageHash = - getMessageHash(to, address(nft), startTime, saltNonce, signArray); - checkSigner(executor, criteriaMessageHash, signature); - mint1155NFTBatch(to, ids, amounts, nft); - useSignature(signature); - } - - function shardMixByUser( - ShardParam memory param, - uint256[] memory ids, - uint256[] memory amounts, - bytes calldata signature, - IBEERC721 nft - ) external signatureValid(signature) timeValid(param.startTime) { - require(ids.length > 0, "MinterFactory: ids cannot be empty"); - require( - ids.length == amounts.length, - "MinterFactory: ids and amounts length mismatch" - ); - - uint256[] memory signArray = new uint256[](ids.length * 2); - for (uint256 i = 0; i < ids.length; ++i) { - require( - shard.balanceOf(param.to, ids[i]) > 0, - "MinterFactory: not enough shard" - ); - signArray[i * 2] = ids[i]; - signArray[i * 2 + 1] = amounts[i]; - } - bytes32 criteriaMessageHash = - getShardMixHash(param, address(nft), signArray); - checkSigner(executor, criteriaMessageHash, signature); - // Check payment approval and buyer balance - IERC20 paymentContract = IERC20(param.payToken); - require( - paymentContract.balanceOf(param.to) >= param.payAmount, - "MinterFactory: doesn't have enough token to mix shard" - ); - require( - paymentContract.allowance(param.to, address(this)) >= param.payAmount, - "MinterFactory: doesn't approve MinterFactory to spend payment amount" - ); - // transfer money to address - paymentContract.safeTransferFrom( - param.to, - feeToAddress, - param.payAmount - ); - shard.burnBatch(param.to, ids, amounts); - mint721NFT(param.to, param.nftId, nft); - useSignature(signature); - } - - function mint721NFT( - address to, - uint256 tokenId, - IBEERC721 nft - ) internal { - require(to != address(0), "MinterFactory: to address can not be zero"); - nft.mint(to, tokenId); - emit TokenMinted(address(nft), to, tokenId); - } - - function mint1155NFT( - address to, - uint256 id, - uint256 amount, - IBEERC1155 nft - ) internal { - require(to != address(0), "MinterFactory: to address can not be zero"); - nft.mintBatch(to, id.asSingletonArray(), amount.asSingletonArray(), ""); - emit TokenMinted(address(chip), to, id); - } - - function mint1155NFTBatch( - address to, - uint256[] memory ids, - uint256[] memory amounts, - IBEERC1155 nft - ) internal { - nft.mintBatch(to, ids, amounts, ""); - emit TokenMintedBatch(address(nft), to, ids, amounts); - } - - - function getMessageHash( - address _to, - address _nftAddress, - uint256 _startTime, - uint256 _saltNonce, - uint256[] memory _ids - ) public pure returns (bytes32) { - bytes memory encoded = - abi.encodePacked(_to, _nftAddress, _startTime, _saltNonce); - uint256 len = _ids.length; - for (uint256 i = 0; i < len; ++i) { - encoded = bytes.concat(encoded, abi.encodePacked(_ids[i])); - } - return keccak256(encoded); - } - - function getShardMixHash( - ShardParam memory param, - address nftAddress, - uint256[] memory _ids - ) internal pure returns (bytes32) { - bytes memory encoded = - abi.encodePacked( - param.to, - nftAddress, - param.nftId, - param.payToken, - param.payAmount, - param.startTime, - param.saltNonce - ); - uint256 len = _ids.length; - for (uint256 i = 0; i < len; ++i) { - encoded = bytes.concat(encoded, abi.encodePacked(_ids[i])); - } - return keccak256(encoded); + function getShardMixHash( + ShardParam memory param, + address nftAddress, + uint256[] memory _ids + ) internal pure returns (bytes32) { + bytes memory encoded = abi.encodePacked( + param.to, + nftAddress, + param.nftId, + param.payToken, + param.payAmount, + param.startTime, + param.saltNonce + ); + uint256 len = _ids.length; + for (uint256 i = 0; i < len; ++i) { + encoded = bytes.concat(encoded, abi.encodePacked(_ids[i])); } + return keccak256(encoded); + } } diff --git a/contracts/logic/MysteryBoxProxy.sol b/contracts/logic/MysteryBoxProxy.sol index 619a692..80b04b5 100644 --- a/contracts/logic/MysteryBoxProxy.sol +++ b/contracts/logic/MysteryBoxProxy.sol @@ -8,165 +8,153 @@ import "../interfaces/IBEERC721.sol"; import "../core/HasSignature.sol"; contract MysteryBoxProxy is Ownable, Initializable, HasSignature { - IBEERC721 public box; - IBEERC721 public hero; - IBEERC721 public equip; - IBEERC721 public chip; + IBEERC721 public box; + IBEERC721 public hero; + IBEERC721 public equip; + IBEERC721 public chip; - uint8 public constant TYPE_NONE = 0; - uint8 public constant TYPE_HERO = 1; - uint8 public constant TYPE_EQUIP = 2; - uint8 public constant TYPE_CHIP = 3; + uint8 public constant TYPE_NONE = 0; + uint8 public constant TYPE_HERO = 1; + uint8 public constant TYPE_EQUIP = 2; + uint8 public constant TYPE_CHIP = 3; - address public executor; + address public executor; - mapping(bytes => bool) public usedSignatures; + mapping(bytes => bool) public usedSignatures; - event TokenMinted( - address contractAddress, - address to, - uint256 indexed tokenId + event TokenMinted( + address contractAddress, + address to, + uint256 indexed tokenId + ); + + event BoxOpened( + address indexed to, + uint256 indexed boxId, + uint256 val, + uint256[3] ids, + uint8[3] types + ); + + constructor() HasSignature("MysteryBoxProxy", "1") {} + + function init(address[4] calldata _erc721s) external initializer onlyOwner { + hero = IBEERC721(_erc721s[0]); + equip = IBEERC721(_erc721s[1]); + chip = IBEERC721(_erc721s[2]); + box = IBEERC721(_erc721s[3]); + } + + /** + * @dev update executor + */ + function updateExecutor(address account) external onlyOwner { + require(account != address(0), "address can not be zero"); + executor = account; + } + + function mintBoxTo(address to, uint256 tokenId) external onlyOwner { + require(to != address(0), "to address can not be zero"); + box.mint(to, tokenId); + emit TokenMinted(address(box), to, tokenId); + } + + function openBox( + uint256 boxId, + uint256[3] calldata ids, + uint256 saltNonce, + bytes calldata signature + ) external { + require(ids.length == 3, "MysteryBoxProxy: amount of token id mismatch"); + require( + !usedSignatures[signature], + "MysteryBoxProxy: signature used. please send another transaction with new signature" ); - - event BoxOpened( - address indexed to, - uint256 indexed boxId, - uint256 val, - uint256[3] ids, - uint8[3] types + address owner = msg.sender; + require( + box.ownerOf(boxId) == owner, + "MysteryBoxProxy: only owner can open this box" ); + bytes32 criteriaMessageHash = getMessageHash( + boxId, + ids[0], + ids[1], + ids[2], + saltNonce + ); + checkSigner(executor, criteriaMessageHash, signature); + // open box + box.burn(owner, boxId); + usedSignatures[signature] = true; - constructor() HasSignature("MysteryBoxProxy", "1") {} + uint256[3] memory results = [ids[0], 0, 0]; + uint8[3] memory types = [TYPE_HERO, TYPE_NONE, TYPE_NONE]; + mint721WithType(owner, ids[0], types[0]); + results[0] = ids[0]; - function init(address[4] calldata _erc721s) - external - initializer - onlyOwner - { - hero = IBEERC721(_erc721s[0]); - equip = IBEERC721(_erc721s[1]); - chip = IBEERC721(_erc721s[2]); - box = IBEERC721(_erc721s[3]); + uint256 val = rand(owner, saltNonce, 100); + if (val >= 70 && val < 90) { + types[1] = TYPE_CHIP; + mint721WithType(owner, ids[1], types[1]); + results[1] = ids[1]; + } else if (val >= 90 && val < 98) { + types[1] = TYPE_EQUIP; + mint721WithType(owner, ids[1], types[1]); + results[1] = ids[1]; + } else if (val >= 98) { + types[1] = TYPE_EQUIP; + mint721WithType(owner, ids[1], types[1]); + results[1] = ids[1]; + types[2] = TYPE_CHIP; + mint721WithType(owner, ids[2], types[2]); + results[2] = ids[2]; } + emit BoxOpened(owner, boxId, val, results, types); + } - /** - * @dev update executor - */ - function updateExecutor(address account) external onlyOwner { - require(account != address(0), "address can not be zero"); - executor = account; + function mint721WithType( + address to, + uint256 tokenId, + uint256 typeNum + ) private { + if (typeNum == 1) { + hero.mint(to, tokenId); + } else if (typeNum == 2) { + equip.mint(to, tokenId); + } else if (typeNum == 3) { + chip.mint(to, tokenId); } + } - function mintBoxTo(address to, uint256 tokenId) external onlyOwner{ - require(to != address(0), 'to address can not be zero'); - box.mint(to, tokenId); - emit TokenMinted(address(box), to, tokenId); - } + function rand( + address owner, + uint256 nonce, + uint256 _length + ) internal view returns (uint256) { + uint256 random = uint256( + keccak256( + abi.encodePacked(owner, nonce, block.difficulty, block.timestamp) + ) + ); + return random % _length; + } - function openBox( - uint256 boxId, - uint256[3] calldata ids, - uint256 saltNonce, - bytes calldata signature - ) external { - require( - ids.length == 3, - "MysteryBoxProxy: amount of token id mismatch" - ); - require( - !usedSignatures[signature], - "MysteryBoxProxy: signature used. please send another transaction with new signature" - ); - address owner = msg.sender; - require( - box.ownerOf(boxId) == owner, - "MysteryBoxProxy: only owner can open this box" - ); - bytes32 criteriaMessageHash = getMessageHash( - boxId, - ids[0], - ids[1], - ids[2], - saltNonce - ); - checkSigner(executor, criteriaMessageHash, signature); - // open box - box.burn(owner, boxId); - usedSignatures[signature] = true; - - uint256[3] memory results = [ids[0], 0, 0]; - uint8[3] memory types = [TYPE_HERO, TYPE_NONE, TYPE_NONE]; - mint721WithType(owner, ids[0], types[0]); - results[0] = ids[0]; - - uint256 val = rand(owner, saltNonce, 100); - if (val >= 70 && val < 90) { - types[1] = TYPE_CHIP; - mint721WithType(owner, ids[1], types[1]); - results[1] = ids[1]; - } else if (val >= 90 && val < 98) { - types[1] = TYPE_EQUIP; - mint721WithType(owner, ids[1], types[1]); - results[1] = ids[1]; - } else if (val >= 98) { - types[1] = TYPE_EQUIP; - mint721WithType(owner, ids[1], types[1]); - results[1] = ids[1]; - types[2] = TYPE_CHIP; - mint721WithType(owner, ids[2], types[2]); - results[2] = ids[2]; - } - emit BoxOpened(owner, boxId, val, results, types); - } - - function mint721WithType( - address to, - uint256 tokenId, - uint256 typeNum - ) private { - if (typeNum == 1) { - hero.mint(to, tokenId); - } else if (typeNum == 2) { - equip.mint(to, tokenId); - } else if (typeNum == 3) { - chip.mint(to, tokenId); - } - } - - function rand( - address owner, - uint256 nonce, - uint256 _length - ) internal view returns (uint256) { - uint256 random = uint256( - keccak256( - abi.encodePacked( - owner, - nonce, - block.difficulty, - block.timestamp - ) - ) - ); - return random % _length; - } - - function getMessageHash( - uint256 _boxId, - uint256 _firstToken, - uint256 _secondToken, - uint256 _thirdToken, - uint256 _saltNonce - ) public pure returns (bytes32) { - return - keccak256( - abi.encodePacked( - _boxId, - _firstToken, - _secondToken, - _thirdToken, - _saltNonce - ) - ); - } + function getMessageHash( + uint256 _boxId, + uint256 _firstToken, + uint256 _secondToken, + uint256 _thirdToken, + uint256 _saltNonce + ) public pure returns (bytes32) { + return + keccak256( + abi.encodePacked( + _boxId, + _firstToken, + _secondToken, + _thirdToken, + _saltNonce + ) + ); + } } diff --git a/contracts/logic/UserEvolveFactory.sol b/contracts/logic/UserEvolveFactory.sol index 74de53a..c9fcaef 100644 --- a/contracts/logic/UserEvolveFactory.sol +++ b/contracts/logic/UserEvolveFactory.sol @@ -10,7 +10,7 @@ contract UserEvolveFactory is Ownable, Initializable { IBEERC721 public hero; IBEERC721 public equip; - event TokenEvolveFail ( + event TokenEvolveFail( address indexed to, bytes signature, string reason, @@ -23,114 +23,83 @@ contract UserEvolveFactory is Ownable, Initializable { factory = IEvolveFactory(_nfts[2]); } - /** + /** * @dev evolve function Hero NFT * tokenIds: [hero_to_evolve, hero_for_burn, chip] */ function evolveHero( - uint256[3] calldata tokenIds, - uint256 startTime, - uint256 saltNonce, - bytes calldata signature - ) external returns (bool success){ + uint256[3] calldata tokenIds, + uint256 startTime, + uint256 saltNonce, + bytes calldata signature + ) external returns (bool success) { address to = _msgSender(); - try factory.evolve721NFT(to, tokenIds, startTime, saltNonce, signature, hero) { + try + factory.evolve721NFT(to, tokenIds, startTime, saltNonce, signature, hero) + { return true; } catch Error(string memory reason) { bytes memory by; factory.useSignature(signature); - emit TokenEvolveFail( - to, - signature, - reason, - by - ); + emit TokenEvolveFail(to, signature, reason, by); return false; } catch (bytes memory lowLevelData) { factory.useSignature(signature); string memory reason; - emit TokenEvolveFail( - to, - signature, - reason, - lowLevelData - ); - return false; - } - } - /** - * @dev evolve function for equip NFT - * tokenIds: [equip_to_evolve, equip_for_burn, chip] - */ - function evolveEquip( - uint256[3] calldata tokenIds, - uint256 startTime, - uint256 saltNonce, - bytes calldata signature - ) external returns (bool success){ - address to = _msgSender(); - try factory.evolve721NFT(to, tokenIds, startTime, saltNonce, signature, equip) { - return true; - } catch Error(string memory reason) { - bytes memory by; - factory.useSignature(signature); - emit TokenEvolveFail( - to, - signature, - reason, - by - ); - return false; - } catch (bytes memory lowLevelData) { - factory.useSignature(signature); - string memory reason; - emit TokenEvolveFail( - to, - signature, - reason, - lowLevelData - ); + emit TokenEvolveFail(to, signature, reason, lowLevelData); return false; } } /** - * @dev evolve function for chip + * @dev evolve function for equip NFT + * tokenIds: [equip_to_evolve, equip_for_burn, chip] */ - function evolveChip( - uint256[] memory ids, - uint256 startTime, - uint256 saltNonce, - bytes calldata signature - ) external returns (bool success){ + function evolveEquip( + uint256[3] calldata tokenIds, + uint256 startTime, + uint256 saltNonce, + bytes calldata signature + ) external returns (bool success) { address to = _msgSender(); - try factory.evolveChip( - to, - ids, - startTime, - saltNonce, - signature - ) { + try + factory.evolve721NFT(to, tokenIds, startTime, saltNonce, signature, equip) + { return true; } catch Error(string memory reason) { bytes memory by; factory.useSignature(signature); - emit TokenEvolveFail( - to, - signature, - reason, - by - ); + emit TokenEvolveFail(to, signature, reason, by); return false; } catch (bytes memory lowLevelData) { factory.useSignature(signature); string memory reason; - emit TokenEvolveFail( - to, - signature, - reason, - lowLevelData - ); + emit TokenEvolveFail(to, signature, reason, lowLevelData); + return false; + } + } + + /** + * @dev evolve function for chip + */ + function evolveChip( + uint256[] memory ids, + uint256 startTime, + uint256 saltNonce, + bytes calldata signature + ) external returns (bool success) { + address to = _msgSender(); + try factory.evolveChip(to, ids, startTime, saltNonce, signature) { + return true; + } catch Error(string memory reason) { + bytes memory by; + factory.useSignature(signature); + emit TokenEvolveFail(to, signature, reason, by); + return false; + } catch (bytes memory lowLevelData) { + factory.useSignature(signature); + string memory reason; + emit TokenEvolveFail(to, signature, reason, lowLevelData); return false; } } diff --git a/contracts/logic/UserMinterFactory.sol b/contracts/logic/UserMinterFactory.sol index 963feff..68c23c9 100644 --- a/contracts/logic/UserMinterFactory.sol +++ b/contracts/logic/UserMinterFactory.sol @@ -28,6 +28,7 @@ contract UserMinterFactory is Ownable, FactoryBase, Initializable { shard = IBEERC1155(addressArr[3]); factory = MinterFactory(addressArr[4]); } + /** * @dev mint hero by user */ @@ -36,32 +37,23 @@ contract UserMinterFactory is Ownable, FactoryBase, Initializable { uint256 startTime, uint256 saltNonce, bytes calldata signature - ) external returns (bool success){ + ) external returns (bool success) { address to = _msgSender(); - try factory.mint721ByUser(to, tokenId, startTime, saltNonce, signature, hero) { + try + factory.mint721ByUser(to, tokenId, startTime, saltNonce, signature, hero) + { return true; } catch Error(string memory reason) { bytes memory by; factory.useSignature(signature); - emit TokenMintFail( - to, - signature, - reason, - by - ); + emit TokenMintFail(to, signature, reason, by); return false; } catch (bytes memory lowLevelData) { factory.useSignature(signature); string memory reason; - emit TokenMintFail( - to, - signature, - reason, - lowLevelData - ); + emit TokenMintFail(to, signature, reason, lowLevelData); return false; } - } /** @@ -72,112 +64,104 @@ contract UserMinterFactory is Ownable, FactoryBase, Initializable { uint256 startTime, uint256 saltNonce, bytes calldata signature - ) external returns (bool success){ + ) external returns (bool success) { address to = _msgSender(); - try factory.mint721ByUser(to, tokenId, startTime, saltNonce, signature, equip) { + try + factory.mint721ByUser(to, tokenId, startTime, saltNonce, signature, equip) + { return true; } catch Error(string memory reason) { bytes memory by; factory.useSignature(signature); - emit TokenMintFail( - to, - signature, - reason, - by - ); + emit TokenMintFail(to, signature, reason, by); return false; } catch (bytes memory lowLevelData) { factory.useSignature(signature); string memory reason; - emit TokenMintFail( - to, - signature, - reason, - lowLevelData - ); + emit TokenMintFail(to, signature, reason, lowLevelData); return false; } - } /** - * @dev user batch mint 1155 chip - */ + * @dev user batch mint 1155 chip + */ function mintChipBatchUser( uint256[] memory ids, uint256 startTime, uint256 saltNonce, bytes calldata signature - ) external returns (bool success){ + ) external returns (bool success) { uint256 len = ids.length; uint256[] memory amounts = new uint256[](len); for (uint256 i = 0; i < len; ++i) { amounts[i] = 1; } address to = _msgSender(); - try factory.mint1155BatchByUser(to, ids, amounts, startTime, saltNonce, signature, chip) { + try + factory.mint1155BatchByUser( + to, + ids, + amounts, + startTime, + saltNonce, + signature, + chip + ) + { return true; - } catch Error(string memory reason) { + } catch Error(string memory reason) { bytes memory by; factory.useSignature(signature); - emit TokenMintFail( - to, - signature, - reason, - by - ); + emit TokenMintFail(to, signature, reason, by); return false; } catch (bytes memory lowLevelData) { factory.useSignature(signature); string memory reason; - emit TokenMintFail( - to, - signature, - reason, - lowLevelData - ); + emit TokenMintFail(to, signature, reason, lowLevelData); return false; } } /** - * @dev user batch mint 1155 shard - */ + * @dev user batch mint 1155 shard + */ function mintShardBatchUser( uint256[] memory ids, uint256[] memory amounts, uint256 startTime, uint256 saltNonce, bytes calldata signature - ) external returns (bool success){ + ) external returns (bool success) { address to = _msgSender(); - try factory.mint1155BatchByUser(to, ids, amounts, startTime, saltNonce, signature, shard) { + try + factory.mint1155BatchByUser( + to, + ids, + amounts, + startTime, + saltNonce, + signature, + shard + ) + { return true; } catch Error(string memory reason) { bytes memory by; factory.useSignature(signature); - emit TokenMintFail( - to, - signature, - reason, - by - ); + emit TokenMintFail(to, signature, reason, by); return false; } catch (bytes memory lowLevelData) { factory.useSignature(signature); string memory reason; - emit TokenMintFail( - to, - signature, - reason, - lowLevelData - ); + emit TokenMintFail(to, signature, reason, lowLevelData); return false; } } + /** - * @dev mint hero or equip with shard - */ + * @dev mint hero or equip with shard + */ function shardMixByUser( uint256 nftId, uint8 nftType, @@ -197,36 +181,24 @@ contract UserMinterFactory is Ownable, FactoryBase, Initializable { nft = equip; } ShardParam memory param = ShardParam( - to, nftId, payToken, payAmount, startTime, saltNonce); - try factory.shardMixByUser( - param, - ids, - amounts, - signature, - nft - ) { + to, + nftId, + payToken, + payAmount, + startTime, + saltNonce + ); + try factory.shardMixByUser(param, ids, amounts, signature, nft) { return true; } catch Error(string memory reason) { bytes memory by; factory.useSignature(signature); - emit TokenMintFail( - to, - signature, - reason, - by - ); + emit TokenMintFail(to, signature, reason, by); return false; } catch (bytes memory lowLevelData) { factory.useSignature(signature); string memory reason; - emit TokenMintFail( - to, - signature, - reason, - lowLevelData - ); + emit TokenMintFail(to, signature, reason, lowLevelData); } - - } - + } } diff --git a/contracts/market/BEBoxMall.sol b/contracts/market/BEBoxMall.sol index 9ab01e8..7e960dd 100644 --- a/contracts/market/BEBoxMall.sol +++ b/contracts/market/BEBoxMall.sol @@ -8,137 +8,150 @@ import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/governance/TimelockController.sol"; import "../core/HasSignature.sol"; -contract BEBoxMall is Ownable, HasSignature, TimelockController{ - using SafeERC20 for IERC20; - using Address for address; +contract BEBoxMall is Ownable, HasSignature, TimelockController { + using SafeERC20 for IERC20; + using Address for address; - uint256 public constant MIN_DELAY = 2 days; - uint256 public constant MAX_DELAY = 16 days; - uint256 private _minDelay; + uint256 public constant MIN_DELAY = 2 days; + uint256 public constant MAX_DELAY = 16 days; + uint256 private _minDelay; - bool public address_initialized; + bool public address_initialized; - constructor( - address[] memory proposers, - address[] memory executors) - TimelockController(MIN_DELAY, proposers, executors) - HasSignature("BEBoxMall", "1"){ - _minDelay = MIN_DELAY; - address_initialized = false; + constructor(address[] memory proposers, address[] memory executors) + TimelockController(MIN_DELAY, proposers, executors) + HasSignature("BEBoxMall", "1") + { + _minDelay = MIN_DELAY; + address_initialized = false; + } + + event BEBoxPaid( + uint256 indexed boxId, + address indexed buyer, + uint256 boxType, + uint256 price, + address paymentToken + ); + + address public paymentReceivedAddress; + + function setPaymentReceivedAddress(address _paymentReceivedAddress) public { + require( + _paymentReceivedAddress != address(0), + "BEBoxMall::setPaymentReceivedAddress: payment received address can not be zero" + ); + if (address_initialized) { + require( + msg.sender == address(this), + "BEBoxMall::setPaymentReceivedAddress: Call must come from BEBoxMall." + ); + } else { + require( + msg.sender == owner(), + "BEBoxMall::setPaymentReceivedAddress: First call must come from owner." + ); + address_initialized = true; } + paymentReceivedAddress = _paymentReceivedAddress; + } - event BEBoxPaid( - uint256 indexed boxId, - address indexed buyer, - uint256 boxType, - uint256 price, - address paymentToken + /** + * @dev BE box payment function + */ + function payForBoxWithSignature( + uint256 boxId, + uint256 _type, + address userAddress, + uint256 price, + address paymentErc20, + uint256 saltNonce, + bytes calldata signature + ) external onlyOwner signatureValid(signature) { + require( + !userAddress.isContract(), + "BEBoxPayment: Only user address is allowed to buy box" + ); + require(_type > 0, "BEBoxPayment: Invalid box type"); + require(price > 0, "BEBoxPayment: Invalid payment amount"); + bytes32 criteriaMessageHash = getMessageHash( + _type, + paymentErc20, + price, + saltNonce ); - address public paymentReceivedAddress; + checkSigner712(userAddress, criteriaMessageHash, signature); - function setPaymentReceivedAddress(address _paymentReceivedAddress) - public - { - require(_paymentReceivedAddress != address(0), 'BEBoxMall::setPaymentReceivedAddress: payment received address can not be zero'); - if (address_initialized) { - require(msg.sender == address(this), "BEBoxMall::setPaymentReceivedAddress: Call must come from BEBoxMall."); - } else { - require(msg.sender == owner(), "BEBoxMall::setPaymentReceivedAddress: First call must come from owner."); - address_initialized = true; - } - paymentReceivedAddress = _paymentReceivedAddress; - } + IERC20 paymentToken = IERC20(paymentErc20); + uint256 allowToPayAmount = paymentToken.allowance( + userAddress, + address(this) + ); + require(allowToPayAmount >= price, "BEBoxPayment: Invalid token allowance"); + // Transfer payment + paymentToken.safeTransferFrom(userAddress, paymentReceivedAddress, price); + useSignature(signature); + // Emit payment event + emit BEBoxPaid(boxId, userAddress, _type, price, paymentErc20); + } - /** - * @dev BE box payment function - */ - function payForBoxWithSignature( - uint256 boxId, - uint256 _type, - address userAddress, - uint256 price, - address paymentErc20, - uint256 saltNonce, - bytes calldata signature - ) external onlyOwner signatureValid(signature){ - require( - !userAddress.isContract(), - "BEBoxPayment: Only user address is allowed to buy box" - ); - require(_type > 0, "BEBoxPayment: Invalid box type"); - require(price > 0, "BEBoxPayment: Invalid payment amount"); - bytes32 criteriaMessageHash = getMessageHash( - _type, - paymentErc20, - price, - saltNonce - ); + function getMessageHash( + uint256 _boxType, + address _paymentErc20, + uint256 _price, + uint256 _saltNonce + ) public pure returns (bytes32) { + return + keccak256( + abi.encode( + keccak256( + "set(uint256 item,address token,uint256 price,uint256 salt)" + ), + _boxType, + _paymentErc20, + _price, + _saltNonce + ) + ); + } - checkSigner712(userAddress, criteriaMessageHash, signature); + /** + * @dev Returns the minimum delay for an operation to become valid. + * + * This value can be changed by executing an operation that calls `updateDelay`. + */ + function getMinDelay() + public + view + virtual + override + returns (uint256 duration) + { + return _minDelay; + } - IERC20 paymentToken = IERC20(paymentErc20); - uint256 allowToPayAmount = paymentToken.allowance( - userAddress, - address(this) - ); - require( - allowToPayAmount >= price, - "BEBoxPayment: Invalid token allowance" - ); - // Transfer payment - paymentToken.safeTransferFrom( - userAddress, - paymentReceivedAddress, - price - ); - useSignature(signature); - // Emit payment event - emit BEBoxPaid(boxId, userAddress, _type, price, paymentErc20); - } - - function getMessageHash( - uint256 _boxType, - address _paymentErc20, - uint256 _price, - uint256 _saltNonce - ) public pure returns (bytes32) { - return - keccak256( - abi.encode( - keccak256("set(uint256 item,address token,uint256 price,uint256 salt)"), - _boxType, - _paymentErc20, - _price, - _saltNonce - ) - ); - } - - /** - * @dev Returns the minimum delay for an operation to become valid. - * - * This value can be changed by executing an operation that calls `updateDelay`. - */ - function getMinDelay() public view virtual override returns (uint256 duration) { - return _minDelay; - } - - /** - * @dev Changes the minimum timelock duration for future operations. - * - * Emits a {MinDelayChange} event. - * - * Requirements: - * - * - the caller must be the timelock itself. This can only be achieved by scheduling and later executing - * an operation where the timelock is the target and the data is the ABI-encoded call to this function. - */ - function updateDelay(uint256 newDelay) external virtual override { - require(msg.sender == address(this), "BEBoxMall: caller must be timelock"); - require(newDelay >= MIN_DELAY, "BEBoxMall: newDelay must greater than or equal to MIN_DELAY"); - require(newDelay <= MAX_DELAY, "BEBoxMall: newDelay must less than or equal to MAX_DELAY"); - emit MinDelayChange(_minDelay, newDelay); - _minDelay = newDelay; - } + /** + * @dev Changes the minimum timelock duration for future operations. + * + * Emits a {MinDelayChange} event. + * + * Requirements: + * + * - the caller must be the timelock itself. This can only be achieved by scheduling and later executing + * an operation where the timelock is the target and the data is the ABI-encoded call to this function. + */ + function updateDelay(uint256 newDelay) external virtual override { + require(msg.sender == address(this), "BEBoxMall: caller must be timelock"); + require( + newDelay >= MIN_DELAY, + "BEBoxMall: newDelay must greater than or equal to MIN_DELAY" + ); + require( + newDelay <= MAX_DELAY, + "BEBoxMall: newDelay must less than or equal to MAX_DELAY" + ); + emit MinDelayChange(_minDelay, newDelay); + _minDelay = newDelay; + } } diff --git a/contracts/market/MarketPlace.sol b/contracts/market/MarketPlace.sol index 6a48340..00544e4 100644 --- a/contracts/market/MarketPlace.sol +++ b/contracts/market/MarketPlace.sol @@ -13,191 +13,191 @@ import "../core/HasSignature.sol"; // this contract will transfer ownership to BETimelockController after deployed // all onlyowner method would add timelock contract MarketPlace is Ownable, HasSignature { - using SafeERC20 for IERC20; - using SafeMath for uint256; + using SafeERC20 for IERC20; + using SafeMath for uint256; - // Supported payment token WETH & list of authorized ERC20 - mapping(address => bool) public paymentTokens; - mapping(bytes => bool) public usedSignatures; + // Supported payment token WETH & list of authorized ERC20 + mapping(address => bool) public paymentTokens; + mapping(bytes => bool) public usedSignatures; - // Address to receive transaction fee - address public feeToAddress; - uint256 public transactionFee; + // Address to receive transaction fee + address public feeToAddress; + uint256 public transactionFee; - uint256 public constant MIN_TRANSACTION_FEE = 50; - uint256 public constant MAX_TRANSACTION_FEE = 1000; + uint256 public constant MIN_TRANSACTION_FEE = 50; + uint256 public constant MAX_TRANSACTION_FEE = 1000; - // Events - event MatchTransaction( - uint256 indexed tokenId, - address contractAddress, - uint256 price, - address paymentToken, - address seller, - address buyer, - uint256 fee + // Events + event MatchTransaction( + uint256 indexed tokenId, + address contractAddress, + uint256 price, + address paymentToken, + address seller, + address buyer, + uint256 fee + ); + + constructor() HasSignature("MarketPlace", "1") {} + + function setFeeToAddress(address _feeToAddress) external onlyOwner { + require( + _feeToAddress != address(0), + "fee received address can not be zero" + ); + feeToAddress = _feeToAddress; + } + + function setTransactionFee(uint256 _transactionFee) external onlyOwner { + require( + _transactionFee >= MIN_TRANSACTION_FEE && + _transactionFee <= MAX_TRANSACTION_FEE, + "Marketplace: _transactionFee must >= 50 and <= 1000" + ); + transactionFee = _transactionFee; + } + + function setPaymentTokens(address[] calldata _paymentTokens) + external + onlyOwner + { + for (uint256 i = 0; i < _paymentTokens.length; i++) { + if (paymentTokens[_paymentTokens[i]]) { + continue; + } + + paymentTokens[_paymentTokens[i]] = true; + } + } + + function removePaymentTokens(address[] calldata _removedPaymentTokens) + external + onlyOwner + { + for (uint256 i = 0; i < _removedPaymentTokens.length; i++) { + paymentTokens[_removedPaymentTokens[i]] = false; + } + } + + function ignoreSignature( + address[2] calldata addresses, + uint256[3] calldata values, + bytes calldata signature + ) external signatureValid(signature) { + bytes32 criteriaMessageHash = getMessageHash( + addresses[0], + values[0], + addresses[1], + values[1], + values[2] ); - constructor() - HasSignature("MarketPlace", "1"){ + checkSigner(_msgSender(), criteriaMessageHash, signature); + useSignature(signature); + } + + /** + * @dev Function matched transaction with user signatures + */ + function matchTransaction( + address[3] calldata addresses, + uint256[3] calldata values, + bytes calldata signature + ) external signatureValid(signature) returns (bool) { + // address[3] [seller_address,nft_address,payment_token_address] + // uint256[3] [token_id,price,salt_nonce] + // bytes seller_signature + require(paymentTokens[addresses[2]], "Marketplace: invalid payment method"); + + bytes32 criteriaMessageHash = getMessageHash( + addresses[1], + values[0], + addresses[2], + values[1], + values[2] + ); + + checkSigner712(addresses[0], criteriaMessageHash, signature); + + // check current ownership + IERC721 nft = IERC721(addresses[1]); + require( + nft.ownerOf(values[0]) == addresses[0], + "Marketplace: seller is not owner of this item now" + ); + + // Check payment approval and buyer balance + IERC20 paymentContract = IERC20(addresses[2]); + require( + paymentContract.balanceOf(_msgSender()) >= values[1], + "Marketplace: buyer doesn't have enough token to buy this item" + ); + require( + paymentContract.allowance(_msgSender(), address(this)) >= values[1], + "Marketplace: buyer doesn't approve marketplace to spend payment amount" + ); + + // We divide by 10000 to support decimal value such as 4.25% => 425 / 10000 + uint256 fee = transactionFee.mul(values[1]).div(10000); + uint256 payToSellerAmount = values[1].sub(fee); + + // transfer money to seller + paymentContract.safeTransferFrom( + _msgSender(), + addresses[0], + payToSellerAmount + ); + + // transfer fee to address + if (fee > 0) { + paymentContract.safeTransferFrom(_msgSender(), feeToAddress, fee); } - function setFeeToAddress(address _feeToAddress) external onlyOwner { - require(_feeToAddress != address(0), 'fee received address can not be zero'); - feeToAddress = _feeToAddress; - } + // transfer item to buyer + nft.safeTransferFrom(addresses[0], _msgSender(), values[0]); - function setTransactionFee(uint256 _transactionFee) external onlyOwner { - require( - _transactionFee >= MIN_TRANSACTION_FEE && _transactionFee <= MAX_TRANSACTION_FEE, - "Marketplace: _transactionFee must >= 50 and <= 1000" - ); - transactionFee = _transactionFee; - } + useSignature(signature); + // emit sale event + emitEvent(addresses, values); + return true; + } - function setPaymentTokens(address[] calldata _paymentTokens) - external - onlyOwner - { - for (uint256 i = 0; i < _paymentTokens.length; i++) { - if (paymentTokens[_paymentTokens[i]]) { - continue; - } + /** + * @dev Function to emit transaction matched event + */ + function emitEvent(address[3] calldata addresses, uint256[3] calldata values) + internal + { + emit MatchTransaction( + values[0], + addresses[1], + values[1], + addresses[2], + addresses[0], + _msgSender(), + transactionFee + ); + } - paymentTokens[_paymentTokens[i]] = true; - } - } - - function removePaymentTokens(address[] calldata _removedPaymentTokens) - external - onlyOwner - { - for (uint256 i = 0; i < _removedPaymentTokens.length; i++) { - paymentTokens[_removedPaymentTokens[i]] = false; - } - } - - function ignoreSignature( - address[2] calldata addresses, - uint256[3] calldata values, - bytes calldata signature - ) external signatureValid(signature){ - bytes32 criteriaMessageHash = getMessageHash( - addresses[0], - values[0], - addresses[1], - values[1], - values[2] - ); - - checkSigner(_msgSender(), criteriaMessageHash, signature); - useSignature(signature); - } - - /** - * @dev Function matched transaction with user signatures - */ - function matchTransaction( - address[3] calldata addresses, - uint256[3] calldata values, - bytes calldata signature - ) external signatureValid(signature) returns (bool) { - // address[3] [seller_address,nft_address,payment_token_address] - // uint256[3] [token_id,price,salt_nonce] - // bytes seller_signature - require( - paymentTokens[addresses[2]], - "Marketplace: invalid payment method" - ); - - bytes32 criteriaMessageHash = getMessageHash( - addresses[1], - values[0], - addresses[2], - values[1], - values[2] - ); - - checkSigner712(addresses[0], criteriaMessageHash, signature); - - // check current ownership - IERC721 nft = IERC721(addresses[1]); - require( - nft.ownerOf(values[0]) == addresses[0], - "Marketplace: seller is not owner of this item now" - ); - - // Check payment approval and buyer balance - IERC20 paymentContract = IERC20(addresses[2]); - require( - paymentContract.balanceOf(_msgSender()) >= values[1], - "Marketplace: buyer doesn't have enough token to buy this item" - ); - require( - paymentContract.allowance(_msgSender(), address(this)) >= values[1], - "Marketplace: buyer doesn't approve marketplace to spend payment amount" - ); - - // We divide by 10000 to support decimal value such as 4.25% => 425 / 10000 - uint256 fee = transactionFee.mul(values[1]).div(10000); - uint256 payToSellerAmount = values[1].sub(fee); - - // transfer money to seller - paymentContract.safeTransferFrom( - _msgSender(), - addresses[0], - payToSellerAmount - ); - - // transfer fee to address - if (fee > 0) { - paymentContract.safeTransferFrom(_msgSender(), feeToAddress, fee); - } - - // transfer item to buyer - nft.safeTransferFrom(addresses[0], _msgSender(), values[0]); - - useSignature(signature); - // emit sale event - emitEvent(addresses, values); - return true; - } - - /** - * @dev Function to emit transaction matched event - */ - function emitEvent( - address[3] calldata addresses, - uint256[3] calldata values - ) internal { - emit MatchTransaction( - values[0], - addresses[1], - values[1], - addresses[2], - addresses[0], - _msgSender(), - transactionFee - ); - } - - function getMessageHash( - address _nftAddress, - uint256 _tokenId, - address _paymentErc20, - uint256 _price, - uint256 _saltNonce - ) public pure returns (bytes32) { - return - keccak256( - abi.encode( - keccak256("set(address nft,uint256 tokenId,address payToken,uint256 price,uint256 salt)"), - _nftAddress, - _tokenId, - _paymentErc20, - _price, - _saltNonce - ) - ); - } + function getMessageHash( + address _nftAddress, + uint256 _tokenId, + address _paymentErc20, + uint256 _price, + uint256 _saltNonce + ) public pure returns (bytes32) { + return + keccak256( + abi.encode( + keccak256( + "set(address nft,uint256 tokenId,address payToken,uint256 price,uint256 salt)" + ), + _nftAddress, + _tokenId, + _paymentErc20, + _price, + _saltNonce + ) + ); + } } diff --git a/contracts/tokens/erc1155/BEBase1155.sol b/contracts/tokens/erc1155/BEBase1155.sol index 5704090..1e2eeb3 100644 --- a/contracts/tokens/erc1155/BEBase1155.sol +++ b/contracts/tokens/erc1155/BEBase1155.sol @@ -7,301 +7,285 @@ import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; abstract contract BEBase1155 is ERC1155, Ownable, AccessControl { - using Strings for uint256; + using Strings for uint256; - bytes32 public constant URI_SETTER_ROLE = keccak256("URI_SETTER_ROLE"); - bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); - bytes32 public constant BURN_ROLE = keccak256("BURN_ROLE"); - bytes32 public constant LOCK_ROLE = keccak256("LOCK_ROLE"); + bytes32 public constant URI_SETTER_ROLE = keccak256("URI_SETTER_ROLE"); + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant BURN_ROLE = keccak256("BURN_ROLE"); + bytes32 public constant LOCK_ROLE = keccak256("LOCK_ROLE"); - mapping(uint256 => bool) public lockedTokens; + mapping(uint256 => bool) public lockedTokens; - mapping(address => uint256[]) private _ownedTokens; - // for 0 means not exists, value stored = index + 1; - mapping(address => mapping(uint256 => uint256)) private _ownedTokensIndex; + mapping(address => uint256[]) private _ownedTokens; + // for 0 means not exists, value stored = index + 1; + mapping(address => mapping(uint256 => uint256)) private _ownedTokensIndex; - mapping(uint256 => uint256) private _totalSupply; + mapping(uint256 => uint256) private _totalSupply; - uint256 public maxSupply = 0; + uint256 public maxSupply = 0; - struct TokenStruct { - uint256 tokenId; - uint256 amount; + struct TokenStruct { + uint256 tokenId; + uint256 amount; + } + + constructor() ERC1155("https://market.cebg.games/api/nft/info/{id}") { + _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); + _grantRole(URI_SETTER_ROLE, msg.sender); + } + + function setURI(string memory newuri) external onlyRole(URI_SETTER_ROLE) { + _setURI(newuri); + } + + function mintBatch( + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) external onlyRole(MINTER_ROLE) { + _mintBatch(to, ids, amounts, data); + } + + function burnBatch( + address account, + uint256[] memory ids, + uint256[] memory values + ) external onlyRole(BURN_ROLE) { + _burnBatch(account, ids, values); + } + + // The following functions are overrides required by Solidity. + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC1155, AccessControl) + returns (bool) + { + return super.supportsInterface(interfaceId); + } + + /** + * @dev Add factory to mint/burn item + */ + function setMintFactory(address factory) external onlyOwner { + _grantRole(MINTER_ROLE, factory); + } + + /** + * @dev Remove factory + */ + function removeMintFactory(address factory) external onlyOwner { + _revokeRole(MINTER_ROLE, factory); + } + + function grantLockRole(address account) external onlyOwner { + _grantRole(LOCK_ROLE, account); + } + + function revokeLockRole(address account) external onlyOwner { + _revokeRole(LOCK_ROLE, account); + } + + /** + * @dev Add factory to burn item + */ + function grantBurnRole(address proxy) external onlyOwner { + _grantRole(BURN_ROLE, proxy); + } + + /** + * @dev Remove proxy + */ + function revokeBurnRole(address proxy) external onlyOwner { + _revokeRole(BURN_ROLE, proxy); + } + + /** + * @dev Total amount of tokens in with a given id. + */ + function totalSupply(uint256 id) external view virtual returns (uint256) { + return _totalSupply[id]; + } + + /** + * @dev Indicates whether any token exist with a given id, or not. + */ + function exists(uint256 id) public view virtual returns (bool) { + return _totalSupply[id] > 0; + } + + function canMint( + uint256 /*id*/ + ) external view virtual returns (bool) { + return true; + } + + /** + * @dev Lock token to use in game or for rental + */ + function lock(uint256 id) external onlyRole(LOCK_ROLE) { + require(_totalSupply[id] > 0, "Must be valid tokenId"); + require(!lockedTokens[id], "Token has already locked"); + lockedTokens[id] = true; + } + + function lockBatch(uint256[] memory ids) external onlyRole(LOCK_ROLE) { + uint256 len = ids.length; + for (uint256 i = 0; i < len; ++i) { + uint256 id = ids[i]; + require(_totalSupply[id] > 0, "Must be valid tokenId"); + require(!lockedTokens[id], "Token has already locked"); + lockedTokens[id] = true; } + } - constructor() ERC1155("https://market.cebg.games/api/nft/info/{id}") { - _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); - _grantRole(URI_SETTER_ROLE, msg.sender); + /** + * @dev Unlock token to use blockchain or sale on marketplace + */ + function unlock(uint256 id) external onlyRole(LOCK_ROLE) { + require(_totalSupply[id] > 0, "Must be valid tokenId"); + require(lockedTokens[id], "Token has already unlocked"); + lockedTokens[id] = false; + } + + function unlockBatch(uint256[] memory ids) external onlyRole(LOCK_ROLE) { + uint256 len = ids.length; + for (uint256 i = 0; i < len; ++i) { + uint256 id = ids[i]; + require(_totalSupply[id] > 0, "Must be valid tokenId"); + require(lockedTokens[id], "Token has already unlocked"); + lockedTokens[id] = false; } + } - function setURI(string memory newuri) external onlyRole(URI_SETTER_ROLE) { - _setURI(newuri); + /** + * @dev Get lock status + */ + function isLocked(uint256 id) external view returns (bool) { + return lockedTokens[id]; + } + + function isLockedBatch(uint256[] memory ids) + external + view + returns (bool[] memory) + { + uint256 len = ids.length; + bool[] memory results = new bool[](len); + for (uint256 i = 0; i < len; ++i) { + results[i] = lockedTokens[ids[i]]; } + return results; + } - function mintBatch( - address to, - uint256[] memory ids, - uint256[] memory amounts, - bytes memory data - ) external onlyRole(MINTER_ROLE) { - _mintBatch(to, ids, amounts, data); + /** + * @dev See {ERC1155-_beforeTokenTransfer}. + */ + function _beforeTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual override { + super._beforeTokenTransfer(operator, from, to, ids, amounts, data); + uint256 len = ids.length; + for (uint256 i = 0; i < len; ++i) { + require(!lockedTokens[ids[i]], "Can not transfer locked token"); } - - - function burnBatch( - address account, - uint256[] memory ids, - uint256[] memory values - ) external onlyRole(BURN_ROLE) { - _burnBatch(account, ids, values); - } - - // The following functions are overrides required by Solidity. - - function supportsInterface(bytes4 interfaceId) - public - view - override(ERC1155, AccessControl) - returns (bool) - { - return super.supportsInterface(interfaceId); - } - - /** - * @dev Add factory to mint/burn item - */ - function setMintFactory(address factory) - external - onlyOwner - { - _grantRole(MINTER_ROLE, factory); - } - - /** - * @dev Remove factory - */ - function removeMintFactory(address factory) - external - onlyOwner - { - _revokeRole(MINTER_ROLE, factory); - } - - function grantLockRole(address account) - external - onlyOwner - { - _grantRole(LOCK_ROLE, account); - } - - function revokeLockRole(address account) - external - onlyOwner - { - _revokeRole(LOCK_ROLE, account); - } - - /** - * @dev Add factory to burn item - */ - function grantBurnRole(address proxy) external onlyOwner { - _grantRole(BURN_ROLE, proxy); - } - - /** - * @dev Remove proxy - */ - function revokeBurnRole(address proxy) external onlyOwner { - _revokeRole(BURN_ROLE, proxy); - } - - - /** - * @dev Total amount of tokens in with a given id. - */ - function totalSupply(uint256 id) external view virtual returns (uint256) { - return _totalSupply[id]; - } - - /** - * @dev Indicates whether any token exist with a given id, or not. - */ - function exists(uint256 id) public view virtual returns (bool) { - return _totalSupply[id] > 0; - } - - function canMint(uint256 /*id*/) external view virtual returns (bool) { - return true; - } - - - - - /** - * @dev Lock token to use in game or for rental - */ - function lock(uint256 id) external onlyRole(LOCK_ROLE) { - require(_totalSupply[id] > 0, "Must be valid tokenId"); - require(!lockedTokens[id], "Token has already locked"); - lockedTokens[id] = true; - } - - function lockBatch(uint256[] memory ids) external onlyRole(LOCK_ROLE) { - uint256 len = ids.length; - for (uint256 i = 0; i < len; ++i) { - uint256 id = ids[i]; - require(_totalSupply[id] > 0, "Must be valid tokenId"); - require(!lockedTokens[id], "Token has already locked"); - lockedTokens[id] = true; + if (from == address(0)) { + // mint nft + for (uint256 i = 0; i < len; ++i) { + _totalSupply[ids[i]] += amounts[i]; + if (maxSupply > 0) { + require( + _totalSupply[ids[i]] <= maxSupply, + "Can not mint for exceeds max supply" + ); } + } + } else if (from != to) { + // transfer from -> to + for (uint256 i = 0; i < len; ++i) { + _removeTokenFromOwnerEnumeration(from, ids[i], amounts[i]); + } } - /** - * @dev Unlock token to use blockchain or sale on marketplace - */ - function unlock(uint256 id) external onlyRole(LOCK_ROLE) { - require(_totalSupply[id] > 0, "Must be valid tokenId"); - require(lockedTokens[id], "Token has already unlocked"); - lockedTokens[id] = false; + if (to == address(0)) { + // burn nft + for (uint256 i = 0; i < len; ++i) { + _totalSupply[ids[i]] -= amounts[i]; + } + } else if (to != from) { + // mint or transfer from -> to + for (uint256 i = 0; i < len; ++i) { + _addTokenToOwnerEnumeration(to, ids[i]); + } } + } - function unlockBatch(uint256[] memory ids) external onlyRole(LOCK_ROLE) { - uint256 len = ids.length; - for (uint256 i = 0; i < len; ++i) { - uint256 id = ids[i]; - require(_totalSupply[id] > 0, "Must be valid tokenId"); - require(lockedTokens[id], "Token has already unlocked"); - lockedTokens[id] = false; - } + function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { + if (_ownedTokensIndex[to][tokenId] == 0 && balanceOf(to, tokenId) == 0) { + _ownedTokensIndex[to][tokenId] = _ownedTokens[to].length + 1; + _ownedTokens[to].push(tokenId); } + } - /** - * @dev Get lock status - */ - function isLocked(uint256 id) external view returns (bool) { - return lockedTokens[id]; + function _removeTokenFromOwnerEnumeration( + address from, + uint256 tokenId, + uint256 amount + ) private { + uint256 balance = balanceOf(from, tokenId); + if (balance == amount) { + uint256 lastTokenIndex = _ownedTokens[from].length - 1; + uint256 tokenIndex = _ownedTokensIndex[from][tokenId] - 1; + + uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; + // Move the last token to the slot of the to-delete token + _ownedTokens[from][tokenIndex] = lastTokenId; + // Update the moved token's index + _ownedTokensIndex[from][lastTokenId] = tokenIndex + 1; + + // This also deletes the contents at the last position of the array + delete _ownedTokensIndex[from][tokenId]; + _ownedTokens[from].pop(); } + } - function isLockedBatch(uint256[] memory ids) - external - view - returns (bool[] memory) - { - uint256 len = ids.length; - bool[] memory results = new bool[](len); - for (uint256 i = 0; i < len; ++i) { - results[i] = lockedTokens[ids[i]]; - } - return results; + function userTokens( + address user, + uint256 start, + uint256 page + ) external view returns (TokenStruct[] memory) { + uint256 size = _ownedTokens[user].length; + uint256 max = size; + uint256 pageSize = 0; + if (start < size) { + if (start + page < size) { + pageSize = page; + max = start + page; + } else { + pageSize = size - start; + } } - - /** - * @dev See {ERC1155-_beforeTokenTransfer}. - */ - function _beforeTokenTransfer( - address operator, - address from, - address to, - uint256[] memory ids, - uint256[] memory amounts, - bytes memory data - ) internal virtual override { - super._beforeTokenTransfer(operator, from, to, ids, amounts, data); - uint256 len = ids.length; - for (uint256 i = 0; i < len; ++i) { - require(!lockedTokens[ids[i]], "Can not transfer locked token"); - } - if (from == address(0)) { - // mint nft - for (uint256 i = 0; i < len; ++i) { - _totalSupply[ids[i]] += amounts[i]; - if (maxSupply > 0) { - require( - _totalSupply[ids[i]] <= maxSupply, - "Can not mint for exceeds max supply" - ); - } - } - } else if (from != to) { - // transfer from -> to - for (uint256 i = 0; i < len; ++i) { - _removeTokenFromOwnerEnumeration(from, ids[i], amounts[i]); - } - } - - if (to == address(0)) { - // burn nft - for (uint256 i = 0; i < len; ++i) { - _totalSupply[ids[i]] -= amounts[i]; - } - } else if (to != from) { - // mint or transfer from -> to - for (uint256 i = 0; i < len; ++i) { - _addTokenToOwnerEnumeration(to, ids[i]); - } - } - } - function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { - if ( - _ownedTokensIndex[to][tokenId] == 0 && balanceOf(to, tokenId) == 0 - ) { - _ownedTokensIndex[to][tokenId] = _ownedTokens[to].length + 1; - _ownedTokens[to].push(tokenId); - } + TokenStruct[] memory results = new TokenStruct[](pageSize); + if (pageSize > 0) { + for (uint256 i = start; i < max; ++i) { + TokenStruct memory dataObj; + uint256 tokenId = _ownedTokens[user][i]; + dataObj.tokenId = tokenId; + dataObj.amount = balanceOf(user, tokenId); + results[i - start] = dataObj; + } } + return results; + } - function _removeTokenFromOwnerEnumeration( - address from, - uint256 tokenId, - uint256 amount - ) private { - uint256 balance = balanceOf(from, tokenId); - if (balance == amount) { - uint256 lastTokenIndex = _ownedTokens[from].length - 1; - uint256 tokenIndex = _ownedTokensIndex[from][tokenId] - 1; - - uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; - // Move the last token to the slot of the to-delete token - _ownedTokens[from][tokenIndex] = lastTokenId; - // Update the moved token's index - _ownedTokensIndex[from][lastTokenId] = tokenIndex + 1; - - // This also deletes the contents at the last position of the array - delete _ownedTokensIndex[from][tokenId]; - _ownedTokens[from].pop(); - } - } - - function userTokens( - address user, - uint256 start, - uint256 page - ) external view returns (TokenStruct[] memory) { - uint256 size = _ownedTokens[user].length; - uint256 max = size; - uint256 pageSize = 0; - if (start < size) { - if (start + page < size) { - pageSize = page; - max = start + page; - } else { - pageSize = size - start; - } - } - TokenStruct[] memory results = new TokenStruct[](pageSize); - if (pageSize > 0) { - for (uint256 i = start; i < max; ++i) { - TokenStruct memory dataObj; - uint256 tokenId = _ownedTokens[user][i]; - dataObj.tokenId = tokenId; - dataObj.amount = balanceOf(user, tokenId); - results[i - start] = dataObj; - } - } - return results; - } - - function tokenTypes(address user) external view returns (uint256) { - return _ownedTokens[user].length; - } + function tokenTypes(address user) external view returns (uint256) { + return _ownedTokens[user].length; + } } diff --git a/contracts/tokens/erc1155/BEChip1155.sol b/contracts/tokens/erc1155/BEChip1155.sol index 0cb9ca0..0f0e595 100644 --- a/contracts/tokens/erc1155/BEChip1155.sol +++ b/contracts/tokens/erc1155/BEChip1155.sol @@ -4,13 +4,13 @@ pragma solidity 0.8.10; import "./BEBase1155.sol"; contract BEChip1155 is BEBase1155 { - mapping(uint256 => uint256) public tokenLevels; + mapping(uint256 => uint256) public tokenLevels; - constructor() { - maxSupply = 1; - } + constructor() { + maxSupply = 1; + } - function canMint(uint256 id) external view override returns (bool) { - return !exists(id); - } + function canMint(uint256 id) external view override returns (bool) { + return !exists(id); + } } diff --git a/contracts/tokens/erc1155/BEShard.sol b/contracts/tokens/erc1155/BEShard.sol index d887387..bd7e2db 100644 --- a/contracts/tokens/erc1155/BEShard.sol +++ b/contracts/tokens/erc1155/BEShard.sol @@ -2,9 +2,10 @@ pragma solidity 0.8.10; import "./BEBase1155.sol"; + /** * for Hero and Weapon shard */ contract BEShard is BEBase1155 { - + } diff --git a/contracts/tokens/erc20/BECoin.sol b/contracts/tokens/erc20/BECoin.sol index e327323..d42c92b 100644 --- a/contracts/tokens/erc20/BECoin.sol +++ b/contracts/tokens/erc20/BECoin.sol @@ -2,11 +2,10 @@ pragma solidity 0.8.10; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; - contract BECoin is ERC20Burnable { - uint256 public constant INITIALIZED_CAP = 100000000 * 1e18; + uint256 public constant INITIALIZED_CAP = 100000000 * 1e18; - constructor() ERC20("CRYPTO ELITE'S COIN", "CEC") { - _mint(_msgSender(), INITIALIZED_CAP); - } -} \ No newline at end of file + constructor() ERC20("CRYPTO ELITE'S COIN", "CEC") { + _mint(_msgSender(), INITIALIZED_CAP); + } +} diff --git a/contracts/tokens/erc20/BEGold.sol b/contracts/tokens/erc20/BEGold.sol index fcada3e..a815f58 100644 --- a/contracts/tokens/erc20/BEGold.sol +++ b/contracts/tokens/erc20/BEGold.sol @@ -4,33 +4,31 @@ import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; import "@openzeppelin/contracts/security/Pausable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; + /** * this contract will transfer ownership to BETimelockController after deployed * all onlyowner method would add timelock */ contract BEGold is ERC20, ERC20Burnable, Pausable, Ownable { + constructor() ERC20("CRYPTO ELITE'S GOLD", "CEG") {} + function pause() external onlyOwner { + _pause(); + } - constructor() ERC20("CRYPTO ELITE'S GOLD", "CEG") { - } + function unpause() external onlyOwner { + _unpause(); + } - function pause() external onlyOwner { - _pause(); - } + function mint(address to, uint256 amount) external onlyOwner { + _mint(to, amount); + } - function unpause() external onlyOwner { - _unpause(); - } - - function mint(address to, uint256 amount) external onlyOwner { - _mint(to, amount); - } - - function _beforeTokenTransfer(address from, address to, uint256 amount) - internal - whenNotPaused - override - { - super._beforeTokenTransfer(from, to, amount); - } -} \ No newline at end of file + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal override whenNotPaused { + super._beforeTokenTransfer(from, to, amount); + } +} diff --git a/contracts/tokens/erc721/BEBase.sol b/contracts/tokens/erc721/BEBase.sol index e83ce7a..7c7e224 100644 --- a/contracts/tokens/erc721/BEBase.sol +++ b/contracts/tokens/erc721/BEBase.sol @@ -7,164 +7,157 @@ import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; abstract contract BEBase is ERC721, AccessControl, ERC721Enumerable, Ownable { - using Strings for uint256; + using Strings for uint256; - mapping(uint256 => bool) public lockedTokens; - string private _baseTokenURI = "https://market.cebg.games/api/nft/info/"; - bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); - bytes32 public constant BURN_ROLE = keccak256("BURN_ROLE"); - bytes32 public constant LOCK_ROLE = keccak256("LOCK_ROLE"); + mapping(uint256 => bool) public lockedTokens; + string private _baseTokenURI = "https://market.cebg.games/api/nft/info/"; + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant BURN_ROLE = keccak256("BURN_ROLE"); + bytes32 public constant LOCK_ROLE = keccak256("LOCK_ROLE"); - function _baseURI() internal view virtual override returns (string memory) { - return _baseTokenURI; - } + function _baseURI() internal view virtual override returns (string memory) { + return _baseTokenURI; + } - /** - * @dev Creates a new token for `to`. Its token ID will be automatically - * assigned (and available on the emitted {IERC721-Transfer} event), and the token - * URI autogenerated based on the base URI passed at construction. - * - * See {ERC721-_mint}. - * - * Requirements: - * - * - the caller must have the `MINTER_ROLE`. - */ - function mint(address to, uint256 tokenId) - external - onlyRole(MINTER_ROLE) - virtual { - require(!_exists(tokenId), "Must have unique tokenId"); - // We cannot just use balanceOf to create the new tokenId because tokens - // can be burned (destroyed), so we need a separate counter. - _mint(to, tokenId); - } + /** + * @dev Creates a new token for `to`. Its token ID will be automatically + * assigned (and available on the emitted {IERC721-Transfer} event), and the token + * URI autogenerated based on the base URI passed at construction. + * + * See {ERC721-_mint}. + * + * Requirements: + * + * - the caller must have the `MINTER_ROLE`. + */ + function mint(address to, uint256 tokenId) + external + virtual + onlyRole(MINTER_ROLE) + { + require(!_exists(tokenId), "Must have unique tokenId"); + // We cannot just use balanceOf to create the new tokenId because tokens + // can be burned (destroyed), so we need a separate counter. + _mint(to, tokenId); + } - /** - * @dev Add factory to mint item - */ - function setMintFactory(address factory) external onlyOwner { - _grantRole(MINTER_ROLE, factory); - } + /** + * @dev Add factory to mint item + */ + function setMintFactory(address factory) external onlyOwner { + _grantRole(MINTER_ROLE, factory); + } - /** - * @dev Remove factory - */ - function removeMintFactory(address factory) external onlyOwner { - _revokeRole(MINTER_ROLE, factory); - } + /** + * @dev Remove factory + */ + function removeMintFactory(address factory) external onlyOwner { + _revokeRole(MINTER_ROLE, factory); + } - /** - * @dev Add factory to burn item - */ - function grantBurnRole(address proxy) external onlyOwner { - _grantRole(BURN_ROLE, proxy); - } + /** + * @dev Add factory to burn item + */ + function grantBurnRole(address proxy) external onlyOwner { + _grantRole(BURN_ROLE, proxy); + } - /** - * @dev Remove proxy - */ - function revokeBurnProxy(address proxy) external onlyOwner { - _revokeRole(BURN_ROLE, proxy); - } - /** - * @dev Add address to lock item - */ - function grantLockRole(address account) - external - onlyOwner - { - _grantRole(LOCK_ROLE, account); - } - /** - * @dev Remove address for lock item - */ - function revokeLockRole(address account) - external - onlyOwner - { - _revokeRole(LOCK_ROLE, account); - } + /** + * @dev Remove proxy + */ + function revokeBurnProxy(address proxy) external onlyOwner { + _revokeRole(BURN_ROLE, proxy); + } + /** + * @dev Add address to lock item + */ + function grantLockRole(address account) external onlyOwner { + _grantRole(LOCK_ROLE, account); + } - /** - * @dev Lock token to use in game or for rental - */ - function lock(uint256 tokenId) external onlyRole(LOCK_ROLE) { - require(_exists(tokenId), "Must be valid tokenId"); - require(!lockedTokens[tokenId], "Token has already locked"); - lockedTokens[tokenId] = true; - } + /** + * @dev Remove address for lock item + */ + function revokeLockRole(address account) external onlyOwner { + _revokeRole(LOCK_ROLE, account); + } - /** - * @dev Unlock token to use blockchain or sale on marketplace - */ - function unlock(uint256 tokenId) external onlyRole(LOCK_ROLE){ - require(_exists(tokenId), "Must be valid tokenId"); - require(lockedTokens[tokenId], "Token has already unlocked"); - lockedTokens[tokenId] = false; - } + /** + * @dev Lock token to use in game or for rental + */ + function lock(uint256 tokenId) external onlyRole(LOCK_ROLE) { + require(_exists(tokenId), "Must be valid tokenId"); + require(!lockedTokens[tokenId], "Token has already locked"); + lockedTokens[tokenId] = true; + } - /** - * @dev Get lock status - */ - function isLocked(uint256 tokenId) external view returns (bool) { - return lockedTokens[tokenId]; - } + /** + * @dev Unlock token to use blockchain or sale on marketplace + */ + function unlock(uint256 tokenId) external onlyRole(LOCK_ROLE) { + require(_exists(tokenId), "Must be valid tokenId"); + require(lockedTokens[tokenId], "Token has already unlocked"); + lockedTokens[tokenId] = false; + } - /** - * @dev Set token URI - */ - function updateBaseURI(string calldata baseTokenURI) external onlyOwner { - _baseTokenURI = baseTokenURI; - } + /** + * @dev Get lock status + */ + function isLocked(uint256 tokenId) external view returns (bool) { + return lockedTokens[tokenId]; + } - /** - * @dev See {IERC165-_beforeTokenTransfer}. - */ - function _beforeTokenTransfer( - address from, - address to, - uint256 tokenId - ) internal virtual override(ERC721, ERC721Enumerable) { - require(!lockedTokens[tokenId], "Can not transfer locked token"); - super._beforeTokenTransfer(from, to, tokenId); - } + /** + * @dev Set token URI + */ + function updateBaseURI(string calldata baseTokenURI) external onlyOwner { + _baseTokenURI = baseTokenURI; + } - /** - * @dev See {IERC165-supportsInterface}. - */ - function supportsInterface(bytes4 interfaceId) - public - view - virtual - override(AccessControl, ERC721, ERC721Enumerable) - returns (bool) - { - return super.supportsInterface(interfaceId); - } + /** + * @dev See {IERC165-_beforeTokenTransfer}. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 tokenId + ) internal virtual override(ERC721, ERC721Enumerable) { + require(!lockedTokens[tokenId], "Can not transfer locked token"); + super._beforeTokenTransfer(from, to, tokenId); + } - - /** - * @dev Burns `tokenId`. - * - * Requirements: - * - * - The caller must own `tokenId` or be an approved operator. - */ - function burn(address owner, uint256 tokenId) - external - onlyRole(BURN_ROLE) - virtual - { - require(_exists(tokenId), "TokenId not exists"); - require(!lockedTokens[tokenId], "Can not burn locked token"); - require( - ownerOf(tokenId) == owner, - "current address is not owner of this item now" - ); - _burn(tokenId); - } + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(AccessControl, ERC721, ERC721Enumerable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } - + /** + * @dev Burns `tokenId`. + * + * Requirements: + * + * - The caller must own `tokenId` or be an approved operator. + */ + function burn(address owner, uint256 tokenId) + external + virtual + onlyRole(BURN_ROLE) + { + require(_exists(tokenId), "TokenId not exists"); + require(!lockedTokens[tokenId], "Can not burn locked token"); + require( + ownerOf(tokenId) == owner, + "current address is not owner of this item now" + ); + _burn(tokenId); + } } diff --git a/contracts/tokens/erc721/BEChip.sol b/contracts/tokens/erc721/BEChip.sol index 5b19c33..7d8daf0 100644 --- a/contracts/tokens/erc721/BEChip.sol +++ b/contracts/tokens/erc721/BEChip.sol @@ -4,6 +4,6 @@ import "./BEBase.sol"; // this contract will transfer ownership to BETimelockController after deployed // all onlyowner method would add timelock -contract BEChip is BEBase{ - constructor() ERC721("CRYPTO ELITE'S CHIP", "CHIP") {} +contract BEChip is BEBase { + constructor() ERC721("CRYPTO ELITE'S CHIP", "CHIP") {} } diff --git a/contracts/tokens/erc721/BEEquipment.sol b/contracts/tokens/erc721/BEEquipment.sol index 3598e08..e7d0134 100644 --- a/contracts/tokens/erc721/BEEquipment.sol +++ b/contracts/tokens/erc721/BEEquipment.sol @@ -4,6 +4,6 @@ import "./BEBase.sol"; // this contract will transfer ownership to BETimelockController after deployed // all onlyowner method would add timelock -contract BEEquipment is BEBase{ - constructor() ERC721("CRYPTO ELITE'S WEAPON", "WEAPON") {} +contract BEEquipment is BEBase { + constructor() ERC721("CRYPTO ELITE'S WEAPON", "WEAPON") {} } diff --git a/contracts/tokens/erc721/BEHero.sol b/contracts/tokens/erc721/BEHero.sol index 7c2b572..aab51a1 100644 --- a/contracts/tokens/erc721/BEHero.sol +++ b/contracts/tokens/erc721/BEHero.sol @@ -4,6 +4,6 @@ import "./BEBase.sol"; // this contract will transfer ownership to BETimelockController after deployed // all onlyowner method would add timelock -contract BEHero is BEBase{ - constructor() ERC721("CRYPTO ELITE'S HERO", "HERO") {} -} \ No newline at end of file +contract BEHero is BEBase { + constructor() ERC721("CRYPTO ELITE'S HERO", "HERO") {} +} diff --git a/contracts/tokens/erc721/BEMysteryBox.sol b/contracts/tokens/erc721/BEMysteryBox.sol index 61e495a..a875dc3 100644 --- a/contracts/tokens/erc721/BEMysteryBox.sol +++ b/contracts/tokens/erc721/BEMysteryBox.sol @@ -4,23 +4,26 @@ import "./BEBase.sol"; // this contract will transfer ownership to BETimelockController after deployed // all onlyowner method would add timelock -contract BEMysteryBox is BEBase{ - constructor() ERC721("CRYPTO ELITE'S MYSTERY BOXES", "BOX") {} - - function userTokens(address user, uint256 start, uint256 page) - external view returns (uint256 [] memory){ - uint256 size = balanceOf(user); - uint256[] memory results = new uint256[](page); - if (start < size) { - uint256 max = size; - if (start + page < size) { - max = start + page; - } - for (uint256 i = start; i < max; ++i) { - uint256 tokenId = tokenOfOwnerByIndex(user, i); - results[i-start] = tokenId; - } - } - return results; +contract BEMysteryBox is BEBase { + constructor() ERC721("CRYPTO ELITE'S MYSTERY BOXES", "BOX") {} + + function userTokens( + address user, + uint256 start, + uint256 page + ) external view returns (uint256[] memory) { + uint256 size = balanceOf(user); + uint256[] memory results = new uint256[](page); + if (start < size) { + uint256 max = size; + if (start + page < size) { + max = start + page; + } + for (uint256 i = start; i < max; ++i) { + uint256 tokenId = tokenOfOwnerByIndex(user, i); + results[i - start] = tokenId; + } } + return results; + } } diff --git a/contracts/utils/TimeChecker.sol b/contracts/utils/TimeChecker.sol index e849406..9c7d034 100644 --- a/contracts/utils/TimeChecker.sol +++ b/contracts/utils/TimeChecker.sol @@ -5,13 +5,14 @@ import "@openzeppelin/contracts/access/Ownable.sol"; contract TimeChecker is Ownable { mapping(address => bool) private approvalLists; uint256 private _duration; - + constructor() { _duration = 1 days; } + modifier timeValid(uint256 time) { require( - time + _duration >= block.timestamp, + time + _duration >= block.timestamp, "expired, please send another transaction with new signature" ); _; @@ -20,10 +21,9 @@ contract TimeChecker is Ownable { /** * @dev Returns the max duration for function called by user */ - function getDuration() external view - returns (uint256 duration) { - return _duration; - } + function getDuration() external view returns (uint256 duration) { + return _duration; + } /** * @dev Change duration value @@ -31,6 +31,4 @@ contract TimeChecker is Ownable { function updateDuation(uint256 valNew) external onlyOwner { _duration = valNew; } - } - diff --git a/contracts/utils/UInt.sol b/contracts/utils/UInt.sol index 44f6ec9..e54b62a 100644 --- a/contracts/utils/UInt.sol +++ b/contracts/utils/UInt.sol @@ -1,9 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.10; -library UInt{ - - function asSingletonArray(uint256 element) internal pure returns (uint256[] memory) { +library UInt { + function asSingletonArray(uint256 element) + internal + pure + returns (uint256[] memory) + { uint256[] memory array = new uint256[](1); array[0] = element; return array; diff --git a/package-lock.json b/package-lock.json index bf47bb7..e09456a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1426,6 +1426,15 @@ "integrity": "sha1-n7OjzzEyMoFR81PeRjLgHlIQK+o=", "dev": true }, + "@solidity-parser/parser": { + "version": "0.14.3", + "resolved": "https://registry.npmmirror.com/@solidity-parser/parser/-/parser-0.14.3.tgz", + "integrity": "sha512-29g2SZ29HtsqA58pLCtopI1P/cPy5/UAzlcAXO6T/CNJimG6yA8kx4NaseMyJULiC+TEs02Y9/yeHzClqoA0hw==", + "dev": true, + "requires": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, "@szmarczak/http-timer": { "version": "1.1.2", "resolved": "https://registry.npmmirror.com/@szmarczak/http-timer/download/@szmarczak/http-timer-1.1.2.tgz", @@ -3061,6 +3070,12 @@ "color-convert": "^1.9.0" } }, + "antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmmirror.com/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", + "dev": true + }, "any-signal": { "version": "2.1.2", "resolved": "https://registry.npmmirror.com/any-signal/download/any-signal-2.1.2.tgz", @@ -15296,6 +15311,89 @@ "dev": true, "optional": true }, + "prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmmirror.com/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "dev": true + }, + "prettier-plugin-solidity": { + "version": "1.0.0-beta.24", + "resolved": "https://registry.npmmirror.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.24.tgz", + "integrity": "sha512-6JlV5BBTWzmDSq4kZ9PTXc3eLOX7DF5HpbqmmaF+kloyUwOZbJ12hIYsUaZh2fVgZdV2t0vWcvY6qhILhlzgqg==", + "dev": true, + "requires": { + "@solidity-parser/parser": "^0.14.3", + "emoji-regex": "^10.1.0", + "escape-string-regexp": "^4.0.0", + "semver": "^7.3.7", + "solidity-comments-extractor": "^0.0.7", + "string-width": "^4.2.3" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "emoji-regex": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-10.1.0.tgz", + "integrity": "sha512-xAEnNCT3w2Tg6MA7ly6QqYJvEoY1tm9iIjJ3yMKK9JPlWuRHAMoe5iETwQnx3M9TVbFMfsrBgWKR+IsmswwNjg==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + } + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, "printj": { "version": "1.1.2", "resolved": "https://registry.npmmirror.com/printj/download/printj-1.1.2.tgz", @@ -16708,6 +16806,12 @@ } } }, + "solidity-comments-extractor": { + "version": "0.0.7", + "resolved": "https://registry.npmmirror.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz", + "integrity": "sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==", + "dev": true + }, "source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmmirror.com/source-list-map/download/source-list-map-2.0.1.tgz", diff --git a/package.json b/package.json index 56bc843..9cf4026 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,8 @@ "scripts": { "test": "npx truffle test", "build": "truffle compile", + "prettier": "prettier --write 'contracts/**/*.sol'", + "lint": "prettier --list-different 'contracts/**/*.sol'", "deploy:dev": "truffle migrate --network development", "deploy:20": "truffle migrate --network lan20 --compile-none", "deploy:22": "truffle migrate --network lan22 --compile-none", @@ -20,6 +22,8 @@ "@openzeppelin/test-helpers": "^0.5.15", "@truffle/hdwallet-provider": "^2.0.0", "chai": "^4.3.4", + "prettier": "^2.7.1", + "prettier-plugin-solidity": "^1.0.0-beta.24", "truffle": "^5.4.23", "truffle-plugin-stdjsonin": "git+https://github.com/mhrsalehi/truffle-plugin-stdjsonin.git", "truffle-plugin-verify": "^0.5.25"