Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wighawag/dfc123ffb7838e5aeb88f58abff505f7 to your computer and use it in GitHub Desktop.
Save wighawag/dfc123ffb7838e5aeb88f58abff505f7 to your computer and use it in GitHub Desktop.
{
"language": "Solidity",
"sources": {
"src/contracts_common/src/BaseWithStorage/Admin.sol": {
"content": "pragma solidity ^0.6.0;\n\n\ncontract Admin {\n address internal _admin;\n\n /// @dev emitted when the contract administrator is changed.\n /// @param oldAdmin address of the previous administrator.\n /// @param newAdmin address of the new administrator.\n event AdminChanged(address oldAdmin, address newAdmin);\n\n /// @dev gives the current administrator of this contract.\n /// @return the current administrator of this contract.\n function getAdmin() external view returns (address) {\n return _admin;\n }\n\n /// @dev change the administrator to be `newAdmin`.\n /// @param newAdmin address of the new administrator.\n function changeAdmin(address newAdmin) external {\n require(msg.sender == _admin, \"only admin can change admin\");\n emit AdminChanged(_admin, newAdmin);\n _admin = newAdmin;\n }\n\n modifier onlyAdmin() {\n require(msg.sender == _admin, \"only admin allowed\");\n _;\n }\n}\n"
},
"src/Catalyst/CatalystValue.sol": {
"content": "pragma solidity 0.6.5;\npragma experimental ABIEncoderV2;\n\n\ninterface CatalystValue {\n struct GemEvent {\n uint256[] gemIds;\n bytes32 blockHash;\n }\n\n function getValues(\n uint256 catalystId,\n uint256 seed,\n GemEvent[] calldata events,\n uint32 totalNumberOfGemTypes\n ) external view returns (uint32[] memory values);\n}\n"
},
"src/Interfaces/AssetToken.sol": {
"content": "pragma solidity 0.6.5;\n\n\ninterface AssetToken {\n function mint(\n address creator,\n uint40 packId,\n bytes32 hash,\n uint256 supply,\n uint8 rarity,\n address owner,\n bytes calldata data\n ) external returns (uint256 id);\n\n function mintMultiple(\n address creator,\n uint40 packId,\n bytes32 hash,\n uint256[] calldata supplies,\n bytes calldata rarityPack,\n address owner,\n bytes calldata data\n ) external returns (uint256[] memory ids);\n\n // fails on non-NFT or nft who do not have collection (was a mistake)\n function collectionOf(uint256 id) external view returns (uint256);\n\n // return true for Non-NFT ERC1155 tokens which exists\n function isCollection(uint256 id) external view returns (bool);\n\n function collectionIndexOf(uint256 id) external view returns (uint256);\n\n function extractERC721From(\n address sender,\n uint256 id,\n address to\n ) external returns (uint256 newId);\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id\n ) external;\n}\n"
},
"src/CatalystRegistry.sol": {
"content": "pragma solidity 0.6.5;\npragma experimental ABIEncoderV2;\n\nimport \"./Interfaces/AssetToken.sol\";\nimport \"./contracts_common/src/BaseWithStorage/Admin.sol\";\nimport \"./Catalyst/CatalystValue.sol\";\n\n\ncontract CatalystRegistry is Admin, CatalystValue {\n event Minter(address indexed newMinter);\n event CatalystApplied(uint256 indexed assetId, uint256 indexed catalystId, uint256 seed, uint256[] gemIds, uint64 blockNumber);\n event GemsAdded(uint256 indexed assetId, uint256 seed, uint256[] gemIds, uint64 blockNumber);\n\n function getCatalyst(uint256 assetId) external view returns (bool exists, uint256 catalystId) {\n CatalystStored memory catalyst = _catalysts[assetId];\n if (catalyst.set != 0) {\n return (true, catalyst.catalystId);\n }\n if (assetId & IS_NFT != 0) {\n catalyst = _catalysts[_getCollectionId(assetId)];\n return (catalyst.set != 0, catalyst.catalystId);\n }\n return (false, 0);\n }\n\n function setCatalyst(\n uint256 assetId,\n uint256 catalystId,\n uint256 maxGems,\n uint256[] calldata gemIds\n ) external {\n require(msg.sender == _minter, \"NOT_AUTHORIZED_MINTER\");\n require(gemIds.length <= maxGems, \"INVALID_GEMS_TOO_MANY\");\n uint256 emptySockets = maxGems - gemIds.length;\n _catalysts[assetId] = CatalystStored(uint64(emptySockets), uint64(catalystId), 1);\n uint64 blockNumber = _getBlockNumber();\n emit CatalystApplied(assetId, catalystId, assetId, gemIds, blockNumber);\n }\n\n function addGems(uint256 assetId, uint256[] calldata gemIds) external {\n require(msg.sender == _minter, \"NOT_AUTHORIZED_MINTER\");\n require(assetId & IS_NFT != 0, \"INVALID_NOT_NFT\");\n require(gemIds.length != 0, \"INVALID_GEMS_0\");\n (uint256 emptySockets, uint256 seed) = _getSocketData(assetId);\n require(emptySockets >= gemIds.length, \"INVALID_GEMS_TOO_MANY\");\n emptySockets -= gemIds.length;\n _catalysts[assetId].emptySockets = uint64(emptySockets);\n uint64 blockNumber = _getBlockNumber();\n emit GemsAdded(assetId, seed, gemIds, blockNumber);\n }\n\n /// @dev Set the Minter that will be the only address able to create Estate\n /// @param minter address of the minter\n function setMinter(address minter) external {\n require(msg.sender == _admin, \"NOT_AUTHORIZED_ADMIN\");\n require(minter != _minter, \"INVALID_MINTER_SAME_ALREADY_SET\");\n _minter = minter;\n emit Minter(minter);\n }\n\n /// @dev return the current minter\n function getMinter() external view returns (address) {\n return _minter;\n }\n\n function getValues(\n uint256 catalystId,\n uint256 seed,\n GemEvent[] calldata events,\n uint32 totalNumberOfGemTypes\n ) external override view returns (uint32[] memory values) {\n return _catalystValue.getValues(catalystId, seed, events, totalNumberOfGemTypes);\n }\n\n // ///////// INTERNAL ////////////\n\n uint256 private constant IS_NFT = 0x0000000000000000000000000000000000000000800000000000000000000000;\n uint256 private constant NOT_IS_NFT = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFFFFFF;\n uint256 private constant NOT_NFT_INDEX = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF800000007FFFFFFFFFFFFFFF;\n\n function _getSocketData(uint256 assetId) internal view returns (uint256 emptySockets, uint256 seed) {\n seed = assetId;\n CatalystStored memory catalyst = _catalysts[assetId];\n if (catalyst.set != 0) {\n // the gems are added to an asset who already get a specific catalyst.\n // the seed is its id\n return (catalyst.emptySockets, seed);\n }\n // else the asset is only adding gems while keeping the same seed (that of the original assetId)\n seed = _getCollectionId(assetId);\n catalyst = _catalysts[seed];\n return (catalyst.emptySockets, seed);\n }\n\n function _getBlockNumber() internal view returns (uint64 blockNumber) {\n blockNumber = uint64(block.number + 1);\n }\n\n function _getCollectionId(uint256 assetId) internal pure returns (uint256) {\n return assetId & NOT_NFT_INDEX & NOT_IS_NFT; // compute the same as Asset to get collectionId\n }\n\n // CONSTRUCTOR ////\n constructor(CatalystValue catalystValue, address admin) public {\n _admin = admin;\n _catalystValue = catalystValue;\n }\n\n /// DATA ////////\n\n struct CatalystStored {\n uint64 emptySockets;\n uint64 catalystId;\n uint64 set;\n }\n address internal _minter;\n CatalystValue internal immutable _catalystValue;\n mapping(uint256 => CatalystStored) internal _catalysts;\n}\n"
}
},
"settings": {
"metadata": {
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 2000
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": ["id", "ast"]
}
}
}
}
{
"language": "Solidity",
"sources": {
"src/Base/TheSandbox712.sol": {
"content": "pragma solidity 0.6.5;\n\nimport {ProxyImplementation} from \"../contracts_common/src/BaseWithStorage/ProxyImplementation.sol\";\n\n\ncontract TheSandbox712 is ProxyImplementation {\n bytes32 constant EIP712DOMAIN_TYPEHASH = keccak256(\"EIP712Domain(string name,string version,address verifyingContract)\");\n bytes32 DOMAIN_SEPARATOR;\n\n function init712() public phase(\"712\") {\n DOMAIN_SEPARATOR = keccak256(abi.encode(EIP712DOMAIN_TYPEHASH, keccak256(\"The Sandbox 3D\"), keccak256(\"1\"), address(this)));\n }\n\n function domainSeparator() internal view returns (bytes32) {\n return DOMAIN_SEPARATOR;\n }\n}\n"
},
"src/contracts_common/src/BaseWithStorage/ProxyImplementation.sol": {
"content": "pragma solidity ^0.6.0;\n\n\ncontract ProxyImplementation {\n mapping(string => bool) _initialised;\n\n modifier phase(string memory phaseName) {\n if (!_initialised[phaseName]) {\n _initialised[phaseName] = true;\n _;\n }\n }\n}\n"
},
"src/BaseWithStorage/ERC20Group.sol": {
"content": "pragma solidity 0.6.5;\npragma experimental ABIEncoderV2;\n\nimport \"./ERC20SubToken.sol\";\nimport \"../contracts_common/src/Libraries/SafeMath.sol\";\nimport \"../contracts_common/src/Libraries/AddressUtils.sol\";\nimport \"../contracts_common/src/Libraries/ObjectLib32.sol\";\nimport \"../contracts_common/src/Libraries/BytesUtil.sol\";\n\nimport \"../contracts_common/src/BaseWithStorage/SuperOperators.sol\";\nimport \"../contracts_common/src/BaseWithStorage/MetaTransactionReceiver.sol\";\n\n\ncontract ERC20Group is SuperOperators, MetaTransactionReceiver {\n uint256 internal constant MAX_UINT256 = ~uint256(0);\n\n /// @notice emitted when a new Token is added to the group.\n /// @param subToken the token added, its id will be its index in the array.\n event SubToken(ERC20SubToken subToken);\n\n /// @notice emitted when `owner` is allowing or disallowing `operator` to transfer tokens on its behalf.\n /// @param owner the address approving.\n /// @param operator the address being granted (or revoked) permission to transfer.\n /// @param approved whether the operator is granted transfer right or not.\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n event Minter(address minter, bool enabled);\n\n /// @notice Enable or disable the ability of `minter` to mint tokens\n /// @param minter address that will be given/removed minter right.\n /// @param enabled set whether the minter is enabled or disabled.\n function setMinter(address minter, bool enabled) external {\n require(msg.sender == _admin, \"NOT_AUTHORIZED_ADMIN\");\n _setMinter(minter, enabled);\n }\n\n /// @notice check whether address `who` is given minter rights.\n /// @param who The address to query.\n /// @return whether the address has minter rights.\n function isMinter(address who) public view returns (bool) {\n return _minters[who];\n }\n\n /// @dev mint more tokens of a specific subToken .\n /// @param to address receiving the tokens.\n /// @param id subToken id (also the index at which it was added).\n /// @param amount of token minted.\n function mint(\n address to,\n uint256 id,\n uint256 amount\n ) external {\n require(_minters[msg.sender], \"NOT_AUTHORIZED_MINTER\");\n (uint256 bin, uint256 index) = id.getTokenBinIndex();\n mapping(uint256 => uint256) storage toPack = _packedTokenBalance[to];\n toPack[bin] = toPack[bin].updateTokenBalance(index, amount, ObjectLib32.Operations.ADD);\n _packedSupplies[bin] = _packedSupplies[bin].updateTokenBalance(index, amount, ObjectLib32.Operations.ADD);\n _erc20s[id].emitTransferEvent(address(0), to, amount);\n }\n\n /// @dev mint more tokens of a several subToken .\n /// @param to address receiving the tokens.\n /// @param ids subToken ids (also the index at which it was added).\n /// @param amounts for each token minted.\n function batchMint(\n address to,\n uint256[] calldata ids,\n uint256[] calldata amounts\n ) external {\n require(_minters[msg.sender], \"NOT_AUTHORIZED_MINTER\");\n require(ids.length == amounts.length, \"INVALID_INCONSISTENT_LENGTH\");\n _batchMint(to, ids, amounts);\n }\n\n function _batchMint(\n address to,\n uint256[] memory ids,\n uint256[] memory amounts\n ) internal {\n uint256 lastBin = MAX_UINT256;\n uint256 bal = 0;\n uint256 supply = 0;\n mapping(uint256 => uint256) storage toPack = _packedTokenBalance[to];\n for (uint256 i = 0; i < ids.length; i++) {\n if (amounts[i] != 0) {\n (uint256 bin, uint256 index) = ids[i].getTokenBinIndex();\n if (lastBin == MAX_UINT256) {\n lastBin = bin;\n bal = toPack[bin].updateTokenBalance(index, amounts[i], ObjectLib32.Operations.ADD);\n supply = _packedSupplies[bin].updateTokenBalance(index, amounts[i], ObjectLib32.Operations.ADD);\n } else {\n if (bin != lastBin) {\n toPack[lastBin] = bal;\n bal = toPack[bin];\n _packedSupplies[lastBin] = supply;\n supply = _packedSupplies[bin];\n lastBin = bin;\n }\n bal = bal.updateTokenBalance(index, amounts[i], ObjectLib32.Operations.ADD);\n supply = supply.updateTokenBalance(index, amounts[i], ObjectLib32.Operations.ADD);\n }\n _erc20s[ids[i]].emitTransferEvent(address(0), to, amounts[i]);\n }\n }\n if (lastBin != MAX_UINT256) {\n toPack[lastBin] = bal;\n _packedSupplies[lastBin] = supply;\n }\n }\n\n /// @notice return the current total supply of a specific subToken.\n /// @param id subToken id.\n /// @return supply current total number of tokens.\n function supplyOf(uint256 id) external view returns (uint256 supply) {\n (uint256 bin, uint256 index) = id.getTokenBinIndex();\n return _packedSupplies[bin].getValueInBin(index);\n }\n\n /// @notice return the balance of a particular owner for a particular subToken.\n /// @param owner whose balance it is of.\n /// @param id subToken id.\n /// @return balance of the owner\n function balanceOf(address owner, uint256 id) public view returns (uint256 balance) {\n (uint256 bin, uint256 index) = id.getTokenBinIndex();\n return _packedTokenBalance[owner][bin].getValueInBin(index);\n }\n\n /// @notice return the balances of a list of owners / subTokens.\n /// @param owners list of addresses to which we want to know the balance.\n /// @param ids list of subTokens's addresses.\n /// @return balances list of balances for each request.\n function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) external view returns (uint256[] memory balances) {\n require(owners.length == ids.length, \"INVALID_INCONSISTENT_LENGTH\");\n balances = new uint256[](ids.length);\n for (uint256 i = 0; i < ids.length; i++) {\n balances[i] = balanceOf(owners[i], ids[i]);\n }\n }\n\n /// @notice transfer a number of subToken from one address to another.\n /// @param from owner to transfer from.\n /// @param to destination address that will receive the tokens.\n /// @param id subToken id.\n /// @param value amount of tokens to transfer.\n function singleTransferFrom(\n address from,\n address to,\n uint256 id,\n uint256 value\n ) external {\n require(to != address(0), \"INVALID_TO_ZERO_ADDRESS\");\n ERC20SubToken erc20 = _erc20s[id];\n require(\n from == msg.sender ||\n msg.sender == address(erc20) ||\n _metaTransactionContracts[msg.sender] ||\n _superOperators[msg.sender] ||\n _operatorsForAll[from][msg.sender],\n \"NOT_AUTHORIZED\"\n );\n\n (uint256 bin, uint256 index) = id.getTokenBinIndex();\n mapping(uint256 => uint256) storage fromPack = _packedTokenBalance[from];\n mapping(uint256 => uint256) storage toPack = _packedTokenBalance[to];\n fromPack[bin] = fromPack[bin].updateTokenBalance(index, value, ObjectLib32.Operations.SUB);\n toPack[bin] = toPack[bin].updateTokenBalance(index, value, ObjectLib32.Operations.ADD);\n erc20.emitTransferEvent(from, to, value);\n }\n\n /// @notice transfer a number of different subTokens from one address to another.\n /// @param from owner to transfer from.\n /// @param to destination address that will receive the tokens.\n /// @param ids list of subToken ids to transfer.\n /// @param values list of amount for eacg subTokens to transfer.\n function batchTransferFrom(\n address from,\n address to,\n uint256[] calldata ids,\n uint256[] calldata values\n ) external {\n require(ids.length == values.length, \"INVALID_INCONSISTENT_LENGTH\");\n require(to != address(0), \"INVALID_TO_ZERO_ADDRESS\");\n require(\n from == msg.sender || _superOperators[msg.sender] || _operatorsForAll[from][msg.sender] || _metaTransactionContracts[msg.sender],\n \"NOT_AUTHORIZED\"\n );\n _batchTransferFrom(from, to, ids, values);\n }\n\n function _batchTransferFrom(\n address from,\n address to,\n uint256[] memory ids,\n uint256[] memory values\n ) internal {\n uint256 lastBin = MAX_UINT256;\n uint256 balFrom;\n uint256 balTo;\n mapping(uint256 => uint256) storage fromPack = _packedTokenBalance[from];\n mapping(uint256 => uint256) storage toPack = _packedTokenBalance[to];\n for (uint256 i = 0; i < ids.length; i++) {\n if (values[i] != 0) {\n (uint256 bin, uint256 index) = ids[i].getTokenBinIndex();\n if (lastBin == MAX_UINT256) {\n lastBin = bin;\n balFrom = ObjectLib32.updateTokenBalance(fromPack[bin], index, values[i], ObjectLib32.Operations.SUB);\n balTo = ObjectLib32.updateTokenBalance(toPack[bin], index, values[i], ObjectLib32.Operations.ADD);\n } else {\n if (bin != lastBin) {\n fromPack[lastBin] = balFrom;\n toPack[lastBin] = balTo;\n balFrom = fromPack[bin];\n balTo = toPack[bin];\n lastBin = bin;\n }\n balFrom = balFrom.updateTokenBalance(index, values[i], ObjectLib32.Operations.SUB);\n balTo = balTo.updateTokenBalance(index, values[i], ObjectLib32.Operations.ADD);\n }\n ERC20SubToken erc20 = _erc20s[ids[i]];\n erc20.emitTransferEvent(from, to, values[i]);\n }\n }\n if (lastBin != MAX_UINT256) {\n fromPack[lastBin] = balFrom;\n toPack[lastBin] = balTo;\n }\n }\n\n /// @notice grant or revoke the ability for an address to transfer token on behalf of another address.\n /// @param sender address granting/revoking the approval.\n /// @param operator address being granted/revoked ability to transfer.\n /// @param approved whether the operator is revoked or approved.\n function setApprovalForAllFor(\n address sender,\n address operator,\n bool approved\n ) external {\n require(msg.sender == sender || _metaTransactionContracts[msg.sender] || _superOperators[msg.sender], \"NOT_AUTHORIZED\");\n _setApprovalForAll(sender, operator, approved);\n }\n\n /// @notice grant or revoke the ability for an address to transfer token on your behalf.\n /// @param operator address being granted/revoked ability to transfer.\n /// @param approved whether the operator is revoked or approved.\n function setApprovalForAll(address operator, bool approved) external {\n _setApprovalForAll(msg.sender, operator, approved);\n }\n\n /// @notice return whether an oeprator has the ability to transfer on behalf of another address.\n /// @param owner address who would have granted the rights.\n /// @param operator address being given the ability to transfer.\n /// @return isOperator whether the operator has approval rigths or not.\n function isApprovedForAll(address owner, address operator) external view returns (bool isOperator) {\n return _operatorsForAll[owner][operator] || _superOperators[operator];\n }\n\n function isAuthorizedToTransfer(address owner, address sender) external view returns (bool) {\n return _metaTransactionContracts[sender] || _superOperators[sender] || _operatorsForAll[owner][sender];\n }\n\n function isAuthorizedToApprove(address sender) external view returns (bool) {\n return _metaTransactionContracts[sender] || _superOperators[sender];\n }\n\n function batchBurnFrom(\n address from,\n uint256[] calldata ids,\n uint256[] calldata amounts\n ) external {\n require(from != address(0), \"INVALID_FROM_ZERO_ADDRESS\");\n require(\n from == msg.sender || _metaTransactionContracts[msg.sender] || _superOperators[msg.sender] || _operatorsForAll[from][msg.sender],\n \"NOT_AUTHORIZED\"\n );\n\n _batchBurnFrom(from, ids, amounts);\n }\n\n /// @notice burn token for a specific owner and subToken.\n /// @param from fron which address the token are burned from.\n /// @param id subToken id.\n /// @param value amount of tokens to burn.\n function burnFrom(\n address from,\n uint256 id,\n uint256 value\n ) external {\n require(\n from == msg.sender || _superOperators[msg.sender] || _operatorsForAll[from][msg.sender] || _metaTransactionContracts[msg.sender],\n \"NOT_AUTHORIZED\"\n );\n _burn(from, id, value);\n }\n\n /// @notice burn token for a specific subToken.\n /// @param id subToken id.\n /// @param value amount of tokens to burn.\n function burn(uint256 id, uint256 value) external {\n _burn(msg.sender, id, value);\n }\n\n // ///////////////// INTERNAL //////////////////////////\n\n function _batchBurnFrom(\n address from,\n uint256[] memory ids,\n uint256[] memory amounts\n ) internal {\n uint256 balFrom = 0;\n uint256 supply = 0;\n uint256 lastBin = MAX_UINT256;\n mapping(uint256 => uint256) storage fromPack = _packedTokenBalance[from];\n for (uint256 i = 0; i < ids.length; i++) {\n if (amounts[i] != 0) {\n (uint256 bin, uint256 index) = ids[i].getTokenBinIndex();\n if (lastBin == MAX_UINT256) {\n lastBin = bin;\n balFrom = fromPack[bin].updateTokenBalance(index, amounts[i], ObjectLib32.Operations.SUB);\n supply = _packedSupplies[bin].updateTokenBalance(index, amounts[i], ObjectLib32.Operations.SUB);\n } else {\n if (bin != lastBin) {\n fromPack[lastBin] = balFrom;\n balFrom = fromPack[bin];\n _packedSupplies[lastBin] = supply;\n supply = _packedSupplies[bin];\n lastBin = bin;\n }\n\n balFrom = balFrom.updateTokenBalance(index, amounts[i], ObjectLib32.Operations.SUB);\n supply = supply.updateTokenBalance(index, amounts[i], ObjectLib32.Operations.SUB);\n }\n _erc20s[ids[i]].emitTransferEvent(from, address(0), amounts[i]);\n }\n }\n if (lastBin != MAX_UINT256) {\n fromPack[lastBin] = balFrom;\n _packedSupplies[lastBin] = supply;\n }\n }\n\n function _burn(\n address from,\n uint256 id,\n uint256 value\n ) internal {\n ERC20SubToken erc20 = _erc20s[id];\n (uint256 bin, uint256 index) = id.getTokenBinIndex();\n mapping(uint256 => uint256) storage fromPack = _packedTokenBalance[from];\n fromPack[bin] = ObjectLib32.updateTokenBalance(fromPack[bin], index, value, ObjectLib32.Operations.SUB);\n _packedSupplies[bin] = ObjectLib32.updateTokenBalance(_packedSupplies[bin], index, value, ObjectLib32.Operations.SUB);\n erc20.emitTransferEvent(from, address(0), value);\n }\n\n function _addSubToken(ERC20SubToken subToken) internal returns (uint256 id) {\n id = _erc20s.length;\n require(subToken.groupAddress() == address(this), \"INVALID_GROUP\");\n require(subToken.groupTokenId() == id, \"INVALID_ID\");\n _erc20s.push(subToken);\n emit SubToken(subToken);\n }\n\n function _setApprovalForAll(\n address sender,\n address operator,\n bool approved\n ) internal {\n require(!_superOperators[operator], \"INVALID_SUPER_OPERATOR\");\n _operatorsForAll[sender][operator] = approved;\n emit ApprovalForAll(sender, operator, approved);\n }\n\n function _setMinter(address minter, bool enabled) internal {\n _minters[minter] = enabled;\n emit Minter(minter, enabled);\n }\n\n // ///////////////// UTILITIES /////////////////////////\n using AddressUtils for address;\n using ObjectLib32 for ObjectLib32.Operations;\n using ObjectLib32 for uint256;\n using SafeMath for uint256;\n\n // ////////////////// DATA ///////////////////////////////\n mapping(uint256 => uint256) internal _packedSupplies;\n mapping(address => mapping(uint256 => uint256)) internal _packedTokenBalance;\n mapping(address => mapping(address => bool)) internal _operatorsForAll;\n ERC20SubToken[] internal _erc20s;\n mapping(address => bool) internal _minters;\n\n // ////////////// CONSTRUCTOR ////////////////////////////\n\n struct SubTokenData {\n string name;\n string symbol;\n }\n\n constructor(\n address metaTransactionContract,\n address admin,\n address initialMinter\n ) internal {\n _admin = admin;\n _setMetaTransactionProcessor(metaTransactionContract, true);\n _setMinter(initialMinter, true);\n }\n}\n"
},
"src/BaseWithStorage/ERC20SubToken.sol": {
"content": "pragma solidity 0.6.5;\n\nimport \"../contracts_common/src/Libraries/SafeMathWithRequire.sol\";\nimport \"../contracts_common/src/BaseWithStorage/SuperOperators.sol\";\nimport \"../contracts_common/src/BaseWithStorage/MetaTransactionReceiver.sol\";\n\nimport \"./ERC20Group.sol\";\n\n\ncontract ERC20SubToken {\n // TODO add natspec, currently blocked by solidity compiler issue\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n // TODO add natspec, currently blocked by solidity compiler issue\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// @notice A descriptive name for the tokens\n /// @return name of the tokens\n function name() public view returns (string memory) {\n return _name;\n }\n\n /// @notice An abbreviated name for the tokens\n /// @return symbol of the tokens\n function symbol() public view returns (string memory) {\n return _symbol;\n }\n\n /// @notice the tokenId in ERC20Group\n /// @return the tokenId in ERC20Group\n function groupTokenId() external view returns (uint256) {\n return _index;\n }\n\n /// @notice the ERC20Group address\n /// @return the address of the group\n function groupAddress() external view returns (address) {\n return address(_group);\n }\n\n function totalSupply() external view returns (uint256) {\n return _group.supplyOf(_index);\n }\n\n function balanceOf(address who) external view returns (uint256) {\n return _group.balanceOf(who, _index);\n }\n\n function decimals() external pure returns (uint8) {\n return uint8(0);\n }\n\n function transfer(address to, uint256 amount) external returns (bool success) {\n _transfer(msg.sender, to, amount);\n return true;\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool success) {\n if (msg.sender != from && !_group.isAuthorizedToTransfer(from, msg.sender)) {\n uint256 allowance = _mAllowed[from][msg.sender];\n if (allowance != ~uint256(0)) {\n // save gas when allowance is maximal by not reducing it (see https://github.com/ethereum/EIPs/issues/717)\n require(allowance >= amount, \"NOT_AUTHOIZED_ALLOWANCE\");\n _mAllowed[from][msg.sender] = allowance - amount;\n }\n }\n _transfer(from, to, amount);\n return true;\n }\n\n function approve(address spender, uint256 amount) external returns (bool success) {\n _approveFor(msg.sender, spender, amount);\n return true;\n }\n\n function approveFor(\n address from,\n address spender,\n uint256 amount\n ) external returns (bool success) {\n require(msg.sender == from || _group.isAuthorizedToApprove(msg.sender), \"NOT_AUTHORIZED\");\n _approveFor(from, spender, amount);\n return true;\n }\n\n function emitTransferEvent(\n address from,\n address to,\n uint256 amount\n ) external {\n require(msg.sender == address(_group), \"NOT_AUTHORIZED_GROUP_ONLY\");\n emit Transfer(from, to, amount);\n }\n\n // /////////////////// INTERNAL ////////////////////////\n\n function _approveFor(\n address owner,\n address spender,\n uint256 amount\n ) internal {\n require(owner != address(0) && spender != address(0), \"INVALID_FROM_OR_SPENDER\");\n _mAllowed[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n function allowance(address owner, address spender) external view returns (uint256 remaining) {\n return _mAllowed[owner][spender];\n }\n\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal {\n _group.singleTransferFrom(from, to, _index, amount);\n }\n\n // ///////////////////// UTILITIES ///////////////////////\n using SafeMathWithRequire for uint256;\n\n // //////////////////// CONSTRUCTOR /////////////////////\n constructor(\n ERC20Group group,\n uint256 index,\n string memory tokenName,\n string memory tokenSymbol\n ) public {\n _group = group;\n _index = index;\n _name = tokenName;\n _symbol = tokenSymbol;\n }\n\n // ////////////////////// DATA ///////////////////////////\n ERC20Group internal immutable _group;\n uint256 internal immutable _index;\n mapping(address => mapping(address => uint256)) internal _mAllowed;\n string internal _name;\n string internal _symbol;\n}\n"
},
"src/contracts_common/src/Libraries/SafeMathWithRequire.sol": {
"content": "pragma solidity ^0.6.0;\n\n\n/**\n * @title SafeMath\n * @dev Math operations with safety checks that revert\n */\nlibrary SafeMathWithRequire {\n /**\n * @dev Multiplies two numbers, throws on overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {\n // Gas optimization: this is cheaper than asserting 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522\n if (a == 0) {\n return 0;\n }\n\n c = a * b;\n require(c / a == b, \"overflow\");\n return c;\n }\n\n /**\n * @dev Integer division of two numbers, truncating the quotient.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n require(b != 0, \"divbyzero\");\n // uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n return a / b;\n }\n\n /**\n * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n require(b <= a, \"undeflow\");\n return a - b;\n }\n\n /**\n * @dev Adds two numbers, throws on overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256 c) {\n c = a + b;\n require(c >= a, \"overflow\");\n return c;\n }\n}\n"
},
"src/contracts_common/src/BaseWithStorage/SuperOperators.sol": {
"content": "pragma solidity ^0.6.0;\n\nimport \"./Admin.sol\";\n\n\ncontract SuperOperators is Admin {\n mapping(address => bool) internal _superOperators;\n\n event SuperOperator(address superOperator, bool enabled);\n\n /// @notice Enable or disable the ability of `superOperator` to transfer tokens of all (superOperator rights).\n /// @param superOperator address that will be given/removed superOperator right.\n /// @param enabled set whether the superOperator is enabled or disabled.\n function setSuperOperator(address superOperator, bool enabled) external {\n require(msg.sender == _admin, \"only admin is allowed to add super operators\");\n _superOperators[superOperator] = enabled;\n emit SuperOperator(superOperator, enabled);\n }\n\n /// @notice check whether address `who` is given superOperator rights.\n /// @param who The address to query.\n /// @return whether the address has superOperator rights.\n function isSuperOperator(address who) public view returns (bool) {\n return _superOperators[who];\n }\n}\n"
},
"src/contracts_common/src/BaseWithStorage/Admin.sol": {
"content": "pragma solidity ^0.6.0;\n\n\ncontract Admin {\n address internal _admin;\n\n /// @dev emitted when the contract administrator is changed.\n /// @param oldAdmin address of the previous administrator.\n /// @param newAdmin address of the new administrator.\n event AdminChanged(address oldAdmin, address newAdmin);\n\n /// @dev gives the current administrator of this contract.\n /// @return the current administrator of this contract.\n function getAdmin() external view returns (address) {\n return _admin;\n }\n\n /// @dev change the administrator to be `newAdmin`.\n /// @param newAdmin address of the new administrator.\n function changeAdmin(address newAdmin) external {\n require(msg.sender == _admin, \"only admin can change admin\");\n emit AdminChanged(_admin, newAdmin);\n _admin = newAdmin;\n }\n\n modifier onlyAdmin() {\n require(msg.sender == _admin, \"only admin allowed\");\n _;\n }\n}\n"
},
"src/contracts_common/src/BaseWithStorage/MetaTransactionReceiver.sol": {
"content": "pragma solidity ^0.6.0;\n\nimport \"./Admin.sol\";\n\n\ncontract MetaTransactionReceiver is Admin {\n mapping(address => bool) internal _metaTransactionContracts;\n\n /// @dev emiited when a meta transaction processor is enabled/disabled\n /// @param metaTransactionProcessor address that will be given/removed metaTransactionProcessor rights.\n /// @param enabled set whether the metaTransactionProcessor is enabled or disabled.\n event MetaTransactionProcessor(address metaTransactionProcessor, bool enabled);\n\n /// @dev Enable or disable the ability of `metaTransactionProcessor` to perform meta-tx (metaTransactionProcessor rights).\n /// @param metaTransactionProcessor address that will be given/removed metaTransactionProcessor rights.\n /// @param enabled set whether the metaTransactionProcessor is enabled or disabled.\n function setMetaTransactionProcessor(address metaTransactionProcessor, bool enabled) public {\n require(msg.sender == _admin, \"only admin can setup metaTransactionProcessors\");\n _setMetaTransactionProcessor(metaTransactionProcessor, enabled);\n }\n\n function _setMetaTransactionProcessor(address metaTransactionProcessor, bool enabled) internal {\n _metaTransactionContracts[metaTransactionProcessor] = enabled;\n emit MetaTransactionProcessor(metaTransactionProcessor, enabled);\n }\n\n /// @dev check whether address `who` is given meta-transaction execution rights.\n /// @param who The address to query.\n /// @return whether the address has meta-transaction execution rights.\n function isMetaTransactionProcessor(address who) external view returns (bool) {\n return _metaTransactionContracts[who];\n }\n}\n"
},
"src/contracts_common/src/Libraries/SafeMath.sol": {
"content": "pragma solidity ^0.6.0;\n\n\n/**\n * @title SafeMath\n * @dev Math operations with safety checks that throw on error\n */\nlibrary SafeMath {\n /**\n * @dev Multiplies two numbers, throws on overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {\n // Gas optimization: this is cheaper than asserting 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522\n if (a == 0) {\n return 0;\n }\n\n c = a * b;\n assert(c / a == b);\n return c;\n }\n\n /**\n * @dev Integer division of two numbers, truncating the quotient.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n // assert(b > 0); // Solidity automatically throws when dividing by 0\n // uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n return a / b;\n }\n\n /**\n * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n assert(b <= a);\n return a - b;\n }\n\n /**\n * @dev Adds two numbers, throws on overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256 c) {\n c = a + b;\n assert(c >= a);\n return c;\n }\n}\n"
},
"src/contracts_common/src/Libraries/AddressUtils.sol": {
"content": "pragma solidity ^0.6.0;\n\n\nlibrary AddressUtils {\n function toPayable(address _address) internal pure returns (address payable _payable) {\n return address(uint160(_address));\n }\n\n function isContract(address addr) internal view returns (bool) {\n // for accounts without code, i.e. `keccak256('')`:\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\n\n bytes32 codehash;\n // solium-disable-next-line security/no-inline-assembly\n assembly {\n codehash := extcodehash(addr)\n }\n return (codehash != 0x0 && codehash != accountHash);\n }\n}\n"
},
"src/contracts_common/src/Libraries/ObjectLib32.sol": {
"content": "pragma solidity ^0.6.0;\n\nimport \"./SafeMathWithRequire.sol\";\n\n\nlibrary ObjectLib32 {\n using SafeMathWithRequire for uint256;\n enum Operations {ADD, SUB, REPLACE}\n // Constants regarding bin or chunk sizes for balance packing\n uint256 constant TYPES_BITS_SIZE = 32; // Max size of each object\n uint256 constant TYPES_PER_UINT256 = 256 / TYPES_BITS_SIZE; // Number of types per uint256\n\n //\n // Objects and Tokens Functions\n //\n\n /**\n * @dev Return the bin number and index within that bin where ID is\n * @param tokenId Object type\n * @return bin Bin number\n * @return index ID's index within that bin\n */\n function getTokenBinIndex(uint256 tokenId) internal pure returns (uint256 bin, uint256 index) {\n bin = (tokenId * TYPES_BITS_SIZE) / 256;\n index = tokenId % TYPES_PER_UINT256;\n return (bin, index);\n }\n\n /**\n * @dev update the balance of a type provided in binBalances\n * @param binBalances Uint256 containing the balances of objects\n * @param index Index of the object in the provided bin\n * @param amount Value to update the type balance\n * @param operation Which operation to conduct :\n * Operations.REPLACE : Replace type balance with amount\n * Operations.ADD : ADD amount to type balance\n * Operations.SUB : Substract amount from type balance\n */\n function updateTokenBalance(\n uint256 binBalances,\n uint256 index,\n uint256 amount,\n Operations operation\n ) internal pure returns (uint256 newBinBalance) {\n uint256 objectBalance = 0;\n if (operation == Operations.ADD) {\n objectBalance = getValueInBin(binBalances, index);\n newBinBalance = writeValueInBin(binBalances, index, objectBalance.add(amount));\n } else if (operation == Operations.SUB) {\n objectBalance = getValueInBin(binBalances, index);\n require(objectBalance >= amount, \"can't substract more than there is\");\n newBinBalance = writeValueInBin(binBalances, index, objectBalance.sub(amount));\n } else if (operation == Operations.REPLACE) {\n newBinBalance = writeValueInBin(binBalances, index, amount);\n } else {\n revert(\"Invalid operation\"); // Bad operation\n }\n\n return newBinBalance;\n }\n\n /*\n * @dev return value in binValue at position index\n * @param binValue uint256 containing the balances of TYPES_PER_UINT256 types\n * @param index index at which to retrieve value\n * @return Value at given index in bin\n */\n function getValueInBin(uint256 binValue, uint256 index) internal pure returns (uint256) {\n // Mask to retrieve data for a given binData\n uint256 mask = (uint256(1) << TYPES_BITS_SIZE) - 1;\n\n // Shift amount\n uint256 rightShift = 256 - TYPES_BITS_SIZE * (index + 1);\n return (binValue >> rightShift) & mask;\n }\n\n /**\n * @dev return the updated binValue after writing amount at index\n * @param binValue uint256 containing the balances of TYPES_PER_UINT256 types\n * @param index Index at which to retrieve value\n * @param amount Value to store at index in bin\n * @return Value at given index in bin\n */\n function writeValueInBin(\n uint256 binValue,\n uint256 index,\n uint256 amount\n ) internal pure returns (uint256) {\n require(amount < 2**TYPES_BITS_SIZE, \"Amount to write in bin is too large\");\n\n // Mask to retrieve data for a given binData\n uint256 mask = (uint256(1) << TYPES_BITS_SIZE) - 1;\n\n // Shift amount\n uint256 leftShift = 256 - TYPES_BITS_SIZE * (index + 1);\n return (binValue & ~(mask << leftShift)) | (amount << leftShift);\n }\n}\n"
},
"src/contracts_common/src/Libraries/BytesUtil.sol": {
"content": "pragma solidity ^0.6.0;\n\n\nlibrary BytesUtil {\n function memcpy(\n uint256 dest,\n uint256 src,\n uint256 len\n ) internal pure {\n // Copy word-length chunks while possible\n for (; len >= 32; len -= 32) {\n assembly {\n mstore(dest, mload(src))\n }\n dest += 32;\n src += 32;\n }\n\n // Copy remaining bytes\n uint256 mask = 256**(32 - len) - 1;\n assembly {\n let srcpart := and(mload(src), not(mask))\n let destpart := and(mload(dest), mask)\n mstore(dest, or(destpart, srcpart))\n }\n }\n\n function pointerToBytes(uint256 src, uint256 len) internal pure returns (bytes memory) {\n bytes memory ret = new bytes(len);\n uint256 retptr;\n assembly {\n retptr := add(ret, 32)\n }\n\n memcpy(retptr, src, len);\n return ret;\n }\n\n function addressToBytes(address a) internal pure returns (bytes memory b) {\n assembly {\n let m := mload(0x40)\n mstore(add(m, 20), xor(0x140000000000000000000000000000000000000000, a))\n mstore(0x40, add(m, 52))\n b := m\n }\n }\n\n function uint256ToBytes(uint256 a) internal pure returns (bytes memory b) {\n assembly {\n let m := mload(0x40)\n mstore(add(m, 32), a)\n mstore(0x40, add(m, 64))\n b := m\n }\n }\n\n function doFirstParamEqualsAddress(bytes memory data, address _address) internal pure returns (bool) {\n if (data.length < (36 + 32)) {\n return false;\n }\n uint256 value;\n assembly {\n value := mload(add(data, 36))\n }\n return value == uint256(_address);\n }\n\n function doParamEqualsUInt256(\n bytes memory data,\n uint256 i,\n uint256 value\n ) internal pure returns (bool) {\n if (data.length < (36 + (i + 1) * 32)) {\n return false;\n }\n uint256 offset = 36 + i * 32;\n uint256 valuePresent;\n assembly {\n valuePresent := mload(add(data, offset))\n }\n return valuePresent == value;\n }\n\n function overrideFirst32BytesWithAddress(bytes memory data, address _address) internal pure returns (bytes memory) {\n uint256 dest;\n assembly {\n dest := add(data, 48)\n } // 48 = 32 (offset) + 4 (func sig) + 12 (address is only 20 bytes)\n\n bytes memory addressBytes = addressToBytes(_address);\n uint256 src;\n assembly {\n src := add(addressBytes, 32)\n }\n\n memcpy(dest, src, 20);\n return data;\n }\n\n function overrideFirstTwo32BytesWithAddressAndInt(\n bytes memory data,\n address _address,\n uint256 _value\n ) internal pure returns (bytes memory) {\n uint256 dest;\n uint256 src;\n\n assembly {\n dest := add(data, 48)\n } // 48 = 32 (offset) + 4 (func sig) + 12 (address is only 20 bytes)\n bytes memory bbytes = addressToBytes(_address);\n assembly {\n src := add(bbytes, 32)\n }\n memcpy(dest, src, 20);\n\n assembly {\n dest := add(data, 68)\n } // 48 = 32 (offset) + 4 (func sig) + 32 (next slot)\n bbytes = uint256ToBytes(_value);\n assembly {\n src := add(bbytes, 32)\n }\n memcpy(dest, src, 32);\n\n return data;\n }\n}\n"
},
"src/BaseWithStorage/ERC721BaseToken.sol": {
"content": "/* solhint-disable func-order, code-complexity */\npragma solidity 0.6.5;\n\nimport \"../contracts_common/src/Libraries/AddressUtils.sol\";\nimport \"../contracts_common/src/Interfaces/ERC721TokenReceiver.sol\";\nimport \"../contracts_common/src/Interfaces/ERC721Events.sol\";\nimport \"../contracts_common/src/BaseWithStorage/SuperOperators.sol\";\nimport \"../contracts_common/src/BaseWithStorage/MetaTransactionReceiver.sol\";\nimport \"../contracts_common/src/Interfaces/ERC721MandatoryTokenReceiver.sol\";\n\n\ncontract ERC721BaseToken is ERC721Events, SuperOperators, MetaTransactionReceiver {\n using AddressUtils for address;\n\n bytes4 internal constant _ERC721_RECEIVED = 0x150b7a02;\n bytes4 internal constant _ERC721_BATCH_RECEIVED = 0x4b808c46;\n\n bytes4 internal constant ERC165ID = 0x01ffc9a7;\n bytes4 internal constant ERC721_MANDATORY_RECEIVER = 0x5e8bf644;\n\n mapping(address => uint256) public _numNFTPerAddress;\n mapping(uint256 => uint256) public _owners;\n mapping(address => mapping(address => bool)) public _operatorsForAll;\n mapping(uint256 => address) public _operators;\n\n constructor(address metaTransactionContract, address admin) internal {\n _admin = admin;\n _setMetaTransactionProcessor(metaTransactionContract, true);\n }\n\n function _transferFrom(\n address from,\n address to,\n uint256 id\n ) internal {\n _numNFTPerAddress[from]--;\n _numNFTPerAddress[to]++;\n _owners[id] = uint256(to);\n emit Transfer(from, to, id);\n }\n\n /**\n * @notice Return the number of Land owned by an address\n * @param owner The address to look for\n * @return The number of Land token owned by the address\n */\n function balanceOf(address owner) external view returns (uint256) {\n require(owner != address(0), \"owner is zero address\");\n return _numNFTPerAddress[owner];\n }\n\n function _ownerOf(uint256 id) internal virtual view returns (address) {\n uint256 data = _owners[id];\n if ((data & (2**160)) == 2**160) {\n return address(0);\n }\n return address(data);\n }\n\n function _ownerAndOperatorEnabledOf(uint256 id) internal view returns (address owner, bool operatorEnabled) {\n uint256 data = _owners[id];\n if ((data & (2**160)) == 2**160) {\n owner = address(0);\n } else {\n owner = address(data);\n }\n operatorEnabled = (data / 2**255) == 1;\n }\n\n /**\n * @notice Return the owner of a Land\n * @param id The id of the Land\n * @return owner The address of the owner\n */\n function ownerOf(uint256 id) external view returns (address owner) {\n owner = _ownerOf(id);\n require(owner != address(0), \"token does not exist\");\n }\n\n function _approveFor(\n address owner,\n address operator,\n uint256 id\n ) internal {\n if (operator == address(0)) {\n _owners[id] = _owners[id] & (2**255 - 1); // no need to resset the operator, it will be overriden next time\n } else {\n _owners[id] = _owners[id] | (2**255);\n _operators[id] = operator;\n }\n emit Approval(owner, operator, id);\n }\n\n /**\n * @notice Approve an operator to spend tokens on the sender behalf\n * @param sender The address giving the approval\n * @param operator The address receiving the approval\n * @param id The id of the token\n */\n function approveFor(\n address sender,\n address operator,\n uint256 id\n ) external {\n address owner = _ownerOf(id);\n require(sender != address(0), \"sender is zero address\");\n require(\n msg.sender == sender || _metaTransactionContracts[msg.sender] || _superOperators[msg.sender] || _operatorsForAll[sender][msg.sender],\n \"not authorized to approve\"\n );\n require(owner == sender, \"owner != sender\");\n _approveFor(owner, operator, id);\n }\n\n /**\n * @notice Approve an operator to spend tokens on the sender behalf\n * @param operator The address receiving the approval\n * @param id The id of the token\n */\n function approve(address operator, uint256 id) external {\n address owner = _ownerOf(id);\n require(owner != address(0), \"token does not exist\");\n require(owner == msg.sender || _superOperators[msg.sender] || _operatorsForAll[owner][msg.sender], \"not authorized to approve\");\n _approveFor(owner, operator, id);\n }\n\n /**\n * @notice Get the approved operator for a specific token\n * @param id The id of the token\n * @return The address of the operator\n */\n function getApproved(uint256 id) external view returns (address) {\n (address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(id);\n require(owner != address(0), \"token does not exist\");\n if (operatorEnabled) {\n return _operators[id];\n } else {\n return address(0);\n }\n }\n\n function _checkTransfer(\n address from,\n address to,\n uint256 id\n ) internal view returns (bool isMetaTx) {\n (address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(id);\n require(owner != address(0), \"token does not exist\");\n require(owner == from, \"not owner in _checkTransfer\");\n require(to != address(0), \"can't send to zero address\");\n isMetaTx = msg.sender != from && _metaTransactionContracts[msg.sender];\n if (msg.sender != from && !isMetaTx) {\n require(\n _superOperators[msg.sender] || _operatorsForAll[from][msg.sender] || (operatorEnabled && _operators[id] == msg.sender),\n \"not approved to transfer\"\n );\n }\n }\n\n function _checkInterfaceWith10000Gas(address _contract, bytes4 interfaceId) internal view returns (bool) {\n bool success;\n bool result;\n bytes memory call_data = abi.encodeWithSelector(ERC165ID, interfaceId);\n // solium-disable-next-line security/no-inline-assembly\n assembly {\n let call_ptr := add(0x20, call_data)\n let call_size := mload(call_data)\n let output := mload(0x40) // Find empty storage location using \"free memory pointer\"\n mstore(output, 0x0)\n success := staticcall(10000, _contract, call_ptr, call_size, output, 0x20) // 32 bytes\n result := mload(output)\n }\n // (10000 / 63) \"not enough for supportsInterface(...)\" // consume all gas, so caller can potentially know that there was not enough gas\n assert(gasleft() > 158);\n return success && result;\n }\n\n /**\n * @notice Transfer a token between 2 addresses\n * @param from The sender of the token\n * @param to The recipient of the token\n * @param id The id of the token\n */\n function transferFrom(\n address from,\n address to,\n uint256 id\n ) external {\n bool metaTx = _checkTransfer(from, to, id);\n _transferFrom(from, to, id);\n if (to.isContract() && _checkInterfaceWith10000Gas(to, ERC721_MANDATORY_RECEIVER)) {\n require(_checkOnERC721Received(metaTx ? from : msg.sender, from, to, id, \"\"), \"erc721 transfer rejected by to\");\n }\n }\n\n /**\n * @notice Transfer a token between 2 addresses letting the receiver knows of the transfer\n * @param from The sender of the token\n * @param to The recipient of the token\n * @param id The id of the token\n * @param data Additional data\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 id,\n bytes memory data\n ) public {\n bool metaTx = _checkTransfer(from, to, id);\n _transferFrom(from, to, id);\n if (to.isContract()) {\n require(_checkOnERC721Received(metaTx ? from : msg.sender, from, to, id, data), \"ERC721: transfer rejected by to\");\n }\n }\n\n /**\n * @notice Transfer a token between 2 addresses letting the receiver knows of the transfer\n * @param from The send of the token\n * @param to The recipient of the token\n * @param id The id of the token\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 id\n ) external {\n safeTransferFrom(from, to, id, \"\");\n }\n\n /**\n * @notice Transfer many tokens between 2 addresses\n * @param from The sender of the token\n * @param to The recipient of the token\n * @param ids The ids of the tokens\n * @param data additional data\n */\n function batchTransferFrom(\n address from,\n address to,\n uint256[] calldata ids,\n bytes calldata data\n ) external {\n _batchTransferFrom(from, to, ids, data, false);\n }\n\n function _batchTransferFrom(\n address from,\n address to,\n uint256[] memory ids,\n bytes memory data,\n bool safe\n ) internal {\n bool metaTx = msg.sender != from && _metaTransactionContracts[msg.sender];\n bool authorized = msg.sender == from || metaTx || _superOperators[msg.sender] || _operatorsForAll[from][msg.sender];\n\n require(from != address(0), \"from is zero address\");\n require(to != address(0), \"can't send to zero address\");\n\n uint256 numTokens = ids.length;\n for (uint256 i = 0; i < numTokens; i++) {\n uint256 id = ids[i];\n (address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(id);\n require(owner == from, \"not owner in batchTransferFrom\");\n require(authorized || (operatorEnabled && _operators[id] == msg.sender), \"not authorized\");\n _owners[id] = uint256(to);\n emit Transfer(from, to, id);\n }\n if (from != to) {\n _numNFTPerAddress[from] -= numTokens;\n _numNFTPerAddress[to] += numTokens;\n }\n\n if (to.isContract() && (safe || _checkInterfaceWith10000Gas(to, ERC721_MANDATORY_RECEIVER))) {\n require(_checkOnERC721BatchReceived(metaTx ? from : msg.sender, from, to, ids, data), \"erc721 batch transfer rejected by to\");\n }\n }\n\n /**\n * @notice Transfer many tokens between 2 addresses ensuring the receiving contract has a receiver method\n * @param from The sender of the token\n * @param to The recipient of the token\n * @param ids The ids of the tokens\n * @param data additional data\n */\n function safeBatchTransferFrom(\n address from,\n address to,\n uint256[] calldata ids,\n bytes calldata data\n ) external {\n _batchTransferFrom(from, to, ids, data, true);\n }\n\n /**\n * @notice Check if the contract supports an interface\n * 0x01ffc9a7 is ERC-165\n * 0x80ac58cd is ERC-721\n * @param id The id of the interface\n * @return True if the interface is supported\n */\n function supportsInterface(bytes4 id) public virtual pure returns (bool) {\n return id == 0x01ffc9a7 || id == 0x80ac58cd;\n }\n\n /**\n * @notice Set the approval for an operator to manage all the tokens of the sender\n * @param sender The address giving the approval\n * @param operator The address receiving the approval\n * @param approved The determination of the approval\n */\n function setApprovalForAllFor(\n address sender,\n address operator,\n bool approved\n ) external {\n require(sender != address(0), \"Invalid sender address\");\n require(msg.sender == sender || _metaTransactionContracts[msg.sender] || _superOperators[msg.sender], \"not authorized to approve for all\");\n\n _setApprovalForAll(sender, operator, approved);\n }\n\n /**\n * @notice Set the approval for an operator to manage all the tokens of the sender\n * @param operator The address receiving the approval\n * @param approved The determination of the approval\n */\n function setApprovalForAll(address operator, bool approved) external {\n _setApprovalForAll(msg.sender, operator, approved);\n }\n\n function _setApprovalForAll(\n address sender,\n address operator,\n bool approved\n ) internal {\n require(!_superOperators[operator], \"super operator can't have their approvalForAll changed\");\n _operatorsForAll[sender][operator] = approved;\n\n emit ApprovalForAll(sender, operator, approved);\n }\n\n /**\n * @notice Check if the sender approved the operator\n * @param owner The address of the owner\n * @param operator The address of the operator\n * @return isOperator The status of the approval\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool isOperator) {\n return _operatorsForAll[owner][operator] || _superOperators[operator];\n }\n\n function _burn(\n address from,\n address owner,\n uint256 id\n ) internal {\n require(from == owner, \"not owner\");\n _owners[id] = (_owners[id] & (2**255 - 1)) | (2**160); // record as non owner but keep track of last owner\n _numNFTPerAddress[from]--;\n emit Transfer(from, address(0), id);\n }\n\n /// @notice Burns token `id`.\n /// @param id token which will be burnt.\n function burn(uint256 id) external virtual {\n _burn(msg.sender, _ownerOf(id), id);\n }\n\n /// @notice Burn token`id` from `from`.\n /// @param from address whose token is to be burnt.\n /// @param id token which will be burnt.\n function burnFrom(address from, uint256 id) external virtual {\n require(from != address(0), \"Invalid sender address\");\n (address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(id);\n require(\n msg.sender == from ||\n _metaTransactionContracts[msg.sender] ||\n (operatorEnabled && _operators[id] == msg.sender) ||\n _superOperators[msg.sender] ||\n _operatorsForAll[from][msg.sender],\n \"not authorized to burn\"\n );\n _burn(from, owner, id);\n }\n\n function _checkOnERC721Received(\n address operator,\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) internal returns (bool) {\n bytes4 retval = ERC721TokenReceiver(to).onERC721Received(operator, from, tokenId, _data);\n return (retval == _ERC721_RECEIVED);\n }\n\n function _checkOnERC721BatchReceived(\n address operator,\n address from,\n address to,\n uint256[] memory ids,\n bytes memory _data\n ) internal returns (bool) {\n bytes4 retval = ERC721MandatoryTokenReceiver(to).onERC721BatchReceived(operator, from, ids, _data);\n return (retval == _ERC721_BATCH_RECEIVED);\n }\n}\n"
},
"src/contracts_common/src/Interfaces/ERC721TokenReceiver.sol": {
"content": "/* This Source Code Form is subject to the terms of the Mozilla external\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at http://mozilla.org/MPL/2.0/.\n *\n * This code has not been reviewed.\n * Do not use or deploy this code before reviewing it personally first.\n */\n// solhint-disable-next-line compiler-fixed\npragma solidity ^0.6.0;\n\n\ninterface ERC721TokenReceiver {\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4);\n}\n"
},
"src/contracts_common/src/Interfaces/ERC721Events.sol": {
"content": "pragma solidity ^0.6.0;\n\n\n/**\n * @title ERC721 Non-Fungible Token Standard basic interface\n * @dev see https://eips.ethereum.org/EIPS/eip-721\n */\ninterface ERC721Events {\n event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);\n event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);\n event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);\n}\n"
},
"src/contracts_common/src/Interfaces/ERC721MandatoryTokenReceiver.sol": {
"content": "pragma solidity ^0.6.0;\n\n\n/// @dev Note: The ERC-165 identifier for this interface is 0x5e8bf644.\ninterface ERC721MandatoryTokenReceiver {\n function onERC721BatchReceived(\n address operator,\n address from,\n uint256[] calldata ids,\n bytes calldata data\n ) external returns (bytes4); // needs to return 0x4b808c46\n\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4); // needs to return 0x150b7a02\n\n // needs to implements EIP-165\n // function supportsInterface(bytes4 interfaceId)\n // external\n // view\n // returns (bool);\n}\n"
},
"src/BaseWithStorage/wip/ERC1155BaseToken.sol": {
"content": "pragma solidity 0.6.5;\n\nimport \"../../contracts_common/src/Interfaces/ERC1155.sol\";\nimport \"../../contracts_common/src/Interfaces/ERC1155TokenReceiver.sol\";\n\nimport \"../../contracts_common/src/Libraries/AddressUtils.sol\";\nimport \"../../contracts_common/src/Libraries/ObjectLib32.sol\";\n\nimport \"../../contracts_common/src/BaseWithStorage/MetaTransactionReceiver.sol\";\nimport \"../../contracts_common/src/BaseWithStorage/SuperOperators.sol\";\n\n\ncontract ERC1155BaseToken is MetaTransactionReceiver, SuperOperators, ERC1155 {\n /// @notice Transfers `value` tokens of type `id` from `from` to `to` (with safety call).\n /// @param from address from which tokens are transfered.\n /// @param to address to which the token will be transfered.\n /// @param id the token type transfered.\n /// @param value amount of token transfered.\n /// @param data aditional data accompanying the transfer.\n function safeTransferFrom(\n address from,\n address to,\n uint256 id,\n uint256 value,\n bytes calldata data\n ) external override {\n bool metaTx = _transferFrom(from, to, id, value);\n require(_checkERC1155AndCallSafeTransfer(metaTx ? from : msg.sender, from, to, id, value, data), \"erc1155 transfer rejected\");\n }\n\n /// @notice Transfers `values` tokens of type `ids` from `from` to `to` (with safety call).\n /// @dev call data should be optimized to order ids so packedBalance can be used efficiently.\n /// @param from address from which tokens are transfered.\n /// @param to address to which the token will be transfered.\n /// @param ids ids of each token type transfered.\n /// @param values amount of each token type transfered.\n /// @param data aditional data accompanying the transfer.\n function safeBatchTransferFrom(\n address from,\n address to,\n uint256[] calldata ids,\n uint256[] calldata values,\n bytes calldata data\n ) external override {\n require(ids.length == values.length, \"Inconsistent array length between args\");\n require(to != address(0), \"destination is zero address\");\n require(from != address(0), \"from is zero address\");\n bool metaTx = _metaTransactionContracts[msg.sender];\n require(from == msg.sender || metaTx || _superOperators[msg.sender] || _operatorsForAll[from][msg.sender], \"not authorized\");\n\n _batchTransferFrom(from, to, ids, values);\n emit TransferBatch(metaTx ? from : msg.sender, from, to, ids, values);\n require(_checkERC1155AndCallSafeBatchTransfer(metaTx ? from : msg.sender, from, to, ids, values, data), \"erc1155 transfer rejected\");\n }\n\n /// @notice Get the balance of `owner` for the token type `id`.\n /// @param owner The address of the token holder.\n /// @param id the token type of which to get the balance of.\n /// @return the balance of `owner` for the token type `id`.\n function balanceOf(address owner, uint256 id) public override view returns (uint256) {\n // do not check for existence, balance is zero if never minted\n (uint256 bin, uint256 index) = id.getTokenBinIndex();\n return _packedTokenBalance[owner][bin].getValueInBin(index);\n }\n\n /// @notice Get the balance of `owners` for each token type `ids`.\n /// @param owners the addresses of the token holders queried.\n /// @param ids ids of each token type to query.\n /// @return the balance of each `owners` for each token type `ids`.\n function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) external override view returns (uint256[] memory) {\n require(owners.length == ids.length, \"Inconsistent array length between args\");\n uint256[] memory balances = new uint256[](ids.length);\n for (uint256 i = 0; i < ids.length; i++) {\n balances[i] = balanceOf(owners[i], ids[i]);\n }\n return balances;\n }\n\n /// @notice Enable or disable approval for `operator` to manage all `sender`'s tokens.\n /// @dev used for Meta Transaction (from metaTransactionContract).\n /// @param sender address which grant approval.\n /// @param operator address which will be granted rights to transfer all token owned by `sender`.\n /// @param approved whether to approve or revoke.\n function setApprovalForAllFor(\n address sender,\n address operator,\n bool approved\n ) external {\n require(msg.sender == sender || _metaTransactionContracts[msg.sender] || _superOperators[msg.sender], \"require meta approval\");\n _setApprovalForAll(sender, operator, approved);\n }\n\n /// @notice Enable or disable approval for `operator` to manage all of the caller's tokens.\n /// @param operator address which will be granted rights to transfer all tokens of the caller.\n /// @param approved whether to approve or revoke\n function setApprovalForAll(address operator, bool approved) external override {\n _setApprovalForAll(msg.sender, operator, approved);\n }\n\n /// @notice Queries the approval status of `operator` for owner `owner`.\n /// @param owner the owner of the tokens.\n /// @param operator address of authorized operator.\n /// @return isOperator true if the operator is approved, false if not.\n function isApprovedForAll(address owner, address operator) external override view returns (bool isOperator) {\n require(owner != address(0), \"owner is zero address\");\n require(operator != address(0), \"operator is zero address\");\n return _operatorsForAll[owner][operator] || _superOperators[operator];\n }\n\n /// @notice Query if a contract implements interface `id`.\n /// @param id the interface identifier, as specified in ERC-165.\n /// @return `true` if the contract implements `id`.\n function supportsInterface(bytes4 id) external pure returns (bool) {\n return\n id == ERC165ID || //ERC165\n id == 0xd9b67a26; // ERC1155\n }\n\n function batchBurnFrom(\n address from,\n uint256[] calldata ids,\n uint256[] calldata amounts\n ) external {\n require(from != address(0), \"from is zero address\");\n bool metaTx = _metaTransactionContracts[msg.sender];\n require(from == msg.sender || metaTx || _superOperators[msg.sender] || _operatorsForAll[from][msg.sender], \"not authorized\");\n\n uint256 balFrom;\n\n uint256 lastBin = ~uint256(0);\n for (uint256 i = 0; i < ids.length; i++) {\n if (amounts[i] > 0) {\n (uint256 bin, uint256 index) = ids[i].getTokenBinIndex();\n if (lastBin == ~uint256(0)) {\n lastBin = bin;\n balFrom = ObjectLib32.updateTokenBalance(_packedTokenBalance[from][bin], index, amounts[i], ObjectLib32.Operations.SUB);\n } else {\n if (bin != lastBin) {\n _packedTokenBalance[from][lastBin] = balFrom;\n balFrom = _packedTokenBalance[from][bin];\n lastBin = bin;\n }\n\n balFrom = balFrom.updateTokenBalance(index, amounts[i], ObjectLib32.Operations.SUB);\n }\n }\n }\n if (lastBin != ~uint256(0)) {\n _packedTokenBalance[from][lastBin] = balFrom;\n }\n emit TransferBatch(metaTx ? from : msg.sender, from, address(0), ids, amounts);\n }\n\n /// @notice Burns `amount` tokens of type `id`.\n /// @param id token type which will be burnt.\n /// @param amount amount of token to burn.\n function burn(uint256 id, uint256 amount) external {\n _burn(msg.sender, msg.sender, id, amount);\n }\n\n /// @notice Burns `amount` tokens of type `id` from `from`.\n /// @param from address whose token is to be burnt.\n /// @param id token type which will be burnt.\n /// @param amount amount of token to burn.\n function burnFrom(\n address from,\n uint256 id,\n uint256 amount\n ) external {\n require(from != address(0), \"from is zero address\");\n bool metaTx = _metaTransactionContracts[msg.sender];\n require(from == msg.sender || metaTx || _superOperators[msg.sender] || _operatorsForAll[from][msg.sender], \"not authorized\");\n _burn(metaTx ? from : msg.sender, from, id, amount);\n }\n\n // /////////////////////////////// INTERNAL ////////////////////////////\n function _transferFrom(\n address from,\n address to,\n uint256 id,\n uint256 value\n ) internal returns (bool metaTx) {\n require(to != address(0), \"destination is zero address\");\n require(from != address(0), \"from is zero address\");\n metaTx = _metaTransactionContracts[msg.sender];\n require(from == msg.sender || metaTx || _superOperators[msg.sender] || _operatorsForAll[from][msg.sender], \"Operator not approved\");\n if (value > 0) {\n // if different owners it will fails\n (uint256 bin, uint256 index) = id.getTokenBinIndex();\n _packedTokenBalance[from][bin] = _packedTokenBalance[from][bin].updateTokenBalance(index, value, ObjectLib32.Operations.SUB);\n _packedTokenBalance[to][bin] = _packedTokenBalance[to][bin].updateTokenBalance(index, value, ObjectLib32.Operations.ADD);\n }\n\n emit TransferSingle(metaTx ? from : msg.sender, from, to, id, value);\n }\n\n function _batchTransferFrom(\n address from,\n address to,\n uint256[] memory ids,\n uint256[] memory values\n ) internal {\n uint256 numItems = ids.length;\n uint256 bin;\n uint256 index;\n uint256 balFrom;\n uint256 balTo;\n\n uint256 lastBin = ~uint256(0);\n for (uint256 i = 0; i < numItems; i++) {\n if (values[i] > 0) {\n (bin, index) = ids[i].getTokenBinIndex();\n if (lastBin == ~uint256(0)) {\n lastBin = bin;\n balFrom = ObjectLib32.updateTokenBalance(_packedTokenBalance[from][bin], index, values[i], ObjectLib32.Operations.SUB);\n balTo = ObjectLib32.updateTokenBalance(_packedTokenBalance[to][bin], index, values[i], ObjectLib32.Operations.ADD);\n } else {\n if (bin != lastBin) {\n _packedTokenBalance[from][lastBin] = balFrom;\n _packedTokenBalance[to][lastBin] = balTo;\n balFrom = _packedTokenBalance[from][bin];\n balTo = _packedTokenBalance[to][bin];\n lastBin = bin;\n }\n\n balFrom = balFrom.updateTokenBalance(index, values[i], ObjectLib32.Operations.SUB);\n balTo = balTo.updateTokenBalance(index, values[i], ObjectLib32.Operations.ADD);\n }\n }\n }\n if (lastBin != ~uint256(0)) {\n _packedTokenBalance[from][lastBin] = balFrom;\n _packedTokenBalance[to][lastBin] = balTo;\n }\n }\n\n function _setApprovalForAll(\n address sender,\n address operator,\n bool approved\n ) internal {\n require(sender != address(0), \"sender is zero address\");\n require(sender != operator, \"sender = operator\");\n require(operator != address(0), \"operator is zero address\");\n require(!_superOperators[operator], \"super operator can't have their approvalForAll changed\");\n _operatorsForAll[sender][operator] = approved;\n emit ApprovalForAll(sender, operator, approved);\n }\n\n function _burn(\n address operator,\n address from,\n uint256 id,\n uint256 amount\n ) internal {\n require(amount > 0 && amount <= MAX_SUPPLY, \"invalid amount\");\n (uint256 bin, uint256 index) = (id).getTokenBinIndex();\n _packedTokenBalance[from][bin] = _packedTokenBalance[from][bin].updateTokenBalance(index, amount, ObjectLib32.Operations.SUB);\n emit TransferSingle(operator, from, address(0), id, amount);\n }\n\n function checkIsERC1155Receiver(address _contract) internal view returns (bool) {\n bool success;\n bool result;\n bytes memory call_data = abi.encodeWithSelector(ERC165ID, ERC1155_IS_RECEIVER);\n // solium-disable-next-line security/no-inline-assembly\n assembly {\n let call_ptr := add(0x20, call_data)\n let call_size := mload(call_data)\n let output := mload(0x40) // Find empty storage location using \"free memory pointer\"\n mstore(output, 0x0)\n success := staticcall(10000, _contract, call_ptr, call_size, output, 0x20) // 32 bytes\n result := mload(output)\n }\n // (10000 / 63) \"not enough for supportsInterface(...)\" // consume all gas, so caller can potentially know that there was not enough gas\n assert(gasleft() > 158);\n return success && result;\n }\n\n function _checkERC1155AndCallSafeTransfer(\n address operator,\n address from,\n address to,\n uint256 id,\n uint256 value,\n bytes memory data\n ) internal returns (bool) {\n if (!to.isContract()) {\n return true;\n }\n return ERC1155TokenReceiver(to).onERC1155Received(operator, from, id, value, data) == ERC1155_RECEIVED;\n }\n\n function _checkERC1155AndCallSafeBatchTransfer(\n address operator,\n address from,\n address to,\n uint256[] memory ids,\n uint256[] memory values,\n bytes memory data\n ) internal returns (bool) {\n if (!to.isContract()) {\n return true;\n }\n bytes4 retval = ERC1155TokenReceiver(to).onERC1155BatchReceived(operator, from, ids, values, data);\n return (retval == ERC1155_BATCH_RECEIVED);\n }\n\n // //////////////////////////////// UTILS AND CONSTANTS ///////////////////////////////\n using AddressUtils for address;\n using ObjectLib32 for ObjectLib32.Operations;\n using ObjectLib32 for uint256;\n\n bytes4 internal constant ERC165ID = 0x01ffc9a7;\n bytes4 internal constant ERC1155_IS_RECEIVER = 0x4e2312e0;\n bytes4 internal constant ERC1155_RECEIVED = 0xf23a6e61;\n bytes4 internal constant ERC1155_BATCH_RECEIVED = 0xbc197c81;\n\n uint256 internal constant MAX_SUPPLY = uint256(2)**32 - 1;\n\n // /////////////////////////////////////////// DATA ///////////////////////////////\n\n mapping(address => mapping(uint256 => uint256)) internal _packedTokenBalance;\n mapping(address => mapping(address => bool)) internal _operatorsForAll;\n\n // //////////////////////////////////// CONSTRUCTOR ////////////////////////////////\n constructor(address metaTransactionContract, address admin) internal {\n _setMetaTransactionProcessor(metaTransactionContract, true);\n _admin = admin;\n }\n}\n"
},
"src/contracts_common/src/Interfaces/ERC1155.sol": {
"content": "pragma solidity ^0.6.0;\n\n\n/**\n @title ERC-1155 Multi Token Standard\n @dev See https://eips.ethereum.org/EIPS/eip-1155\n Note: The ERC-165 identifier for this interface is 0xd9b67a26.\n */\ninterface ERC1155 {\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\n\n event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values);\n\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n event URI(string value, uint256 indexed id);\n\n /**\n @notice Transfers `value` amount of an `id` from `from` to `to` (with safety call).\n @dev Caller must be approved to manage the tokens being transferred out of the `from` account (see \"Approval\" section of the standard).\n MUST revert if `to` is the zero address.\n MUST revert if balance of holder for token `id` is lower than the `value` sent.\n MUST revert on any other error.\n MUST emit the `TransferSingle` event to reflect the balance change (see \"Safe Transfer Rules\" section of the standard).\n After the above conditions are met, this function MUST check if `to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `to` and act appropriately (see \"Safe Transfer Rules\" section of the standard).\n @param from Source address\n @param to Target address\n @param id ID of the token type\n @param value Transfer amount\n @param data Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `to`\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 id,\n uint256 value,\n bytes calldata data\n ) external;\n\n /**\n @notice Transfers `values` amount(s) of `ids` from the `from` address to the `to` address specified (with safety call).\n @dev Caller must be approved to manage the tokens being transferred out of the `from` account (see \"Approval\" section of the standard).\n MUST revert if `to` is the zero address.\n MUST revert if length of `ids` is not the same as length of `values`.\n MUST revert if any of the balance(s) of the holder(s) for token(s) in `ids` is lower than the respective amount(s) in `values` sent to the recipient.\n MUST revert on any other error.\n MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \"Safe Transfer Rules\" section of the standard).\n Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\n After the above conditions for the transfer(s) in the batch are met, this function MUST check if `to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `to` and act appropriately (see \"Safe Transfer Rules\" section of the standard).\n @param from Source address\n @param to Target address\n @param ids IDs of each token type (order and length must match _values array)\n @param values Transfer amounts per token type (order and length must match _ids array)\n @param data Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `to`\n */\n function safeBatchTransferFrom(\n address from,\n address to,\n uint256[] calldata ids,\n uint256[] calldata values,\n bytes calldata data\n ) external;\n\n /**\n @notice Get the balance of an account's tokens.\n @param owner The address of the token holder\n @param id ID of the token\n @return The _owner's balance of the token type requested\n */\n function balanceOf(address owner, uint256 id) external view returns (uint256);\n\n /**\n @notice Get the balance of multiple account/token pairs\n @param owners The addresses of the token holders\n @param ids ID of the tokens\n @return The _owner's balance of the token types requested (i.e. balance for each (owner, id) pair)\n */\n function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) external view returns (uint256[] memory);\n\n /**\n @notice Enable or disable approval for a third party (\"operator\") to manage all of the caller's tokens.\n @dev MUST emit the ApprovalForAll event on success.\n @param operator Address to add to the set of authorized operators\n @param approved True if the operator is approved, false to revoke approval\n */\n function setApprovalForAll(address operator, bool approved) external;\n\n /**\n @notice Queries the approval status of an operator for a given owner.\n @param owner The owner of the tokens\n @param operator Address of authorized operator\n @return True if the operator is approved, false if not\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n"
},
"src/contracts_common/src/Interfaces/ERC1155TokenReceiver.sol": {
"content": "pragma solidity ^0.6.0;\n\n\n/// @dev Note: The ERC-165 identifier for this interface is 0x4e2312e0.\ninterface ERC1155TokenReceiver {\n /**\n @notice Handle the receipt of a single ERC1155 token type.\n @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated.\n This function MUST return `bytes4(keccak256(\"onERC1155Received(address,address,uint256,uint256,bytes)\"))` (i.e. 0xf23a6e61) if it accepts the transfer.\n This function MUST revert if it rejects the transfer.\n Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.\n @param operator The address which initiated the transfer (i.e. msg.sender)\n @param from The address which previously owned the token\n @param id The ID of the token being transferred\n @param value The amount of tokens being transferred\n @param data Additional data with no specified format\n @return `bytes4(keccak256(\"onERC1155Received(address,address,uint256,uint256,bytes)\"))`\n */\n function onERC1155Received(\n address operator,\n address from,\n uint256 id,\n uint256 value,\n bytes calldata data\n ) external returns (bytes4);\n\n /**\n @notice Handle the receipt of multiple ERC1155 token types.\n @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated.\n This function MUST return `bytes4(keccak256(\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\"))` (i.e. 0xbc197c81) if it accepts the transfer(s).\n This function MUST revert if it rejects the transfer(s).\n Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.\n @param operator The address which initiated the batch transfer (i.e. msg.sender)\n @param from The address which previously owned the token\n @param ids An array containing ids of each token being transferred (order and length must match _values array)\n @param values An array containing amounts of each token being transferred (order and length must match _ids array)\n @param data Additional data with no specified format\n @return `bytes4(keccak256(\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\"))`\n */\n function onERC1155BatchReceived(\n address operator,\n address from,\n uint256[] calldata ids,\n uint256[] calldata values,\n bytes calldata data\n ) external returns (bytes4);\n}\n"
},
"src/BaseWithStorage/wip/ERC20BaseToken.sol": {
"content": "pragma solidity 0.6.5;\n\nimport \"../../Interfaces/ERC20Extended.sol\";\nimport \"../../contracts_common/src/BaseWithStorage/SuperOperators.sol\";\n\n\ncontract ERC20BaseToken is SuperOperators, ERC20, ERC20Extended {\n bytes32 internal immutable _name; // work only for string that can fit into 32 bytes\n bytes32 internal immutable _symbol; // work only for string that can fit into 32 bytes\n\n uint256 internal _totalSupply;\n mapping(address => uint256) internal _balances;\n mapping(address => mapping(address => uint256)) internal _allowances;\n\n constructor(\n string memory tokenName,\n string memory tokenSymbol,\n address admin\n ) internal {\n require(bytes(tokenName).length > 0, \"INVALID_NAME_REQUIRED\");\n require(bytes(tokenName).length <= 32, \"INVALID_NAME_TOO_LONG\");\n _name = _firstBytes32(bytes(tokenName));\n require(bytes(tokenSymbol).length > 0, \"INVALID_SYMBOL_REQUIRED\");\n require(bytes(tokenSymbol).length <= 32, \"INVALID_SYMBOL_TOO_LONG\");\n _symbol = _firstBytes32(bytes(tokenSymbol));\n\n _admin = admin;\n }\n\n /// @notice A descriptive name for the tokens\n /// @return name of the tokens\n function name() external view returns (string memory) {\n return string(abi.encodePacked(_name));\n }\n\n /// @notice An abbreviated name for the tokens\n /// @return symbol of the tokens\n function symbol() external view returns (string memory) {\n return string(abi.encodePacked(_symbol));\n }\n\n /// @notice Gets the total number of tokens in existence.\n /// @return the total number of tokens in existence.\n function totalSupply() external override view returns (uint256) {\n return _totalSupply;\n }\n\n /// @notice Gets the balance of `owner`.\n /// @param owner The address to query the balance of.\n /// @return The amount owned by `owner`.\n function balanceOf(address owner) external override view returns (uint256) {\n return _balances[owner];\n }\n\n /// @notice gets allowance of `spender` for `owner`'s tokens.\n /// @param owner address whose token is allowed.\n /// @param spender address allowed to transfer.\n /// @return remaining the amount of token `spender` is allowed to transfer on behalf of `owner`.\n function allowance(address owner, address spender) external override view returns (uint256 remaining) {\n return _allowances[owner][spender];\n }\n\n /// @notice returns the number of decimals for that token.\n /// @return the number of decimals.\n function decimals() external virtual pure returns (uint8) {\n return uint8(18);\n }\n\n /// @notice Transfer `amount` tokens to `to`.\n /// @param to the recipient address of the tokens transfered.\n /// @param amount the number of tokens transfered.\n /// @return success true if success.\n function transfer(address to, uint256 amount) external override returns (bool success) {\n _transfer(msg.sender, to, amount);\n return true;\n }\n\n /// @notice Transfer `amount` tokens from `from` to `to`.\n /// @param from whose token it is transferring from.\n /// @param to the recipient address of the tokens transfered.\n /// @param amount the number of tokens transfered.\n /// @return success true if success.\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external override returns (bool success) {\n if (msg.sender != from && !_superOperators[msg.sender]) {\n uint256 currentAllowance = _allowances[from][msg.sender];\n if (currentAllowance != ~uint256(0)) {\n // save gas when allowance is maximal by not reducing it (see https://github.com/ethereum/EIPs/issues/717)\n require(currentAllowance >= amount, \"NOT_AUTHOIZED_ALLOWANCE\");\n _allowances[from][msg.sender] = currentAllowance - amount;\n }\n }\n _transfer(from, to, amount);\n return true;\n }\n\n /// @notice burn `amount` tokens.\n /// @param amount the number of tokens to burn.\n function burn(uint256 amount) external override {\n _burn(msg.sender, amount);\n }\n\n /// @notice burn `amount` tokens from `owner`.\n /// @param from address whose token is to burn.\n /// @param amount the number of token to burn.\n function burnFor(address from, uint256 amount) external override {\n if (msg.sender != from && !_superOperators[msg.sender]) {\n uint256 currentAllowance = _allowances[from][msg.sender];\n if (currentAllowance != ~uint256(0)) {\n require(currentAllowance >= amount, \"NOT_AUTHOIZED_ALLOWANCE\");\n _allowances[from][msg.sender] = currentAllowance - amount;\n }\n }\n _burn(from, amount);\n }\n\n /// @notice approve `spender` to transfer `amount` tokens.\n /// @param spender address to be given rights to transfer.\n /// @param amount the number of tokens allowed.\n /// @return success true if success.\n function approve(address spender, uint256 amount) external override returns (bool success) {\n _approveFor(msg.sender, spender, amount);\n return true;\n }\n\n /// @notice approve `spender` to transfer `amount` tokens from `owner`.\n /// @param owner address whose token is allowed.\n /// @param spender address to be given rights to transfer.\n /// @param amount the number of tokens allowed.\n /// @return success true if success.\n function approveFor(\n address owner,\n address spender,\n uint256 amount\n ) public returns (bool success) {\n require(msg.sender == owner || _superOperators[msg.sender], \"NOT_AUTHORIZED\"); // TODO metatx\n _approveFor(owner, spender, amount);\n return true;\n }\n\n function addAllowanceIfNeeded(\n address owner,\n address spender,\n uint256 amountNeeded\n ) public returns (bool success) {\n require(msg.sender == owner || _superOperators[msg.sender], \"msg.sender != owner && !superOperator\");\n _addAllowanceIfNeeded(owner, spender, amountNeeded);\n return true;\n }\n\n function _addAllowanceIfNeeded(\n address owner,\n address spender,\n uint256 amountNeeded\n ) internal {\n if (amountNeeded > 0 && !isSuperOperator(spender)) {\n uint256 currentAllowance = _allowances[owner][spender];\n if (currentAllowance < amountNeeded) {\n _approveFor(owner, spender, amountNeeded);\n }\n }\n }\n\n function _approveFor(\n address owner,\n address spender,\n uint256 amount\n ) internal {\n require(owner != address(0) && spender != address(0), \"Cannot approve with 0x0\");\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal {\n require(to != address(0), \"Cannot send to 0x0\");\n uint256 currentBalance = _balances[from];\n require(currentBalance >= amount, \"not enough fund\");\n _balances[from] = currentBalance - amount;\n _balances[to] += amount;\n emit Transfer(from, to, amount);\n }\n\n function _mint(address to, uint256 amount) internal {\n require(to != address(0), \"Cannot mint to 0x0\");\n require(amount > 0, \"cannot mint 0 tokens\");\n uint256 currentTotalSupply = _totalSupply;\n uint256 newTotalSupply = currentTotalSupply + amount;\n require(newTotalSupply > currentTotalSupply, \"overflow\");\n _totalSupply = newTotalSupply;\n _balances[to] += amount;\n emit Transfer(address(0), to, amount);\n }\n\n function _burn(address from, uint256 amount) internal {\n require(amount > 0, \"cannot burn 0 tokens\");\n if (msg.sender != from && !_superOperators[msg.sender]) {\n uint256 currentAllowance = _allowances[from][msg.sender];\n require(currentAllowance >= amount, \"Not enough funds allowed\");\n if (currentAllowance != ~uint256(0)) {\n // save gas when allowance is maximal by not reducing it (see https://github.com/ethereum/EIPs/issues/717)\n _allowances[from][msg.sender] = currentAllowance - amount;\n }\n }\n\n uint256 currentBalance = _balances[from];\n require(currentBalance >= amount, \"Not enough funds\");\n _balances[from] = currentBalance - amount;\n _totalSupply -= amount;\n emit Transfer(from, address(0), amount);\n }\n\n function _firstBytes32(bytes memory src) public pure returns (bytes32 output) {\n assembly {\n output := mload(add(src, 32))\n }\n }\n}\n"
},
"src/Interfaces/ERC20Extended.sol": {
"content": "pragma solidity 0.6.5;\n\nimport \"../contracts_common/src/Interfaces/ERC20.sol\";\n\n\ninterface ERC20Extended is ERC20 {\n function burnFor(address from, uint256 amount) external;\n\n function burn(uint256 amount) external;\n}\n"
},
"src/contracts_common/src/Interfaces/ERC20.sol": {
"content": "pragma solidity ^0.6.0;\n\n\n/// @dev see https://eips.ethereum.org/EIPS/eip-20\ninterface ERC20 {\n /// @notice emitted when tokens are transfered from one address to another.\n /// @param from address from which the token are transfered from (zero means tokens are minted).\n /// @param to destination address which the token are transfered to (zero means tokens are burnt).\n /// @param value amount of tokens transferred.\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// @notice emitted when owner grant transfer rights to another address\n /// @param owner address allowing its token to be transferred.\n /// @param spender address allowed to spend on behalf of `owner`\n /// @param value amount of tokens allowed.\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// @notice return the current total amount of tokens owned by all holders.\n /// @return supply total number of tokens held.\n function totalSupply() external view returns (uint256 supply);\n\n /// @notice return the number of tokens held by a particular address.\n /// @param who address being queried.\n /// @return balance number of token held by that address.\n function balanceOf(address who) external view returns (uint256 balance);\n\n /// @notice transfer tokens to a specific address.\n /// @param to destination address receiving the tokens.\n /// @param value number of tokens to transfer.\n /// @return success whether the transfer succeeded.\n function transfer(address to, uint256 value) external returns (bool success);\n\n /// @notice transfer tokens from one address to another.\n /// @param from address tokens will be sent from.\n /// @param to destination address receiving the tokens.\n /// @param value number of tokens to transfer.\n /// @return success whether the transfer succeeded.\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external returns (bool success);\n\n /// @notice approve an address to spend on your behalf.\n /// @param spender address entitled to transfer on your behalf.\n /// @param value amount allowed to be transfered.\n /// @param success whether the approval succeeded.\n function approve(address spender, uint256 value) external returns (bool success);\n\n /// @notice return the current allowance for a particular owner/spender pair.\n /// @param owner address allowing spender.\n /// @param spender address allowed to spend.\n /// @return amount number of tokens `spender` can spend on behalf of `owner`.\n function allowance(address owner, address spender) external view returns (uint256 amount);\n}\n"
},
"src/BaseWithStorage/wip/MintableERC1155Token.sol": {
"content": "pragma solidity 0.6.5;\npragma experimental ABIEncoderV2;\n\nimport \"./ERC1155BaseToken.sol\";\n\n\ncontract MintableERC1155Token is ERC1155BaseToken {\n event Minter(address minter, bool enabled);\n\n /// @notice Enable or disable the ability of `minter` to mint tokens\n /// @param minter address that will be given/removed minter right.\n /// @param enabled set whether the minter is enabled or disabled.\n function setMinter(address minter, bool enabled) external {\n require(msg.sender == _admin, \"only admin is allowed to add minters\");\n _setMinter(minter, enabled);\n }\n\n /// @notice check whether address `who` is given minter rights.\n /// @param who The address to query.\n /// @return whether the address has minter rights.\n function isMinter(address who) public view returns (bool) {\n return _minters[who];\n }\n\n function mint(\n address to,\n uint256 id,\n uint256 amount\n ) external {\n require(_minters[msg.sender], \"only minter allowed to mint\");\n (uint256 bin, uint256 index) = id.getTokenBinIndex();\n _packedTokenBalance[to][bin] = ObjectLib32.updateTokenBalance(_packedTokenBalance[to][bin], index, amount, ObjectLib32.Operations.ADD);\n emit TransferSingle(msg.sender, address(0), to, id, amount);\n }\n\n function batchMint(\n address to,\n uint256[] calldata ids,\n uint256[] calldata amounts\n ) external {\n require(_minters[msg.sender], \"only minter allowed to mint\");\n require(to != address(0), \"to is zero address\");\n\n uint256 balTo;\n\n uint256 lastBin = ~uint256(0);\n for (uint256 i = 0; i < ids.length; i++) {\n if (amounts[i] > 0) {\n (uint256 bin, uint256 index) = ids[i].getTokenBinIndex();\n if (lastBin == ~uint256(0)) {\n lastBin = bin;\n balTo = ObjectLib32.updateTokenBalance(_packedTokenBalance[to][bin], index, amounts[i], ObjectLib32.Operations.ADD);\n } else {\n if (bin != lastBin) {\n _packedTokenBalance[to][lastBin] = balTo;\n balTo = _packedTokenBalance[to][bin];\n lastBin = bin;\n }\n\n balTo = balTo.updateTokenBalance(index, amounts[i], ObjectLib32.Operations.ADD);\n }\n }\n }\n if (lastBin != ~uint256(0)) {\n _packedTokenBalance[to][lastBin] = balTo;\n }\n emit TransferBatch(msg.sender, address(0), to, ids, amounts);\n }\n\n // /////////////////////// INTERNAL\n function _setMinter(address minter, bool enabled) internal {\n _minters[minter] = enabled;\n emit Minter(minter, enabled);\n }\n\n // ////////////////////////\n mapping(address => bool) internal _minters;\n\n // ////////////////////////\n constructor(\n address metaTransactionContract,\n address admin,\n address initialMinter\n ) internal ERC1155BaseToken(metaTransactionContract, admin) {\n _setMinter(initialMinter, true);\n }\n}\n"
},
"src/Catalyst/CatalystDataBase.sol": {
"content": "pragma solidity 0.6.5;\npragma experimental ABIEncoderV2;\n\nimport \"./CatalystValue.sol\";\n\n\ncontract CatalystDataBase is CatalystValue {\n event CatalystConfiguration(uint256 indexed id, uint16 minQuantity, uint16 maxQuantity, uint256 sandMintingFee, uint256 sandUpdateFee);\n\n function _setMintData(uint256 id, MintData memory data) internal {\n _data[id] = data;\n _emitConfiguration(id, data.minQuantity, data.maxQuantity, data.sandMintingFee, data.sandUpdateFee);\n }\n\n function _setValueOverride(uint256 id, CatalystValue valueOverride) internal {\n _valueOverrides[id] = valueOverride;\n }\n\n function _setConfiguration(\n uint256 id,\n uint16 minQuantity,\n uint16 maxQuantity,\n uint256 sandMintingFee,\n uint256 sandUpdateFee\n ) internal {\n _data[id].minQuantity = minQuantity;\n _data[id].maxQuantity = maxQuantity;\n _data[id].sandMintingFee = uint88(sandMintingFee);\n _data[id].sandUpdateFee = uint88(sandUpdateFee);\n _emitConfiguration(id, minQuantity, maxQuantity, sandMintingFee, sandUpdateFee);\n }\n\n function _emitConfiguration(\n uint256 id,\n uint16 minQuantity,\n uint16 maxQuantity,\n uint256 sandMintingFee,\n uint256 sandUpdateFee\n ) internal {\n emit CatalystConfiguration(id, minQuantity, maxQuantity, sandMintingFee, sandUpdateFee);\n }\n\n ///@dev compute a random value between min to 25.\n //. example: 1-25, 6-25, 11-25, 16-25\n function _computeValue(\n uint256 seed,\n uint256 gemId,\n bytes32 blockHash,\n uint256 slotIndex,\n uint32 min\n ) internal pure returns (uint32) {\n return min + uint16(uint256(keccak256(abi.encodePacked(gemId, seed, blockHash, slotIndex))) % (26 - min));\n }\n\n function getValues(\n uint256 catalystId,\n uint256 seed,\n GemEvent[] calldata events,\n uint32 totalNumberOfGemTypes\n ) external override view returns (uint32[] memory values) {\n CatalystValue valueOverride = _valueOverrides[catalystId];\n if (address(valueOverride) != address(0)) {\n return valueOverride.getValues(catalystId, seed, events, totalNumberOfGemTypes);\n }\n values = new uint32[](totalNumberOfGemTypes);\n\n uint32 numGems;\n for (uint256 i = 0; i < events.length; i++) {\n numGems += uint32(events[i].gemIds.length);\n }\n require(numGems <= MAX_UINT32, \"TOO_MANY_GEMS\");\n uint32 minValue = (numGems - 1) * 5 + 1;\n\n uint256 numGemsSoFar = 0;\n for (uint256 i = 0; i < events.length; i++) {\n numGemsSoFar += events[i].gemIds.length;\n for (uint256 j = 0; j < events[i].gemIds.length; j++) {\n uint256 gemId = events[i].gemIds[j];\n uint256 slotIndex = numGemsSoFar - events[i].gemIds.length + j;\n if (values[gemId] == 0) {\n // first gem : value = roll between ((numGemsSoFar-1)*5+1) and 25\n values[gemId] = _computeValue(seed, gemId, events[i].blockHash, slotIndex, (uint32(numGemsSoFar) - 1) * 5 + 1);\n // bump previous values:\n if (values[gemId] < minValue) {\n values[gemId] = minValue;\n }\n } else {\n // further gem, previous roll are overriden with 25 and new roll between 1 and 25\n uint32 newRoll = _computeValue(seed, gemId, events[i].blockHash, slotIndex, 1);\n values[gemId] = (((values[gemId] - 1) / 25) + 1) * 25 + newRoll;\n }\n }\n }\n }\n\n function getMintData(uint256 catalystId)\n external\n view\n returns (\n uint16 maxGems,\n uint16 minQuantity,\n uint16 maxQuantity,\n uint256 sandMintingFee,\n uint256 sandUpdateFee\n )\n {\n maxGems = _data[catalystId].maxGems;\n minQuantity = _data[catalystId].minQuantity;\n maxQuantity = _data[catalystId].maxQuantity;\n sandMintingFee = _data[catalystId].sandMintingFee;\n sandUpdateFee = _data[catalystId].sandUpdateFee;\n }\n\n struct MintData {\n uint88 sandMintingFee;\n uint88 sandUpdateFee;\n uint16 minQuantity;\n uint16 maxQuantity;\n uint16 maxGems;\n }\n\n uint32 internal constant MAX_UINT32 = 2**32 - 1;\n\n mapping(uint256 => MintData) internal _data;\n mapping(uint256 => CatalystValue) internal _valueOverrides;\n}\n"
},
"src/Catalyst/CatalystValue.sol": {
"content": "pragma solidity 0.6.5;\npragma experimental ABIEncoderV2;\n\n\ninterface CatalystValue {\n struct GemEvent {\n uint256[] gemIds;\n bytes32 blockHash;\n }\n\n function getValues(\n uint256 catalystId,\n uint256 seed,\n GemEvent[] calldata events,\n uint32 totalNumberOfGemTypes\n ) external view returns (uint32[] memory values);\n}\n"
},
"src/Catalyst/CatalystToken.sol": {
"content": "pragma solidity 0.6.5;\npragma experimental ABIEncoderV2;\n\n\ninterface CatalystToken {\n function getMintData(uint256 catalystId)\n external\n view\n returns (\n uint16 maxGems,\n uint16 minQuantity,\n uint16 maxQuantity,\n uint256 sandMintingFee,\n uint256 sandUpdateFee\n );\n\n function batchBurnFrom(\n address from,\n uint256[] calldata ids,\n uint256[] calldata amounts\n ) external;\n\n function burnFrom(\n address from,\n uint256 id,\n uint256 amount\n ) external;\n}\n"
},
"src/Catalyst/ERC20GroupCatalyst.sol": {
"content": "pragma solidity 0.6.5;\npragma experimental ABIEncoderV2;\n\nimport \"../BaseWithStorage/ERC20Group.sol\";\nimport \"./CatalystDataBase.sol\";\nimport \"../BaseWithStorage/ERC20SubToken.sol\";\nimport \"./CatalystValue.sol\";\n\n\ncontract ERC20GroupCatalyst is CatalystDataBase, ERC20Group {\n /// @dev add Catalyst, if one of the catalyst to be added in the batch need to have a value override, all catalyst added in that batch need to have override\n /// if this is not desired, they can be added in a separated batch\n /// if no override are needed, the valueOverrides can be left emopty\n function addCatalysts(\n ERC20SubToken[] memory catalysts,\n MintData[] memory mintData,\n CatalystValue[] memory valueOverrides\n ) public {\n require(msg.sender == _admin, \"NOT_AUTHORIZED_ADMIN\");\n require(catalysts.length == mintData.length, \"INVALID_INCONSISTENT_LENGTH\");\n for (uint256 i = 0; i < mintData.length; i++) {\n uint256 id = _addSubToken(catalysts[i]);\n _setMintData(id, mintData[i]);\n if (valueOverrides.length > i) {\n _setValueOverride(id, valueOverrides[i]);\n }\n }\n }\n\n function addCatalyst(\n ERC20SubToken catalyst,\n MintData memory mintData,\n CatalystValue valueOverride\n ) public {\n require(msg.sender == _admin, \"NOT_AUTHORIZED_ADMIN\");\n uint256 id = _addSubToken(catalyst);\n _setMintData(id, mintData);\n _setValueOverride(id, valueOverride);\n }\n\n function setConfiguration(\n uint256 id,\n uint16 minQuantity,\n uint16 maxQuantity,\n uint256 sandMintingFee,\n uint256 sandUpdateFee\n ) external {\n // CatalystMinter hardcode the value for efficiency purpose, so a change here would require a new deployment of CatalystMinter\n require(msg.sender == _admin, \"NOT_AUTHORIZED_ADMIN\");\n _setConfiguration(id, minQuantity, maxQuantity, sandMintingFee, sandUpdateFee);\n }\n\n constructor(\n address metaTransactionContract,\n address admin,\n address initialMinter\n ) public ERC20Group(metaTransactionContract, admin, initialMinter) {}\n}\n"
},
"src/Catalyst/ERC20GroupGem.sol": {
"content": "pragma solidity 0.6.5;\npragma experimental ABIEncoderV2;\n\nimport \"../BaseWithStorage/ERC20Group.sol\";\n\n\ncontract ERC20GroupGem is ERC20Group {\n function addGems(ERC20SubToken[] calldata catalysts) external {\n require(msg.sender == _admin, \"NOT_AUTHORIZED_ADMIN\");\n for (uint256 i = 0; i < catalysts.length; i++) {\n _addSubToken(catalysts[i]);\n }\n }\n\n constructor(\n address metaTransactionContract,\n address admin,\n address initialMinter\n ) public ERC20Group(metaTransactionContract, admin, initialMinter) {}\n}\n"
},
"src/Catalyst/GemToken.sol": {
"content": "pragma solidity 0.6.5;\n\n\ninterface GemToken {\n function batchBurnFrom(\n address from,\n uint256[] calldata ids,\n uint256[] calldata amounts\n ) external;\n}\n"
},
"src/Catalyst/wip/ERC1155Catalyst.sol": {
"content": "pragma solidity 0.6.5;\npragma experimental ABIEncoderV2;\n\nimport \"../../BaseWithStorage/wip/MintableERC1155Token.sol\";\nimport \"../CatalystDataBase.sol\";\n\n\ncontract ERC1155Catalyst is CatalystDataBase, MintableERC1155Token {\n function addCatalysts(string[] memory names, MintData[] memory data) public {\n require(msg.sender == _admin, \"NOT_AUTHORIZED_ADMIN\");\n require(names.length == data.length, \"INVALID_INCONSISTENT_LENGTH\");\n uint256 count = _count;\n for (uint256 i = 0; i < data.length; i++) {\n _names[count + i] = names[i];\n _data[count + i] = data[i];\n }\n _count = count + data.length;\n // TODO event\n }\n\n function addCatalyst(string memory name, MintData memory data) public {\n require(msg.sender == _admin, \"NOT_AUTHORIZED_ADMIN\");\n uint256 count = _count;\n _names[count] = name;\n _data[count] = data;\n _count++;\n // TODO event\n }\n\n // TODO metadata + EIP-165\n\n // ///////////////////////// STORAGE /////////////////////////////////\n uint256 _count;\n mapping(uint256 => string) _names;\n\n // ///////////////////////////////////////////////////////////////////\n constructor(\n address metaTransactionContract,\n address admin,\n address initialMinter\n ) public MintableERC1155Token(metaTransactionContract, admin, initialMinter) {}\n}\n"
},
"src/Catalyst/wip/ERC1155Gem.sol": {
"content": "pragma solidity 0.6.5;\npragma experimental ABIEncoderV2;\n\nimport \"../../BaseWithStorage/wip/MintableERC1155Token.sol\";\n\n\ncontract ERC1155Gem is MintableERC1155Token {\n function addGems(string[] memory names) public {\n require(msg.sender == _admin, \"NOT_AUTHORIZED_ADMIN\");\n _addGems(names);\n }\n\n // TODO metadata + EIP-165\n\n // ///////////////////\n function _addGems(string[] memory names) internal {\n uint256 count = _count;\n for (uint256 i = 0; i < names.length; i++) {\n _names[count + i] = names[i];\n }\n _count = count + names.length;\n // TODO event ?\n }\n\n // /////////////////////\n uint256 _count;\n mapping(uint256 => string) _names;\n\n // ////////////////////////\n constructor(\n address metaTransactionContract,\n address admin,\n address initialMinter,\n string[] memory initialGems\n ) public MintableERC1155Token(metaTransactionContract, admin, initialMinter) {\n _addGems(initialGems);\n }\n}\n"
},
"src/CatalystMinter.sol": {
"content": "pragma solidity 0.6.5;\npragma experimental ABIEncoderV2;\n\nimport \"./Interfaces/AssetToken.sol\";\nimport \"./contracts_common/src/Interfaces/ERC20.sol\";\nimport \"./Interfaces/ERC20Extended.sol\";\nimport \"./contracts_common/src/BaseWithStorage/MetaTransactionReceiver.sol\";\nimport \"./contracts_common/src/Libraries/SafeMathWithRequire.sol\";\nimport \"./Catalyst/GemToken.sol\";\nimport \"./Catalyst/CatalystToken.sol\";\nimport \"./CatalystRegistry.sol\";\nimport \"./BaseWithStorage/ERC20Group.sol\";\n\n\n/// @notice Gateway to mint Asset with Catalyst, Gems and Sand\ncontract CatalystMinter is MetaTransactionReceiver {\n /// @dev emitted when fee collector (that receive the sand fee) get changed\n /// @param newCollector address of the new collector, address(0) means the fee will be burned\n event FeeCollector(address newCollector);\n\n function setFeeCollector(address newCollector) external {\n require(msg.sender == _admin, \"NOT_AUTHORIZED_ADMIN\");\n _setFeeCollector(newCollector);\n }\n\n event GemAdditionFee(uint256 newFee);\n\n function setGemAdditionFee(uint256 newFee) external {\n require(msg.sender == _admin, \"NOT_AUTHORIZED_ADMIN\");\n _setGemAdditionFee(newFee);\n }\n\n /// @notice mint one Asset token.\n /// @param from address creating the Asset, need to be the tx sender or meta tx signer.\n /// @param packId unused packId that will let you predict the resulting tokenId.\n /// @param metadataHash cidv1 ipfs hash of the folder where 0.json file contains the metadata.\n /// @param catalystId address of the Catalyst ERC20 token to burn.\n /// @param gemIds list of gem ids to burn in the catalyst.\n /// @param quantity asset supply to mint\n /// @param to destination address receiving the minted tokens.\n /// @param data extra data.\n function mint(\n address from,\n uint40 packId,\n bytes32 metadataHash,\n uint256 catalystId,\n uint256[] calldata gemIds,\n uint256 quantity,\n address to,\n bytes calldata data\n ) external returns (uint256) {\n _checkAuthorization(from, to);\n _burnCatalyst(from, catalystId);\n uint16 maxGems = _checkQuantityAndBurnSandAndGems(from, catalystId, gemIds, quantity);\n uint256 id = _asset.mint(from, packId, metadataHash, quantity, 0, to, data);\n _catalystRegistry.setCatalyst(id, catalystId, maxGems, gemIds);\n return id;\n }\n\n /// @notice associate a catalyst to a fungible Asset token by extracting it as ERC721 first.\n /// @param from address from which the Asset token belongs to.\n /// @param assetId tokenId of the Asset being extracted.\n /// @param catalystId address of the catalyst token to use and burn.\n /// @param gemIds list of gems to socket into the catalyst (burned).\n /// @param to destination address receiving the extracted and upgraded ERC721 Asset token.\n function extractAndChangeCatalyst(\n address from,\n uint256 assetId,\n uint256 catalystId,\n uint256[] calldata gemIds,\n address to\n ) external returns (uint256 tokenId) {\n _checkAuthorization(from, to);\n tokenId = _asset.extractERC721From(from, assetId, from);\n _changeCatalyst(from, tokenId, catalystId, gemIds, to);\n }\n\n /// @notice associate a new catalyst to a non-fungible Asset token.\n /// @param from address from which the Asset token belongs to.\n /// @param assetId tokenId of the Asset being updated.\n /// @param catalystId address of the catalyst token to use and burn.\n /// @param gemIds list of gems to socket into the catalyst (burned).\n /// @param to destination address receiving the Asset token.\n function changeCatalyst(\n address from,\n uint256 assetId,\n uint256 catalystId,\n uint256[] calldata gemIds,\n address to\n ) external returns (uint256 tokenId) {\n _checkAuthorization(from, to);\n _changeCatalyst(from, assetId, catalystId, gemIds, to);\n return assetId;\n }\n\n /// @notice add gems to a fungible Asset token by extracting it as ERC721 first.\n /// @param from address from which the Asset token belongs to.\n /// @param assetId tokenId of the Asset being extracted.\n /// @param gemIds list of gems to socket into the existing catalyst (burned).\n /// @param to destination address receiving the extracted and upgraded ERC721 Asset token.\n function extractAndAddGems(\n address from,\n uint256 assetId,\n uint256[] calldata gemIds,\n address to\n ) external returns (uint256 tokenId) {\n _checkAuthorization(from, to);\n tokenId = _asset.extractERC721From(from, assetId, from);\n _addGems(from, tokenId, gemIds, to);\n }\n\n /// @notice add gems to a non-fungible Asset token.\n /// @param from address from which the Asset token belongs to.\n /// @param assetId tokenId of the Asset to which the gems will be added to.\n /// @param gemIds list of gems to socket into the existing catalyst (burned).\n /// @param to destination address receiving the extracted and upgraded ERC721 Asset token.\n function addGems(\n address from,\n uint256 assetId,\n uint256[] calldata gemIds,\n address to\n ) external {\n _checkAuthorization(from, to);\n _addGems(from, assetId, gemIds, to);\n }\n\n struct AssetData {\n uint256[] gemIds;\n uint256 quantity;\n uint256 catalystId;\n }\n\n /// @notice mint multiple Asset tokens.\n /// @param from address creating the Asset, need to be the tx sender or meta tx signer.\n /// @param packId unused packId that will let you predict the resulting tokenId.\n /// @param metadataHash cidv1 ipfs hash of the folder where 0.json file contains the metadata.\n /// @param gemsQuantities quantities of gems to be used for each id in order\n /// @param catalystsQuantities quantities of catalyst to be used for each id in order\n /// @param assets contains the data to associate catalyst and gems to the assets.\n /// @param to destination address receiving the minted tokens.\n /// @param data extra data.\n function mintMultiple(\n address from,\n uint40 packId,\n bytes32 metadataHash,\n uint256[] memory gemsQuantities,\n uint256[] memory catalystsQuantities,\n AssetData[] memory assets,\n address to,\n bytes memory data\n ) public returns (uint256[] memory ids) {\n require(assets.length != 0, \"INVALID_0_ASSETS\");\n _checkAuthorization(from, to);\n return _mintMultiple(from, packId, metadataHash, gemsQuantities, catalystsQuantities, assets, to, data);\n }\n\n // //////////////////// INTERNALS ////////////////////\n\n function _checkQuantityAndBurnSandAndGems(\n address from,\n uint256 catalystId,\n uint256[] memory gemIds,\n uint256 quantity\n ) internal returns (uint16) {\n (uint16 maxGems, uint16 minQuantity, uint16 maxQuantity, uint256 sandMintingFee, ) = _getMintData(catalystId);\n require(minQuantity <= quantity && quantity <= maxQuantity, \"INVALID_QUANTITY\");\n require(gemIds.length <= maxGems, \"INVALID_GEMS_TOO_MANY\");\n _burnSingleGems(from, gemIds);\n _chargeSand(from, quantity.mul(sandMintingFee));\n return maxGems;\n }\n\n function _mintMultiple(\n address from,\n uint40 packId,\n bytes32 metadataHash,\n uint256[] memory gemsQuantities,\n uint256[] memory catalystsQuantities,\n AssetData[] memory assets,\n address to,\n bytes memory data\n ) internal returns (uint256[] memory) {\n (uint256 totalSandFee, uint256[] memory supplies, uint16[] memory maxGemsList) = _handleMultipleCatalysts(\n from,\n gemsQuantities,\n catalystsQuantities,\n assets\n );\n\n _chargeSand(from, totalSandFee);\n\n return _mintAssets(from, packId, metadataHash, assets, supplies, maxGemsList, to, data);\n }\n\n function _chargeSand(address from, uint256 sandFee) internal {\n address feeCollector = _feeCollector;\n if (feeCollector != address(0) && sandFee != 0) {\n if (feeCollector == address(BURN_ADDRESS)) {\n // special address for burn\n _sand.burnFor(from, sandFee);\n } else {\n _sand.transferFrom(from, _feeCollector, sandFee);\n }\n }\n }\n\n function _extractMintData(uint256 data)\n internal\n pure\n returns (\n uint16 maxGems,\n uint16 minQuantity,\n uint16 maxQuantity,\n uint256 sandMintingFee,\n uint256 sandUpdateFee\n )\n {\n maxGems = uint16(data >> 240);\n minQuantity = uint16((data >> 224) % 2**16);\n maxQuantity = uint16((data >> 208) % 2**16);\n sandMintingFee = uint256((data >> 120) % 2**88);\n sandUpdateFee = uint256(data % 2**88);\n }\n\n function _getMintData(uint256 catalystId)\n internal\n view\n returns (\n uint16,\n uint16,\n uint16,\n uint256,\n uint256\n )\n {\n if (catalystId == 0) {\n return _extractMintData(_common_mint_data);\n } else if (catalystId == 1) {\n return _extractMintData(_rare_mint_data);\n } else if (catalystId == 2) {\n return _extractMintData(_epic_mint_data);\n } else if (catalystId == 3) {\n return _extractMintData(_legendary_mint_data);\n }\n return _catalysts.getMintData(catalystId);\n }\n\n function _handleMultipleCatalysts(\n address from,\n uint256[] memory gemsQuantities,\n uint256[] memory catalystsQuantities,\n AssetData[] memory assets\n )\n internal\n returns (\n uint256 totalSandFee,\n uint256[] memory supplies,\n uint16[] memory maxGemsList\n )\n {\n _burnCatalysts(from, catalystsQuantities);\n _burnGems(from, gemsQuantities);\n\n supplies = new uint256[](assets.length);\n maxGemsList = new uint16[](assets.length);\n\n for (uint256 i = 0; i < assets.length; i++) {\n require(catalystsQuantities[assets[i].catalystId] != 0, \"INVALID_CATALYST_NOT_ENOUGH\");\n catalystsQuantities[assets[i].catalystId]--;\n gemsQuantities = _checkGemsQuantities(gemsQuantities, assets[i].gemIds);\n (uint16 maxGems, uint16 minQuantity, uint16 maxQuantity, uint256 sandMintingFee, ) = _getMintData(assets[i].catalystId);\n require(minQuantity <= assets[i].quantity && assets[i].quantity <= maxQuantity, \"INVALID_QUANTITY\");\n require(assets[i].gemIds.length <= maxGems, \"INVALID_GEMS_TOO_MANY\");\n maxGemsList[i] = maxGems;\n supplies[i] = assets[i].quantity;\n totalSandFee = totalSandFee.add(sandMintingFee.mul(assets[i].quantity));\n }\n }\n\n function _checkGemsQuantities(uint256[] memory gemsQuantities, uint256[] memory gemIds) internal pure returns (uint256[] memory) {\n for (uint256 i = 0; i < gemIds.length; i++) {\n require(gemsQuantities[gemIds[i]] != 0, \"INVALID_GEMS_NOT_ENOUGH\");\n gemsQuantities[gemIds[i]]--;\n }\n return gemsQuantities;\n }\n\n function _burnCatalysts(address from, uint256[] memory catalystsQuantities) internal {\n uint256[] memory ids = new uint256[](catalystsQuantities.length);\n for (uint256 i = 0; i < ids.length; i++) {\n ids[i] = i;\n }\n _catalysts.batchBurnFrom(from, ids, catalystsQuantities);\n }\n\n function _burnGems(address from, uint256[] memory gemsQuantities) internal {\n uint256[] memory ids = new uint256[](gemsQuantities.length);\n for (uint256 i = 0; i < ids.length; i++) {\n ids[i] = i;\n }\n _gems.batchBurnFrom(from, ids, gemsQuantities);\n }\n\n function _mintAssets(\n address from,\n uint40 packId,\n bytes32 metadataHash,\n AssetData[] memory assets,\n uint256[] memory supplies,\n uint16[] memory maxGemsList,\n address to,\n bytes memory data\n ) internal returns (uint256[] memory tokenIds) {\n tokenIds = _asset.mintMultiple(from, packId, metadataHash, supplies, \"\", to, data);\n for (uint256 i = 0; i < tokenIds.length; i++) {\n _catalystRegistry.setCatalyst(tokenIds[i], assets[i].catalystId, maxGemsList[i], assets[i].gemIds);\n }\n }\n\n function _changeCatalyst(\n address from,\n uint256 assetId,\n uint256 catalystId,\n uint256[] memory gemIds,\n address to\n ) internal {\n require(assetId & IS_NFT != 0, \"INVALID_NOT_NFT\"); // Asset (ERC1155ERC721.sol) ensure NFT will return true here and non-NFT will return false\n _burnCatalyst(from, catalystId);\n (uint16 maxGems, , , , uint256 sandUpdateFee) = _getMintData(catalystId);\n require(gemIds.length <= maxGems, \"INVALID_GEMS_TOO_MANY\");\n _burnGems(from, gemIds);\n _chargeSand(from, sandUpdateFee);\n\n _catalystRegistry.setCatalyst(assetId, catalystId, maxGems, gemIds);\n\n _transfer(from, to, assetId);\n }\n\n function _addGems(\n address from,\n uint256 assetId,\n uint256[] memory gemIds,\n address to\n ) internal {\n require(assetId & IS_NFT != 0, \"INVALID_NOT_NFT\"); // Asset (ERC1155ERC721.sol) ensure NFT will return true here and non-NFT will return false\n _catalystRegistry.addGems(assetId, gemIds);\n _chargeSand(from, gemIds.length.mul(_gemAdditionFee));\n _transfer(from, to, assetId);\n }\n\n function _transfer(\n address from,\n address to,\n uint256 assetId\n ) internal {\n if (from != to) {\n _asset.safeTransferFrom(from, to, assetId);\n }\n }\n\n function _checkAuthorization(address from, address to) internal view {\n require(to != address(0), \"INVALID_TO_ZERO_ADDRESS\");\n require(from == msg.sender || _metaTransactionContracts[msg.sender], \"NOT_SENDER\");\n }\n\n function _burnSingleGems(address from, uint256[] memory gemIds) internal {\n uint256[] memory amounts = new uint256[](gemIds.length);\n for (uint256 i = 0; i < gemIds.length; i++) {\n amounts[i] = 1;\n }\n _gems.batchBurnFrom(from, gemIds, amounts);\n }\n\n function _burnCatalyst(address from, uint256 catalystId) internal {\n _catalysts.burnFrom(from, catalystId, 1);\n }\n\n function _setFeeCollector(address newCollector) internal {\n _feeCollector = newCollector;\n emit FeeCollector(newCollector);\n }\n\n function _setGemAdditionFee(uint256 newFee) internal {\n _gemAdditionFee = newFee;\n emit GemAdditionFee(newFee);\n }\n\n // /////////////////// UTILITIES /////////////////////\n using SafeMathWithRequire for uint256;\n\n // //////////////////////// DATA /////////////////////\n uint256 private constant IS_NFT = 0x0000000000000000000000000000000000000000800000000000000000000000;\n address private constant BURN_ADDRESS = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF;\n\n ERC20Extended internal immutable _sand;\n AssetToken internal immutable _asset;\n GemToken internal immutable _gems;\n CatalystToken internal immutable _catalysts;\n CatalystRegistry internal immutable _catalystRegistry;\n address internal _feeCollector;\n\n uint256 internal immutable _common_mint_data;\n uint256 internal immutable _rare_mint_data;\n uint256 internal immutable _epic_mint_data;\n uint256 internal immutable _legendary_mint_data;\n\n uint256 internal _gemAdditionFee;\n\n // /////////////////// CONSTRUCTOR ////////////////////\n constructor(\n CatalystRegistry catalystRegistry,\n ERC20Extended sand,\n AssetToken asset,\n GemToken gems,\n address metaTx,\n address admin,\n address feeCollector,\n uint256 gemAdditionFee,\n CatalystToken catalysts,\n uint256[4] memory bakedInMintdata\n ) public {\n _catalystRegistry = catalystRegistry;\n _sand = sand;\n _asset = asset;\n _gems = gems;\n _catalysts = catalysts;\n _admin = admin;\n _setGemAdditionFee(gemAdditionFee);\n _setFeeCollector(feeCollector);\n _setMetaTransactionProcessor(metaTx, true);\n _common_mint_data = bakedInMintdata[0];\n _rare_mint_data = bakedInMintdata[1];\n _epic_mint_data = bakedInMintdata[2];\n _legendary_mint_data = bakedInMintdata[3];\n }\n}\n"
},
"src/Interfaces/AssetToken.sol": {
"content": "pragma solidity 0.6.5;\n\n\ninterface AssetToken {\n function mint(\n address creator,\n uint40 packId,\n bytes32 hash,\n uint256 supply,\n uint8 rarity,\n address owner,\n bytes calldata data\n ) external returns (uint256 id);\n\n function mintMultiple(\n address creator,\n uint40 packId,\n bytes32 hash,\n uint256[] calldata supplies,\n bytes calldata rarityPack,\n address owner,\n bytes calldata data\n ) external returns (uint256[] memory ids);\n\n // fails on non-NFT or nft who do not have collection (was a mistake)\n function collectionOf(uint256 id) external view returns (uint256);\n\n // return true for Non-NFT ERC1155 tokens which exists\n function isCollection(uint256 id) external view returns (bool);\n\n function collectionIndexOf(uint256 id) external view returns (uint256);\n\n function extractERC721From(\n address sender,\n uint256 id,\n address to\n ) external returns (uint256 newId);\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id\n ) external;\n}\n"
},
"src/CatalystRegistry.sol": {
"content": "pragma solidity 0.6.5;\npragma experimental ABIEncoderV2;\n\nimport \"./Interfaces/AssetToken.sol\";\nimport \"./contracts_common/src/BaseWithStorage/Admin.sol\";\nimport \"./Catalyst/CatalystValue.sol\";\n\n\ncontract CatalystRegistry is Admin, CatalystValue {\n event Minter(address indexed newMinter);\n event CatalystApplied(uint256 indexed assetId, uint256 indexed catalystId, uint256 seed, uint256[] gemIds, uint64 blockNumber);\n event GemsAdded(uint256 indexed assetId, uint256 seed, uint256[] gemIds, uint64 blockNumber);\n\n function getCatalyst(uint256 assetId) external view returns (bool exists, uint256 catalystId) {\n CatalystStored memory catalyst = _catalysts[assetId];\n if (catalyst.set != 0) {\n return (true, catalyst.catalystId);\n }\n if (assetId & IS_NFT != 0) {\n catalyst = _catalysts[_getCollectionId(assetId)];\n return (catalyst.set != 0, catalyst.catalystId);\n }\n return (false, 0);\n }\n\n function setCatalyst(\n uint256 assetId,\n uint256 catalystId,\n uint256 maxGems,\n uint256[] calldata gemIds\n ) external {\n require(msg.sender == _minter, \"NOT_AUTHORIZED_MINTER\");\n require(gemIds.length <= maxGems, \"INVALID_GEMS_TOO_MANY\");\n uint256 emptySockets = maxGems - gemIds.length;\n _catalysts[assetId] = CatalystStored(uint64(emptySockets), uint64(catalystId), 1);\n uint64 blockNumber = _getBlockNumber();\n emit CatalystApplied(assetId, catalystId, assetId, gemIds, blockNumber);\n }\n\n function addGems(uint256 assetId, uint256[] calldata gemIds) external {\n require(msg.sender == _minter, \"NOT_AUTHORIZED_MINTER\");\n require(assetId & IS_NFT != 0, \"INVALID_NOT_NFT\");\n require(gemIds.length != 0, \"INVALID_GEMS_0\");\n (uint256 emptySockets, uint256 seed) = _getSocketData(assetId);\n require(emptySockets >= gemIds.length, \"INVALID_GEMS_TOO_MANY\");\n emptySockets -= gemIds.length;\n _catalysts[assetId].emptySockets = uint64(emptySockets);\n uint64 blockNumber = _getBlockNumber();\n emit GemsAdded(assetId, seed, gemIds, blockNumber);\n }\n\n /// @dev Set the Minter that will be the only address able to create Estate\n /// @param minter address of the minter\n function setMinter(address minter) external {\n require(msg.sender == _admin, \"NOT_AUTHORIZED_ADMIN\");\n require(minter != _minter, \"INVALID_MINTER_SAME_ALREADY_SET\");\n _minter = minter;\n emit Minter(minter);\n }\n\n /// @dev return the current minter\n function getMinter() external view returns (address) {\n return _minter;\n }\n\n function getValues(\n uint256 catalystId,\n uint256 seed,\n GemEvent[] calldata events,\n uint32 totalNumberOfGemTypes\n ) external override view returns (uint32[] memory values) {\n return _catalystValue.getValues(catalystId, seed, events, totalNumberOfGemTypes);\n }\n\n // ///////// INTERNAL ////////////\n\n uint256 private constant IS_NFT = 0x0000000000000000000000000000000000000000800000000000000000000000;\n uint256 private constant NOT_IS_NFT = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFFFFFF;\n uint256 private constant NOT_NFT_INDEX = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF800000007FFFFFFFFFFFFFFF;\n\n function _getSocketData(uint256 assetId) internal view returns (uint256 emptySockets, uint256 seed) {\n seed = assetId;\n CatalystStored memory catalyst = _catalysts[assetId];\n if (catalyst.set != 0) {\n // the gems are added to an asset who already get a specific catalyst.\n // the seed is its id\n return (catalyst.emptySockets, seed);\n }\n // else the asset is only adding gems while keeping the same seed (that of the original assetId)\n seed = _getCollectionId(assetId);\n catalyst = _catalysts[seed];\n return (catalyst.emptySockets, seed);\n }\n\n function _getBlockNumber() internal view returns (uint64 blockNumber) {\n blockNumber = uint64(block.number + 1);\n }\n\n function _getCollectionId(uint256 assetId) internal pure returns (uint256) {\n return assetId & NOT_NFT_INDEX & NOT_IS_NFT; // compute the same as Asset to get collectionId\n }\n\n // CONSTRUCTOR ////\n constructor(CatalystValue catalystValue, address admin) public {\n _admin = admin;\n _catalystValue = catalystValue;\n }\n\n /// DATA ////////\n\n struct CatalystStored {\n uint64 emptySockets;\n uint64 catalystId;\n uint64 set;\n }\n address internal _minter;\n CatalystValue internal immutable _catalystValue;\n mapping(uint256 => CatalystStored) internal _catalysts;\n}\n"
},
"src/contracts_common/src/Base/ERC820Implementer.sol": {
"content": "pragma solidity ^0.6.0;\n\n\ninterface ERC820Registry {\n function getManager(address addr) external view returns (address);\n\n function setManager(address addr, address newManager) external;\n\n function getInterfaceImplementer(address addr, bytes32 iHash) external view returns (address);\n\n function setInterfaceImplementer(\n address addr,\n bytes32 iHash,\n address implementer\n ) external;\n}\n\n\ncontract ERC820Implementer {\n ERC820Registry constant erc820Registry = ERC820Registry(0x820b586C8C28125366C998641B09DCbE7d4cBF06);\n\n function setInterfaceImplementation(string memory ifaceLabel, address impl) internal {\n bytes32 ifaceHash = keccak256(bytes(ifaceLabel));\n erc820Registry.setInterfaceImplementer(address(this), ifaceHash, impl);\n }\n\n function interfaceAddr(address addr, string memory ifaceLabel) internal view returns (address) {\n bytes32 ifaceHash = keccak256(bytes(ifaceLabel));\n return erc820Registry.getInterfaceImplementer(addr, ifaceHash);\n }\n\n function delegateManagement(address newManager) internal {\n erc820Registry.setManager(address(this), newManager);\n }\n}\n"
},
"src/contracts_common/src/BaseWithStorage/Ownable.sol": {
"content": "pragma solidity ^0.6.0;\n\n\n/**\n * @title Ownable\n * @dev The Ownable contract has an owner address, and provides basic authorization control\n * functions, this simplifies the implementation of \"user permissions\".\n */\ncontract Ownable {\n address payable public owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev The Ownable constructor sets the original `owner` of the contract to the sender\n * account.\n */\n constructor() public {\n owner = msg.sender;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(msg.sender == owner);\n _;\n }\n\n // /**\n // * @dev Allows the current owner to relinquish control of the contract.\n // * @notice Renouncing to ownership will leave the contract without an owner.\n // * It will not be possible to call the functions with the `onlyOwner`\n // * modifier anymore.\n // */\n // function renounceOwnership() public onlyOwner {\n // emit OwnershipRenounced(owner);\n // owner = address(0);\n // }\n\n /**\n * @dev Allows the current owner to transfer control of the contract to a newOwner.\n * @param _newOwner The address to transfer ownership to.\n */\n function transferOwnership(address payable _newOwner) public onlyOwner {\n _transferOwnership(_newOwner);\n }\n\n /**\n * @dev Transfers control of the contract to a newOwner.\n * @param _newOwner The address to transfer ownership to.\n */\n function _transferOwnership(address payable _newOwner) internal {\n require(_newOwner != address(0));\n emit OwnershipTransferred(owner, _newOwner);\n owner = _newOwner;\n }\n}\n"
},
"src/contracts_common/src/BaseWithStorage/Pausable.sol": {
"content": "pragma solidity ^0.6.0;\n\nimport \"./Ownable.sol\";\n\n\n/**\n * @title Pausable\n * @dev Base contract which allows children to implement an emergency stop mechanism.\n */\ncontract Pausable is Ownable {\n event Pause();\n event Unpause();\n\n bool public paused = false;\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n */\n modifier whenNotPaused() {\n require(!paused);\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n */\n modifier whenPaused() {\n require(paused);\n _;\n }\n\n /**\n * @dev called by the owner to pause, triggers stopped state\n */\n function pause() public onlyOwner whenNotPaused {\n paused = true;\n emit Pause();\n }\n\n /**\n * @dev called by the owner to unpause, returns to normal state\n */\n function unpause() public onlyOwner whenPaused {\n paused = false;\n emit Unpause();\n }\n}\n"
},
"src/contracts_common/src/BaseWithStorage/ReferrableSale.sol": {
"content": "pragma solidity ^0.6.0;\n\nimport \"./Ownable.sol\";\n\n\n/**\n * @title ReferrableSale\n * @dev Implements the base elements for a sales referral system.\n * It is supposed to be inherited by a sales contract.\n * The referrals are expressed in percentage * 100, for example 1000 represents 10% and 555 represents 5.55%.\n */\ncontract ReferrableSale is Ownable {\n event DefaultReferralSet(uint256 percentage);\n\n event CustomReferralSet(address indexed referrer, uint256 percentage);\n\n uint256 public defaultReferralPercentage;\n mapping(address => uint256) public customReferralPercentages;\n\n function setDefaultReferral(uint256 _defaultReferralPercentage) public onlyOwner {\n require(_defaultReferralPercentage < 10000, \"Referral must be less than 100 percent\");\n require(_defaultReferralPercentage != defaultReferralPercentage, \"New referral must be different from the previous\");\n defaultReferralPercentage = _defaultReferralPercentage;\n emit DefaultReferralSet(_defaultReferralPercentage);\n }\n\n function setCustomReferral(address _referrer, uint256 _customReferralPercentage) public onlyOwner {\n require(_customReferralPercentage < 10000, \"Referral must be less than 100 percent\");\n require(_customReferralPercentage != customReferralPercentages[_referrer], \"New referral must be different from the previous\");\n customReferralPercentages[_referrer] = _customReferralPercentage;\n emit CustomReferralSet(_referrer, _customReferralPercentage);\n }\n}\n"
},
"src/contracts_common/src/BaseWithStorage/Withdrawable.sol": {
"content": "pragma solidity ^0.6.0;\n\nimport \"./Ownable.sol\";\nimport \"../Interfaces/ERC20.sol\";\n\n\ncontract Withdrawable is Ownable {\n function withdrawEther(address payable _destination) external onlyOwner {\n _destination.transfer(address(this).balance);\n }\n\n function withdrawToken(ERC20 _token, address _destination) external onlyOwner {\n require(_token.transfer(_destination, _token.balanceOf(address(this))), \"Transfer failed\");\n }\n}\n"
},
"src/contracts_common/src/Interfaces/ERC1271.sol": {
"content": "pragma solidity ^0.6.0;\n\n\ninterface ERC1271 {\n /**\n * @dev Should return whether the signature provided is valid for the provided data\n * @param data Arbitrary length data signed on the behalf of address(this)\n * @param signature Signature byte array associated with _data\n * @return magicValue\n * MUST return the bytes4 magic value 0x20c13b0b when function passes.\n * MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)\n * MUST allow external calls\n */\n function isValidSignature(bytes calldata data, bytes calldata signature) external view returns (bytes4 magicValue);\n}\n"
},
"src/contracts_common/src/Interfaces/ERC1271Constants.sol": {
"content": "pragma solidity ^0.6.0;\n\n\ncontract ERC1271Constants {\n bytes4 internal constant ERC1271_MAGICVALUE = 0x20c13b0b;\n}\n"
},
"src/contracts_common/src/Interfaces/ERC165.sol": {
"content": "pragma solidity ^0.6.0;\n\n\n/**\n * @title ERC165\n * @dev https://eips.ethereum.org/EIPS/eip-165\n */\ninterface ERC165 {\n /**\n * @notice Query if a contract implements interface `interfaceId`\n * @param interfaceId The interface identifier, as specified in ERC-165\n * @dev Interface identification is specified in ERC-165. This function\n * uses less than 30,000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
},
"src/contracts_common/src/Interfaces/ERC1654.sol": {
"content": "pragma solidity ^0.6.0;\n\n\ninterface ERC1654 {\n /**\n * @dev Should return whether the signature provided is valid for the provided hash\n * @param hash 32 bytes hash to be signed\n * @param signature Signature byte array associated with hash\n * @return magicValue 0x1626ba7e if valid else 0x00000000\n */\n function isValidSignature(bytes32 hash, bytes calldata signature) external view returns (bytes4 magicValue);\n}\n"
},
"src/contracts_common/src/Interfaces/ERC1654Constants.sol": {
"content": "pragma solidity ^0.6.0;\n\n\ncontract ERC1654Constants {\n bytes4 internal constant ERC1654_MAGICVALUE = 0x1626ba7e;\n}\n"
},
"src/contracts_common/src/Interfaces/ERC20Receiver.sol": {
"content": "pragma solidity ^0.6.0;\n\n\ninterface ERC20Receiver {\n function receiveApproval(\n address _from,\n uint256 _value,\n address _tokenAddress,\n bytes calldata _data\n ) external;\n}\n"
},
"src/contracts_common/src/Interfaces/ERC20WithMetadata.sol": {
"content": "/* This Source Code Form is subject to the terms of the Mozilla external\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at http://mozilla.org/MPL/2.0/.\n *\n * This code has not been reviewed.\n * Do not use or deploy this code before reviewing it personally first.\n */\n// solhint-disable-next-line compiler-fixed\npragma solidity ^0.6.0;\n\nimport \"./ERC20.sol\";\n\n\ninterface ERC20WithMetadata is ERC20 {\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\n}\n"
},
"src/contracts_common/src/Interfaces/ERC721.sol": {
"content": "pragma solidity ^0.6.0;\n\nimport \"./ERC165.sol\";\nimport \"./ERC721Events.sol\";\n\n\n/**\n * @title ERC721 Non-Fungible Token Standard basic interface\n * @dev see https://eips.ethereum.org/EIPS/eip-721\n */\n\ninterface ERC721 is ERC165, ERC721Events {\n function balanceOf(address owner) external view returns (uint256 balance);\n\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n // function exists(uint256 tokenId) external view returns (bool exists);\n\n function approve(address to, uint256 tokenId) external;\n\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n function setApprovalForAll(address operator, bool approved) external;\n\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes calldata data\n ) external;\n}\n"
},
"src/contracts_common/src/Interfaces/ERC777Token.sol": {
"content": "/* This Source Code Form is subject to the terms of the Mozilla external\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at http://mozilla.org/MPL/2.0/.\n *\n * This code has not been reviewed.\n * Do not use or deploy this code before reviewing it personally first.\n */\n// solhint-disable-next-line compiler-fixed\npragma solidity ^0.6.0;\n\n\ninterface ERC777Token {\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address owner) external view returns (uint256);\n\n function granularity() external view returns (uint256);\n\n function defaultOperators() external view returns (address[] memory);\n\n function isOperatorFor(address operator, address tokenHolder) external view returns (bool);\n\n function authorizeOperator(address operator) external;\n\n function revokeOperator(address operator) external;\n\n function send(\n address to,\n uint256 amount,\n bytes calldata data\n ) external;\n\n function operatorSend(\n address from,\n address to,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n // function burn(uint256 amount, bytes data) external;\n // function operatorBurn(address from, uint256 amount, bytes data, bytes operatorData) external;\n\n event Sent(address indexed operator, address indexed from, address indexed to, uint256 amount, bytes data, bytes operatorData); // solhint-disable-next-line separate-by-one-line-in-contract\n event Minted(address indexed operator, address indexed to, uint256 amount, bytes operatorData);\n event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData);\n event AuthorizedOperator(address indexed operator, address indexed tokenHolder);\n event RevokedOperator(address indexed operator, address indexed tokenHolder);\n}\n"
},
"src/contracts_common/src/Interfaces/ERC777TokenEvents.sol": {
"content": "pragma solidity ^0.6.0;\n\n\ninterface ERC777TokenEvents {\n event Sent(address indexed operator, address indexed from, address indexed to, uint256 amount, bytes data, bytes operatorData); // solhint-disable-next-line separate-by-one-line-in-contract\n event Minted(address indexed operator, address indexed to, uint256 amount, bytes operatorData);\n event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData);\n event AuthorizedOperator(address indexed operator, address indexed tokenHolder);\n event RevokedOperator(address indexed operator, address indexed tokenHolder);\n}\n"
},
"src/contracts_common/src/Interfaces/ERC777TokensRecipient.sol": {
"content": "/* This Source Code Form is subject to the terms of the Mozilla external\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at http://mozilla.org/MPL/2.0/.\n *\n * This code has not been reviewed.\n * Do not use or deploy this code before reviewing it personally first.\n */\n// solhint-disable-next-line compiler-fixed\npragma solidity ^0.6.0;\n\n\ninterface ERC777TokensRecipient {\n function tokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n}\n"
},
"src/contracts_common/src/Interfaces/ERC777TokensSender.sol": {
"content": "/* This Source Code Form is subject to the terms of the Mozilla external\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at http://mozilla.org/MPL/2.0/.\n *\n * This code has not been reviewed.\n * Do not use or deploy this code before reviewing it personally first.\n */\n// solhint-disable-next-line compiler-fixed\npragma solidity ^0.6.0;\n\n\ninterface ERC777TokensSender {\n function tokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n"
},
"src/contracts_common/src/Interfaces/Medianizer.sol": {
"content": "pragma solidity ^0.6.0;\n\n\n/**\n * @title Medianizer contract\n * @dev From MakerDAO (https://etherscan.io/address/0x729D19f657BD0614b4985Cf1D82531c67569197B#code)\n */\ninterface Medianizer {\n function read() external view returns (bytes32);\n}\n"
},
"src/contracts_common/src/Libraries/Math.sol": {
"content": "pragma solidity ^0.6.0;\n\n\n/**\n * @title Math\n * @dev Math operations\n */\nlibrary Math {\n function max(uint256 a, uint256 b) internal pure returns (uint256 c) {\n return a >= b ? a : b;\n }\n\n function min(uint256 a, uint256 b) internal pure returns (uint256 c) {\n return a < b ? a : b;\n }\n}\n"
},
"src/contracts_common/src/Libraries/ObjectLib.sol": {
"content": "pragma solidity ^0.6.0;\n\nimport \"./SafeMathWithRequire.sol\";\n\n\nlibrary ObjectLib {\n using SafeMathWithRequire for uint256;\n enum Operations {ADD, SUB, REPLACE}\n // Constants regarding bin or chunk sizes for balance packing\n uint256 constant TYPES_BITS_SIZE = 16; // Max size of each object\n uint256 constant TYPES_PER_UINT256 = 256 / TYPES_BITS_SIZE; // Number of types per uint256\n\n //\n // Objects and Tokens Functions\n //\n\n /**\n * @dev Return the bin number and index within that bin where ID is\n * @param _tokenId Object type\n * @return bin Bin number\n * @return index ID's index within that bin\n */\n function getTokenBinIndex(uint256 _tokenId) internal pure returns (uint256 bin, uint256 index) {\n bin = (_tokenId * TYPES_BITS_SIZE) / 256;\n index = _tokenId % TYPES_PER_UINT256;\n return (bin, index);\n }\n\n /**\n * @dev update the balance of a type provided in _binBalances\n * @param _binBalances Uint256 containing the balances of objects\n * @param _index Index of the object in the provided bin\n * @param _amount Value to update the type balance\n * @param _operation Which operation to conduct :\n * Operations.REPLACE : Replace type balance with _amount\n * Operations.ADD : ADD _amount to type balance\n * Operations.SUB : Substract _amount from type balance\n */\n function updateTokenBalance(\n uint256 _binBalances,\n uint256 _index,\n uint256 _amount,\n Operations _operation\n ) internal pure returns (uint256 newBinBalance) {\n uint256 objectBalance = 0;\n if (_operation == Operations.ADD) {\n objectBalance = getValueInBin(_binBalances, _index);\n newBinBalance = writeValueInBin(_binBalances, _index, objectBalance.add(_amount));\n } else if (_operation == Operations.SUB) {\n objectBalance = getValueInBin(_binBalances, _index);\n newBinBalance = writeValueInBin(_binBalances, _index, objectBalance.sub(_amount));\n } else if (_operation == Operations.REPLACE) {\n newBinBalance = writeValueInBin(_binBalances, _index, _amount);\n } else {\n revert(\"Invalid operation\"); // Bad operation\n }\n\n return newBinBalance;\n }\n\n /*\n * @dev return value in _binValue at position _index\n * @param _binValue uint256 containing the balances of TYPES_PER_UINT256 types\n * @param _index index at which to retrieve value\n * @return Value at given _index in _bin\n */\n function getValueInBin(uint256 _binValue, uint256 _index) internal pure returns (uint256) {\n // Mask to retrieve data for a given binData\n uint256 mask = (uint256(1) << TYPES_BITS_SIZE) - 1;\n\n // Shift amount\n uint256 rightShift = 256 - TYPES_BITS_SIZE * (_index + 1);\n return (_binValue >> rightShift) & mask;\n }\n\n /**\n * @dev return the updated _binValue after writing _amount at _index\n * @param _binValue uint256 containing the balances of TYPES_PER_UINT256 types\n * @param _index Index at which to retrieve value\n * @param _amount Value to store at _index in _bin\n * @return Value at given _index in _bin\n */\n function writeValueInBin(\n uint256 _binValue,\n uint256 _index,\n uint256 _amount\n ) internal pure returns (uint256) {\n require(_amount < 2**TYPES_BITS_SIZE, \"Amount to write in bin is too large\");\n\n // Mask to retrieve data for a given binData\n uint256 mask = (uint256(1) << TYPES_BITS_SIZE) - 1;\n\n // Shift amount\n uint256 leftShift = 256 - TYPES_BITS_SIZE * (_index + 1);\n return (_binValue & ~(mask << leftShift)) | (_amount << leftShift);\n }\n}\n"
},
"src/contracts_common/src/Libraries/ObjectLib64.sol": {
"content": "pragma solidity ^0.6.0;\n\nimport \"./SafeMathWithRequire.sol\";\n\n\nlibrary ObjectLib64 {\n using SafeMathWithRequire for uint256;\n enum Operations {ADD, SUB, REPLACE}\n // Constants regarding bin or chunk sizes for balance packing\n uint256 constant TYPES_BITS_SIZE = 64; // Max size of each object\n uint256 constant TYPES_PER_UINT256 = 256 / TYPES_BITS_SIZE; // Number of types per uint256\n\n //\n // Objects and Tokens Functions\n //\n\n /**\n * @dev Return the bin number and index within that bin where ID is\n * @param _tokenId Object type\n * @return bin Bin number\n * @return index ID's index within that bin\n */\n function getTokenBinIndex(uint256 _tokenId) internal pure returns (uint256 bin, uint256 index) {\n bin = (_tokenId * TYPES_BITS_SIZE) / 256;\n index = _tokenId % TYPES_PER_UINT256;\n return (bin, index);\n }\n\n /**\n * @dev update the balance of a type provided in _binBalances\n * @param _binBalances Uint256 containing the balances of objects\n * @param _index Index of the object in the provided bin\n * @param _amount Value to update the type balance\n * @param _operation Which operation to conduct :\n * Operations.REPLACE : Replace type balance with _amount\n * Operations.ADD : ADD _amount to type balance\n * Operations.SUB : Substract _amount from type balance\n */\n function updateTokenBalance(\n uint256 _binBalances,\n uint256 _index,\n uint256 _amount,\n Operations _operation\n ) internal pure returns (uint256 newBinBalance) {\n uint256 objectBalance = 0;\n if (_operation == Operations.ADD) {\n objectBalance = getValueInBin(_binBalances, _index);\n newBinBalance = writeValueInBin(_binBalances, _index, objectBalance.add(_amount));\n } else if (_operation == Operations.SUB) {\n objectBalance = getValueInBin(_binBalances, _index);\n newBinBalance = writeValueInBin(_binBalances, _index, objectBalance.sub(_amount));\n } else if (_operation == Operations.REPLACE) {\n newBinBalance = writeValueInBin(_binBalances, _index, _amount);\n } else {\n revert(\"Invalid operation\"); // Bad operation\n }\n\n return newBinBalance;\n }\n\n /*\n * @dev return value in _binValue at position _index\n * @param _binValue uint256 containing the balances of TYPES_PER_UINT256 types\n * @param _index index at which to retrieve value\n * @return Value at given _index in _bin\n */\n function getValueInBin(uint256 _binValue, uint256 _index) internal pure returns (uint256) {\n // Mask to retrieve data for a given binData\n uint256 mask = (uint256(1) << TYPES_BITS_SIZE) - 1;\n\n // Shift amount\n uint256 rightShift = 256 - TYPES_BITS_SIZE * (_index + 1);\n return (_binValue >> rightShift) & mask;\n }\n\n /**\n * @dev return the updated _binValue after writing _amount at _index\n * @param _binValue uint256 containing the balances of TYPES_PER_UINT256 types\n * @param _index Index at which to retrieve value\n * @param _amount Value to store at _index in _bin\n * @return Value at given _index in _bin\n */\n function writeValueInBin(\n uint256 _binValue,\n uint256 _index,\n uint256 _amount\n ) internal pure returns (uint256) {\n require(_amount < 2**TYPES_BITS_SIZE, \"Amount to write in bin is too large\");\n\n // Mask to retrieve data for a given binData\n uint256 mask = (uint256(1) << TYPES_BITS_SIZE) - 1;\n\n // Shift amount\n uint256 leftShift = 256 - TYPES_BITS_SIZE * (_index + 1);\n return (_binValue & ~(mask << leftShift)) | (_amount << leftShift);\n }\n}\n"
},
"src/contracts_common/src/Libraries/PriceUtil.sol": {
"content": "pragma solidity ^0.6.0;\n\nimport \"./SafeMathWithRequire.sol\";\n\n\nlibrary PriceUtil {\n using SafeMathWithRequire for uint256;\n\n function calculateCurrentPrice(\n uint256 startingPrice,\n uint256 endingPrice,\n uint256 duration,\n uint256 secondsPassed\n ) internal pure returns (uint256) {\n if (secondsPassed > duration) {\n return endingPrice;\n }\n if (endingPrice == startingPrice) {\n return endingPrice;\n } else if (endingPrice > startingPrice) {\n return startingPrice.add((endingPrice.sub(startingPrice)).mul(secondsPassed).div(duration));\n } else {\n return startingPrice.sub((startingPrice.sub(endingPrice)).mul(secondsPassed).div(duration));\n }\n }\n\n function calculateFee(uint256 price, uint256 fee10000th) internal pure returns (uint256) {\n // _fee < 10000, so the result will be <= price\n return (price.mul(fee10000th)) / 10000;\n }\n}\n"
},
"src/contracts_common/src/Libraries/SigUtil.sol": {
"content": "pragma solidity ^0.6.0;\n\n\nlibrary SigUtil {\n function recover(bytes32 hash, bytes memory sig) internal pure returns (address recovered) {\n require(sig.length == 65);\n\n bytes32 r;\n bytes32 s;\n uint8 v;\n assembly {\n r := mload(add(sig, 32))\n s := mload(add(sig, 64))\n v := byte(0, mload(add(sig, 96)))\n }\n\n // Version of signature should be 27 or 28, but 0 and 1 are also possible versions\n if (v < 27) {\n v += 27;\n }\n require(v == 27 || v == 28);\n\n recovered = ecrecover(hash, v, r, s);\n require(recovered != address(0));\n }\n\n function recoverWithZeroOnFailure(bytes32 hash, bytes memory sig) internal pure returns (address) {\n if (sig.length != 65) {\n return (address(0));\n }\n\n bytes32 r;\n bytes32 s;\n uint8 v;\n assembly {\n r := mload(add(sig, 32))\n s := mload(add(sig, 64))\n v := byte(0, mload(add(sig, 96)))\n }\n\n // Version of signature should be 27 or 28, but 0 and 1 are also possible versions\n if (v < 27) {\n v += 27;\n }\n\n if (v != 27 && v != 28) {\n return (address(0));\n } else {\n return ecrecover(hash, v, r, s);\n }\n }\n\n // Builds a prefixed hash to mimic the behavior of eth_sign.\n function prefixed(bytes32 hash) internal pure returns (bytes memory) {\n return abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash);\n }\n}\n"
},
"src/contracts_common/src/UpgradableProxy/AdminUpgradeabilityProxy.sol": {
"content": "// from https://github.com/zeppelinos/zos/blob/1cea266a672a1efc31915420af5eb5185173837c/packages/lib/contracts/upgradeability/AdminUpgradeabilityProxy.sol\npragma solidity ^0.6.0;\n\nimport \"./UpgradeabilityProxy.sol\";\nimport \"./ProxyAdmin.sol\";\n\n\n/**\n * @title AdminUpgradeabilityProxy\n * @dev This contract combines an upgradeability proxy with an authorization\n * mechanism for administrative tasks.\n * All external functions in this contract must be guarded by the\n * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity\n * feature proposal that would enable this to be done automatically.\n */\ncontract AdminUpgradeabilityProxy is UpgradeabilityProxy {\n /**\n * @dev Emitted when the administration has been transferred.\n * @param previousAdmin Address of the previous admin.\n * @param newAdmin Address of the new admin.\n */\n event AdminChanged(address previousAdmin, address newAdmin);\n\n /**\n * @dev Storage slot with the admin of the contract.\n * This is the keccak-256 hash of \"org.zeppelinos.proxy.admin\", and is\n * validated in the constructor.\n */\n bytes32 private constant ADMIN_SLOT = 0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b;\n\n /**\n * @dev Modifier to check whether the `msg.sender` is the admin.\n * If it is, it will run the function. Otherwise, it will delegate the call\n * to the implementation.\n */\n modifier ifAdmin() {\n if (msg.sender == _admin()) {\n _;\n } else {\n _fallback();\n }\n }\n\n /**\n * Contract constructor.\n * It sets the `msg.sender` as the proxy administrator.\n * @param _implementation address of the initial implementation.\n * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.\n * It should include the signature and the parameters of the function to be called, as described in\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\n * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.\n */\n constructor(\n address payable _owner,\n address _implementation,\n bytes memory _data\n ) public payable UpgradeabilityProxy(_implementation, _data) {\n assert(ADMIN_SLOT == keccak256(\"org.zeppelinos.proxy.admin\"));\n\n ProxyAdmin proxyAdmin = new ProxyAdmin(this, _owner); // TODO cheaper creation : https://eips.ethereum.org/EIPS/eip-1167\n emit AdminChanged(address(0), address(proxyAdmin));\n _setAdmin(address(proxyAdmin));\n }\n\n /**\n * @return The address of the proxy admin.\n */\n function admin() external ifAdmin returns (address) {\n return _admin();\n }\n\n /**\n * @return The address of the implementation.\n */\n function implementation() external ifAdmin returns (address) {\n return _implementation();\n }\n\n /**\n * @dev Changes the admin of the proxy.\n * Only the current admin can call this function.\n * @param newAdmin Address to transfer proxy administration to.\n */\n function changeAdmin(address newAdmin) external ifAdmin {\n require(newAdmin != address(0), \"Cannot change the admin of a proxy to the zero address\");\n emit AdminChanged(_admin(), newAdmin);\n _setAdmin(newAdmin);\n }\n\n /**\n * @dev Upgrade the backing implementation of the proxy.\n * Only the admin can call this function.\n * @param newImplementation Address of the new implementation.\n */\n function upgradeTo(address newImplementation) external ifAdmin {\n _upgradeTo(newImplementation);\n }\n\n /**\n * @dev Upgrade the backing implementation of the proxy and call a function\n * on the new implementation.\n * This is useful to initialize the proxied contract.\n * @param newImplementation Address of the new implementation.\n * @param data Data to send as msg.data in the low level call.\n * It should include the signature and the parameters of the function to be called, as described in\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\n */\n function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {\n _upgradeTo(newImplementation);\n (bool success, ) = newImplementation.delegatecall(data);\n require(success, \"failed to call newImplementation\");\n }\n\n /**\n * @return adm The admin slot.\n */\n function _admin() internal view returns (address adm) {\n bytes32 slot = ADMIN_SLOT;\n assembly {\n adm := sload(slot)\n }\n }\n\n /**\n * @dev Sets the address of the proxy admin.\n * @param newAdmin Address of the new proxy admin.\n */\n function _setAdmin(address newAdmin) internal {\n bytes32 slot = ADMIN_SLOT;\n\n assembly {\n sstore(slot, newAdmin)\n }\n }\n\n /**\n * @dev Only fall back when the sender is not the admin.\n */\n // override is not supported by prettier-plugin-solidity : https://github.com/prettier-solidity/prettier-plugin-solidity/issues/221\n // prettier-ignore\n function _willFallback() override internal {\n require(\n msg.sender != _admin(),\n \"Cannot call fallback function from the proxy admin\"\n );\n super._willFallback();\n }\n}\n"
},
"src/contracts_common/src/UpgradableProxy/UpgradeabilityProxy.sol": {
"content": "// from https://github.com/zeppelinos/zos/blob/1cea266a672a1efc31915420af5eb5185173837c/packages/lib/contracts/upgradeability/UpgradeabilityProxy.sol\npragma solidity ^0.6.0;\n\nimport \"./ProxyBase.sol\";\nimport \"../Libraries/AddressUtils.sol\";\n\n\n/**\n * @title UpgradeabilityProxy\n * @dev This contract implements a proxy that allows to change the\n * implementation address to which it will delegate.\n * Such a change is called an implementation upgrade.\n */\ncontract UpgradeabilityProxy is ProxyBase {\n /**\n * @dev Emitted when the implementation is upgraded.\n * @param implementation Address of the new implementation.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Storage slot with the address of the current implementation.\n * This is the keccak-256 hash of \"org.zeppelinos.proxy.implementation\", and is\n * validated in the constructor.\n */\n bytes32 private constant IMPLEMENTATION_SLOT = 0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3;\n\n /**\n * @dev Contract constructor.\n * @param _implementation Address of the initial implementation.\n * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.\n * It should include the signature and the parameters of the function to be called, as described in\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\n * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.\n */\n constructor(address _implementation, bytes memory _data) public payable {\n assert(IMPLEMENTATION_SLOT == keccak256(\"org.zeppelinos.proxy.implementation\"));\n _setImplementation(_implementation);\n if (_data.length > 0) {\n (bool success, ) = _implementation.delegatecall(_data);\n require(success, \"could not call the contract\");\n }\n }\n\n /**\n * @dev Returns the current implementation.\n * @return impl Address of the current implementation\n */\n // override is not supported by prettier-plugin-solidity : https://github.com/prettier-solidity/prettier-plugin-solidity/issues/221\n // prettier-ignore\n function _implementation() override internal view returns (address impl) {\n bytes32 slot = IMPLEMENTATION_SLOT;\n assembly {\n impl := sload(slot)\n }\n }\n\n /**\n * @dev Upgrades the proxy to a new implementation.\n * @param newImplementation Address of the new implementation.\n */\n function _upgradeTo(address newImplementation) internal {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Sets the implementation address of the proxy.\n * @param newImplementation Address of the new implementation.\n */\n function _setImplementation(address newImplementation) private {\n require(AddressUtils.isContract(newImplementation), \"Cannot set a proxy implementation to a non-contract address\");\n\n bytes32 slot = IMPLEMENTATION_SLOT;\n\n assembly {\n sstore(slot, newImplementation)\n }\n }\n}\n"
},
"src/contracts_common/src/UpgradableProxy/ProxyBase.sol": {
"content": "// issue swith indentation due to abstract ?\n/* solhint-disable */\n\n// from https://github.com/zeppelinos/zos/blob/1cea266a672a1efc31915420af5eb5185173837c/packages/lib/contracts/upgradeability/Proxy.sol\npragma solidity ^0.6.0;\n\n\n/**\n * @title ProxyBase\n * @dev Implements delegation of calls to other contracts, with proper\n * forwarding of return values and bubbling of failures.\n * It defines a fallback function that delegates all calls to the address\n * returned by the abstract _implementation() internal function.\n */\nabstract contract ProxyBase {\n /**\n * @dev Fallback function.\n * Implemented entirely in `_fallback`.\n */\n fallback() external payable {\n _fallback();\n }\n\n /**\n * @dev receiver function.\n * Implemented entirely in `_fallback`.\n */\n receive() external payable {\n _fallback();\n }\n\n /**\n * @return The Address of the implementation.\n */\n function _implementation() internal virtual view returns (address);\n\n /**\n * @dev Delegates execution to an implementation contract.\n * This is a low level function that doesn't return to its internal call site.\n * It will return to the external caller whatever the implementation returns.\n * @param implementation Address to delegate.\n */\n function _delegate(address implementation) internal {\n assembly {\n // Copy msg.data. We take full control of memory in this inline assembly\n // block because it will not return to Solidity code. We overwrite the\n // Solidity scratch pad at memory position 0.\n calldatacopy(0, 0, calldatasize())\n\n // Call the implementation.\n // out and outsize are 0 because we don't know the size yet.\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\n\n // Copy the returned data.\n returndatacopy(0, 0, returndatasize())\n\n switch result\n // delegatecall returns 0 on error.\n case 0 {\n revert(0, returndatasize())\n }\n default {\n return(0, returndatasize())\n }\n }\n }\n\n /**\n * @dev Function that is run as the first thing in the fallback function.\n * Can be redefined in derived contracts to add functionality.\n * Redefinitions must call super._willFallback().\n */\n function _willFallback() internal virtual {}\n\n /**\n * @dev fallback implementation.\n * Extracted to enable manual triggering.\n */\n function _fallback() internal {\n _willFallback();\n _delegate(_implementation());\n }\n}\n"
},
"src/contracts_common/src/UpgradableProxy/ProxyAdmin.sol": {
"content": "pragma solidity ^0.6.0;\n\nimport \"./AdminUpgradeabilityProxy.sol\";\nimport \"../BaseWithStorage/Ownable.sol\";\n\n\ncontract ProxyAdmin is Ownable {\n AdminUpgradeabilityProxy proxy;\n\n constructor(AdminUpgradeabilityProxy _proxy, address payable _owner) public {\n proxy = _proxy;\n owner = _owner;\n }\n\n function proxyAddress() public view returns (address) {\n return address(proxy);\n }\n\n function admin() public returns (address) {\n return proxy.admin();\n }\n\n function changeAdmin(address newAdmin) public onlyOwner {\n proxy.changeAdmin(newAdmin);\n }\n\n function upgradeTo(address implementation) public onlyOwner {\n proxy.upgradeTo(implementation);\n }\n\n function upgradeToAndCall(address implementation, bytes memory data) public payable onlyOwner {\n // prettier-ignore\n proxy.upgradeToAndCall{value:msg.value}(implementation, data);\n }\n}\n"
},
"src/Estate.sol": {
"content": "pragma solidity 0.6.5;\n\nimport \"./Estate/EstateBaseToken.sol\";\n\n\ncontract Estate is EstateBaseToken {\n constructor(\n address metaTransactionContract,\n address admin,\n LandToken land\n ) public EstateBaseToken(metaTransactionContract, admin, land) {}\n\n /**\n * @notice Return the name of the token contract\n * @return The name of the token contract\n */\n function name() external pure returns (string memory) {\n return \"Sandbox's ESTATEs\";\n }\n\n /**\n * @notice Return the symbol of the token contract\n * @return The symbol of the token contract\n */\n function symbol() external pure returns (string memory) {\n return \"ESTATE\";\n }\n\n // solium-disable-next-line security/no-assign-params\n function uint2str(uint256 _i) internal pure returns (string memory) {\n if (_i == 0) {\n return \"0\";\n }\n uint256 j = _i;\n uint256 len;\n while (j != 0) {\n len++;\n j /= 10;\n }\n bytes memory bstr = new bytes(len);\n uint256 k = len - 1;\n while (_i != 0) {\n bstr[k--] = bytes1(uint8(48 + (_i % 10)));\n _i /= 10;\n }\n return string(bstr);\n }\n\n /**\n * @notice Return the URI of a specific token\n * @param id The id of the token\n * @return The URI of the token\n */\n function tokenURI(uint256 id) public view returns (string memory) {\n require(_ownerOf(id) != address(0), \"Id does not exist\");\n return string(abi.encodePacked(\"https://api.sandbox.game/estates/\", uint2str(id), \"/metadata.json\"));\n }\n\n /**\n * @notice Check if the contract supports an interface\n * 0x01ffc9a7 is ERC-165\n * 0x80ac58cd is ERC-721\n * 0x5b5e139f is ERC-721 metadata\n * @param id The id of the interface\n * @return True if the interface is supported\n */\n // override is not supported by prettier-plugin-solidity : https://github.com/prettier-solidity/prettier-plugin-solidity/issues/221\n // prettier-ignore\n function supportsInterface(bytes4 id) public override pure returns (bool) {\n return super.supportsInterface(id) || id == 0x5b5e139f;\n }\n}\n"
},
"src/Estate/EstateBaseToken.sol": {
"content": "pragma solidity 0.6.5;\n\nimport \"../BaseWithStorage/ERC721BaseToken.sol\";\nimport \"../Interfaces/LandToken.sol\";\nimport \"../contracts_common/src/Interfaces/ERC721MandatoryTokenReceiver.sol\";\n\n\ncontract EstateBaseToken is ERC721BaseToken {\n uint16 internal constant GRID_SIZE = 408;\n\n uint256 _nextId = 1;\n mapping(uint256 => uint24[]) _quadsInEstate;\n LandToken _land;\n address _minter;\n address _breaker;\n\n event QuadsAdded(uint256 indexed id, uint24[] list);\n event QuadsRemoved(uint256 indexed id, uint256 numRemoved);\n\n event Minter(address newMinter);\n event Breaker(address newBreaker);\n\n constructor(\n address metaTransactionContract,\n address admin,\n LandToken land\n ) public ERC721BaseToken(metaTransactionContract, admin) {\n _land = land;\n }\n\n /// @notice Set the Minter that will be the only address able to create Estate\n /// @param minter address of the minter\n function setMinter(address minter) external {\n require(msg.sender == _admin, \"ADMIN_NOT_AUTHORIZED\");\n require(minter != _minter, \"MINTER_SAME_ALREADY_SET\");\n _minter = minter;\n emit Minter(minter);\n }\n\n /// @notice return the current minter\n function getMinter() external view returns (address) {\n return _minter;\n }\n\n /// @notice Set the Breaker that will be the only address able to break Estate apart\n /// @param breaker address of the breaker\n function setBreaker(address breaker) external {\n require(msg.sender == _admin, \"ADMIN_NOT_AUTHORIZED\");\n require(breaker != _breaker, \"BREAKER_SAME_ALREADY_SET\");\n _breaker = breaker;\n emit Breaker(breaker);\n }\n\n /// @notice return the current breaker\n function getBreaker() external view returns (address) {\n return _breaker;\n }\n\n /// @notice create an Estate from a quad (a group of land forming a square on a specific grid in the Land contract)\n /// @param sender address perforing the operation that will create an Estate from its land token\n /// @param to the estate will belong to that address\n /// @param size edge size of the quad, 3, 6, 12 or 24\n /// @param x top left corner position of the quad\n /// @param y top left corner position of the quad\n function createFromQuad(\n address sender,\n address to,\n uint256 size,\n uint256 x,\n uint256 y\n ) external returns (uint256) {\n require(to != address(0), \"DESTINATION_ZERO_ADDRESS\");\n require(to != address(this), \"DESTINATION_ESTATE_CONTRACT\");\n _check_create_authorized(sender);\n uint256 estateId = _mintEstate(to);\n _addSingleQuad(sender, estateId, size, x, y, true, 0);\n return estateId;\n }\n\n /// @notice add a single quad to an existing estate\n /// @param sender address perforing the operation that will add the quad to its Estate\n /// @param estateId the estate that is going to be modified\n /// @param size edge size of the quad, 3, 6, 12 or 24\n /// @param x top left corner position of the quad\n /// @param y top left corner position of the quad\n /// @param junction this need to be the index (in the estate) of a quad part of the estate that is adjacent to the newly added quad\n function addQuad(\n address sender,\n uint256 estateId,\n uint256 size,\n uint256 x,\n uint256 y,\n uint256 junction\n ) external {\n _check_add_authorized(sender, estateId);\n _addSingleQuad(sender, estateId, size, x, y, false, junction);\n }\n\n /// @notice create an Estate from a set of Lands, these need to be adjacent so they form a connected whole\n /// @param sender address perforing the operation that will create an Estate from its land token\n /// @param to the estate will belong to that address\n /// @param ids set of Land to add to the estate\n /// @param junctions list of indexes (the index at which the land/quad was indeed in the estate) that will connect added land to the current estate (only if the previously added land is not adjacent to the one added)\n function createFromMultipleLands(\n address sender,\n address to,\n uint256[] calldata ids,\n uint256[] calldata junctions\n ) external returns (uint256) {\n require(to != address(0), \"DESTINATION_ZERO_ADDRESS\");\n require(to != address(this), \"DESTINATION_ESTATE_CONTRACT\");\n _check_create_authorized(sender);\n uint256 estateId = _mintEstate(to);\n _addLands(sender, estateId, ids, junctions);\n return estateId;\n }\n\n /// @notice add a single land to an existing estate\n /// @param sender address perforing the operation that will add the quad to its Estate\n /// @param estateId the estate that is going to be modified\n /// @param id land id to be added to the estate\n /// @param junction this need to be the index (in the estate) of a quad/land part of the estate that is adjacent to the newly added quad\n function addSingleLand(\n address sender,\n uint256 estateId,\n uint256 id,\n uint256 junction\n ) external {\n _check_add_authorized(sender, estateId); // TODO test estateId == 0\n _addLand(sender, estateId, id, junction);\n }\n\n /// @notice add a multiple lands to an existing estate\n /// @param sender address perforing the operation that will add the quad to its Estate\n /// @param estateId the estate that is going to be modified\n /// @param ids array of land ids to be added (these need to be adjacent to each other or to the lands alreayd part of the estate)\n /// @param junctions list of indexes (the index at which the land/quad was indeed in the estate) that will connect added land to the current estate (only if the previously added land is not adjacent to the one added)\n function addMultipleLands(\n address sender,\n uint256 estateId,\n uint256[] calldata ids,\n uint256[] calldata junctions\n ) external {\n _check_add_authorized(sender, estateId);\n _addLands(sender, estateId, ids, junctions);\n }\n\n /// @notice create an Estate from a set of Quads, these need to be adjacent so they form a connected whole\n /// @param sender address perforing the operation that will create an Estate from its land token\n /// @param to the estate will belong to that address\n /// @param sizes the array of sizes for each quad\n /// @param xs the array of top left corner x coordinates for each quad\n /// @param ys the array of top left corner y coordinates for each quad\n /// @param junctions list of indexes (the index at which the land/quad was indeed in the estate) that will connect added land to the current estate (only if the previously added land is not adjacent to the one added)\n function createFromMultipleQuads(\n address sender,\n address to,\n uint256[] calldata sizes,\n uint256[] calldata xs,\n uint256[] calldata ys,\n uint256[] calldata junctions\n ) external returns (uint256) {\n require(to != address(0), \"DESTINATION_ZERO_ADDRESS\");\n require(to != address(this), \"DESTINATION_ESTATE_CONTRACT\");\n _check_create_authorized(sender);\n uint256 estateId = _mintEstate(to);\n _addQuads(sender, estateId, sizes, xs, ys, junctions);\n return estateId;\n }\n\n /// @notice add a multiple lands to an existing estate\n /// @param sender address perforing the operation that will add the quad to its Estate\n /// @param estateId the estate that is going to be modified\n /// @param sizes the array of sizes for each quad\n /// @param xs the array of top left corner x coordinates for each quad\n /// @param ys the array of top left corner y coordinates for each quad\n /// @param junctions list of indexes (the index at which the land/quad was indeed in the estate) that will connect added land to the current estate (only if the previously added land is not adjacent to the one added)\n function addMultipleQuads(\n address sender,\n uint256 estateId,\n uint256[] calldata sizes,\n uint256[] calldata xs,\n uint256[] calldata ys,\n uint256[] calldata junctions\n ) external {\n _check_add_authorized(sender, estateId);\n _addQuads(sender, estateId, sizes, xs, ys, junctions);\n }\n\n // override is not supported by prettier-plugin-solidity : https://github.com/prettier-solidity/prettier-plugin-solidity/issues/221\n // prettier-ignore\n /// @notice burn an Estate\n /// @param id estate id to be burnt\n function burn(uint256 id) external override {\n _check_burn_authorized(msg.sender, id);\n _burn(msg.sender, _ownerOf(id), id);\n }\n\n // override is not supported by prettier-plugin-solidity : https://github.com/prettier-solidity/prettier-plugin-solidity/issues/221\n // prettier-ignore\n /// @notice burn an Estate on behalf\n /// @param from owner of the estate to be burnt\n /// @param id estate id to be burnt\n function burnFrom(address from, uint256 id) external override {\n _check_burn_authorized(from, id);\n _burn(from, _ownerOf(id), id);\n }\n\n /// @notice burn an Estate on behalf and transfer land\n /// @param sender owner of the estate to be burnt\n /// @param estateId estate id to be burnt\n /// @param to address that will receive the lands\n function burnAndTransferFrom(\n address sender,\n uint256 estateId,\n address to\n ) external {\n _check_burn_authorized(sender, estateId);\n _owners[estateId] = (_owners[estateId] & (2**255 - 1)) | (2**160);\n _numNFTPerAddress[sender]--;\n emit Transfer(sender, address(0), estateId);\n transferAllFromDestroyedEstate(sender, estateId, to);\n }\n\n // Optimized version where the whole list is in memory\n /// @notice transfer all lands from a burnt estate\n /// @param sender previous owner of the burnt estate\n /// @param estateId estate id\n /// @param to address that will receive the lands\n function transferAllFromDestroyedEstate(\n address sender,\n uint256 estateId,\n address to\n ) public {\n require(to != address(0), \"DESTINATION_ZERO_ADDRESS\");\n require(to != address(this), \"DESTINATION_ESTATE_CONTRACT\");\n _check_withdrawal_authorized(sender, estateId);\n uint24[] memory list = _quadsInEstate[estateId];\n uint256 num = list.length;\n require(num > 0, \"WITHDRAWAL_COMPLETE\");\n uint256[] memory sizes = new uint256[](num);\n uint256[] memory xs = new uint256[](num);\n uint256[] memory ys = new uint256[](num);\n for (uint256 i = 0; i < num; i++) {\n (uint16 x, uint16 y, uint8 size) = _decode(list[num - 1 - i]);\n _quadsInEstate[estateId].pop();\n sizes[i] = size;\n xs[i] = x;\n ys[i] = y;\n }\n delete _quadsInEstate[estateId];\n _land.batchTransferQuad(address(this), to, sizes, xs, ys, \"\");\n emit QuadsRemoved(estateId, num);\n }\n\n /// @notice transfer a certain number of lands from a burnt estate\n /// @param sender previous owner of the burnt estate\n /// @param estateId estate id\n /// @param num number of land to transfer\n /// @param to address that will receive the lands\n function transferFromDestroyedEstate(\n address sender,\n uint256 estateId,\n uint256 num,\n address to\n ) public {\n require(to != address(0), \"DESTINATION_ZERO_ADDRESS\");\n require(to != address(this), \"DESTINATION_ESTATE_CONTRACT\");\n _check_withdrawal_authorized(sender, estateId);\n uint24[] storage list = _quadsInEstate[estateId];\n uint256 numLeft = list.length;\n if (num == 0) {\n num = numLeft;\n }\n require(num > 0, \"WITHDRAWAL_COMPLETE\");\n require(numLeft >= num, \"WITHDRAWAL_OVERFLOW\");\n uint256[] memory sizes = new uint256[](num);\n uint256[] memory xs = new uint256[](num);\n uint256[] memory ys = new uint256[](num);\n for (uint256 i = 0; i < num; i++) {\n (uint16 x, uint16 y, uint8 size) = _decode(list[numLeft - 1 - i]);\n list.pop();\n sizes[i] = size;\n xs[i] = x;\n ys[i] = y;\n }\n _land.batchTransferQuad(address(this), to, sizes, xs, ys, \"\");\n emit QuadsRemoved(estateId, num);\n }\n\n // //////////////////////////////////////////////////////////////////////////////////////////////////////\n\n function _withdrawalOwnerOf(uint256 id) internal view returns (address) {\n uint256 data = _owners[id];\n if ((data & (2**160)) == 2**160) {\n return address(data);\n }\n return address(0);\n }\n\n function _check_owner_authorized(address sender, uint256 estateId) internal view {\n require(sender != address(0), \"SENDER_ZERO_ADDRESS\");\n (address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(estateId);\n require(owner == sender, \"OWNER_NOT_EQUAL_SENDER\");\n require(\n msg.sender == sender ||\n _metaTransactionContracts[msg.sender] ||\n _superOperators[msg.sender] ||\n _operatorsForAll[sender][msg.sender] ||\n (operatorEnabled && _operators[estateId] == msg.sender),\n \"NOT_AUHTORIZED\"\n );\n }\n\n function _check_burn_authorized(address sender, uint256 estateId) internal view {\n require(sender != address(0), \"SENDER_ZERO_ADDRESS\");\n address breaker = _breaker;\n if (breaker == address(0)) {\n _check_owner_authorized(sender, estateId);\n } else {\n require(msg.sender == breaker, \"BREAKER_NOT_AUTHORIZED\");\n }\n }\n\n function _check_create_authorized(address sender) internal view {\n require(sender != address(0), \"SENDER_ZERO_ADDRESS\");\n address minter = _minter;\n if (minter == address(0)) {\n require(msg.sender == sender || _metaTransactionContracts[msg.sender], \"CREATE_NOT_AUHTORIZED\");\n } else {\n require(msg.sender == minter, \"MINTER_NOT_AUTHORIZED\");\n }\n }\n\n function _check_add_authorized(address sender, uint256 estateId) internal view {\n require(sender != address(0), \"SENDER_ZERO_ADDRESS\");\n address minter = _minter;\n if (minter == address(0)) {\n _check_owner_authorized(sender, estateId);\n } else {\n require(msg.sender == minter, \"MINTER_NOT_AUTHORIZED\");\n }\n }\n\n function _check_withdrawal_authorized(address sender, uint256 estateId) internal view {\n require(sender != address(0), \"SENDER_ZERO_ADDRESS\");\n require(sender == _withdrawalOwnerOf(estateId), \"LAST_OWNER_NOT_EQUAL_SENDER\");\n require(\n msg.sender == sender || _metaTransactionContracts[msg.sender] || _superOperators[msg.sender] || _operatorsForAll[sender][msg.sender],\n \"WITHDRAWAL_NOT_AUHTORIZED\"\n );\n }\n\n // //////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n function _encode(\n uint16 x,\n uint16 y,\n uint8 size\n ) internal pure returns (uint24) {\n return uint24(size) * uint24(2**18) + (uint24(x) + uint24(y) * GRID_SIZE);\n }\n\n function _decode(uint24 data)\n internal\n pure\n returns (\n uint16 x,\n uint16 y,\n uint8 size\n )\n {\n size = uint8(data / (2**18));\n uint24 xy = data % (2**18);\n y = uint16(xy / GRID_SIZE);\n x = uint16(xy % GRID_SIZE);\n }\n\n function _mintEstate(address to) internal returns (uint256) {\n uint256 estateId = _nextId++;\n _owners[estateId] = uint256(to);\n _numNFTPerAddress[to]++;\n emit Transfer(address(0), to, estateId);\n return estateId;\n }\n\n function _addSingleQuad(\n address sender,\n uint256 estateId,\n uint256 size,\n uint256 x,\n uint256 y,\n bool justCreated,\n uint256 junction\n ) internal {\n _land.transferQuad(sender, address(this), size, x, y, \"\");\n uint24[] memory list = new uint24[](1);\n list[0] = _encode(uint16(x), uint16(y), uint8(size));\n if (!justCreated) {\n require(_quadsInEstate[estateId].length > junction, \"JUNCTION_NOT_EXISTS\");\n (uint16 lastX, uint16 lastY, uint8 lastSize) = _decode(_quadsInEstate[estateId][junction]);\n require(_adjacent(uint16(x), uint16(y), uint8(size), lastX, lastY, lastSize), \"JUNCTION_NOT_ADJACENT\");\n }\n _quadsInEstate[estateId].push(list[0]);\n emit QuadsAdded(estateId, list);\n }\n\n function _addQuads(\n address sender,\n uint256 estateId,\n uint256[] memory sizes,\n uint256[] memory xs,\n uint256[] memory ys,\n uint256[] memory junctions\n ) internal {\n _land.batchTransferQuad(sender, address(this), sizes, xs, ys, \"\");\n uint24[] memory list = new uint24[](sizes.length);\n for (uint256 i = 0; i < list.length; i++) {\n list[i] = _encode(uint16(xs[i]), uint16(ys[i]), uint8(sizes[i]));\n }\n\n uint256 numQuadsAlreadyIn = _quadsInEstate[estateId].length;\n _checkAdjacency(estateId, numQuadsAlreadyIn, list, junctions);\n\n if (numQuadsAlreadyIn == 0) {\n _quadsInEstate[estateId] = list;\n } else {\n for (uint256 i = 0; i < list.length; i++) {\n _quadsInEstate[estateId].push(list[i]);\n }\n }\n emit QuadsAdded(estateId, list);\n }\n\n function _checkAdjacency(\n uint256 estateId,\n uint256 numQuadsAlreadyIn,\n uint24[] memory list,\n uint256[] memory junctions\n ) internal view {\n uint16 lastX = 0;\n uint16 lastY = 0;\n uint8 lastSize = 0;\n if (numQuadsAlreadyIn > 0) {\n (lastX, lastY, lastSize) = _decode(_quadsInEstate[estateId][numQuadsAlreadyIn - 1]);\n }\n uint256 j = 0;\n for (uint256 i = 0; i < list.length; i++) {\n (uint16 x, uint16 y, uint8 size) = _decode(list[i]);\n if (lastSize != 0 && !_adjacent(x, y, size, lastX, lastY, lastSize)) {\n require(j < junctions.length, \"JUNCTIONS_MISSING\");\n uint256 index = junctions[j];\n j++;\n uint24 data;\n if (index >= numQuadsAlreadyIn) {\n require(index - numQuadsAlreadyIn < i, \"JUNCTIONS_NOT_PAST\");\n data = list[index - numQuadsAlreadyIn];\n } else {\n data = _quadsInEstate[estateId][index];\n }\n (uint16 jx, uint16 jy, uint8 jsize) = _decode(data);\n require(_adjacent(x, y, size, jx, jy, jsize), \"JUNCTION_NOT_ADJACENT\");\n }\n lastX = x;\n lastY = y;\n lastSize = size;\n }\n }\n\n function _adjacent(\n uint16 x1,\n uint16 y1,\n uint8 s1,\n uint16 x2,\n uint16 y2,\n uint8 s2\n ) internal pure returns (bool) {\n return ((x1 + s1 > x2 && x1 < x2 + s2 && y1 == y2 - s1) ||\n (x1 + s1 > x2 && x1 < x2 + s2 && y1 == y2 + s2) ||\n (x1 == x2 - s1 && y1 + s1 > y2 && y1 < y2 + s2) ||\n (x1 == x2 + s2 && y1 + s1 > y2 && y1 < y2 + s2));\n }\n\n function _addLands(\n address sender,\n uint256 estateId,\n uint256[] memory ids,\n uint256[] memory junctions\n ) internal {\n _land.batchTransferFrom(sender, address(this), ids, \"\");\n uint24[] memory list = new uint24[](ids.length);\n for (uint256 i = 0; i < list.length; i++) {\n uint16 x = uint16(ids[i] % GRID_SIZE);\n uint16 y = uint16(ids[i] / GRID_SIZE);\n list[i] = _encode(x, y, 1);\n }\n\n uint256 numQuadsAlreadyIn = _quadsInEstate[estateId].length;\n _checkAdjacency(estateId, numQuadsAlreadyIn, list, junctions);\n\n if (numQuadsAlreadyIn == 0) {\n _quadsInEstate[estateId] = list;\n } else {\n for (uint256 i = 0; i < list.length; i++) {\n _quadsInEstate[estateId].push(list[i]);\n }\n }\n emit QuadsAdded(estateId, list);\n }\n\n function _addLand(\n address sender,\n uint256 estateId,\n uint256 id,\n uint256 junction\n ) internal {\n _land.transferFrom(sender, address(this), id);\n uint24[] memory list = new uint24[](1);\n uint16 x = uint16(id % GRID_SIZE);\n uint16 y = uint16(id / GRID_SIZE);\n list[0] = _encode(x, y, 1);\n\n require(_quadsInEstate[estateId].length > junction, \"JUNCTION_NOT_EXISTENT\");\n (uint16 lastX, uint16 lastY, uint8 lastSize) = _decode(_quadsInEstate[estateId][junction]);\n require(_adjacent(x, y, 1, lastX, lastY, lastSize), \"JUNCTION_NOT_ADJACENT\");\n _quadsInEstate[estateId].push(list[0]);\n emit QuadsAdded(estateId, list);\n }\n\n // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n function _idInPath(\n uint256 i,\n uint256 size,\n uint256 x,\n uint256 y\n ) internal pure returns (uint256) {\n uint256 row = i / size;\n if (row % 2 == 0) {\n // alow ids to follow a path in a quad\n return (x + (i % size)) + ((y + row) * GRID_SIZE);\n } else {\n return ((x + size) - (1 + (i % size))) + ((y + row) * GRID_SIZE);\n }\n }\n\n function onERC721BatchReceived(\n address operator,\n address from,\n uint256[] calldata ids,\n bytes calldata data\n ) external returns (bytes4) {\n if (operator == address(this)) {\n return _ERC721_BATCH_RECEIVED;\n }\n address to = abi.decode(data, (address));\n require(to != address(0), \"DESTINATION_ZERO_ADDRESS\");\n require(to != address(this), \"DESTINATION_ESTATE_CONTRACT\");\n require(from == address(0), \"ONLY_MINTING_ALLOWED_NO_TRANSFER\");\n uint8 size = 0;\n if (ids.length == 1) {\n revert(\"SIZE_1X1\");\n } else if (ids.length == 9) {\n size = 3;\n } else if (ids.length == 36) {\n size = 6;\n } else if (ids.length == 144) {\n size = 12;\n } else if (ids.length == 576) {\n size = 24;\n } else {\n revert(\"SIZE_INVALID\");\n }\n uint16 x = uint16(ids[0] % GRID_SIZE);\n uint16 y = uint16(ids[0] / GRID_SIZE);\n for (uint256 i = 1; i < ids.length; i++) {\n uint256 id = ids[i];\n require(id == _idInPath(i, size, x, y), \"ID_ORDER\");\n }\n uint256 estateId = _mintEstate(to);\n uint24[] memory list = new uint24[](1);\n list[0] = _encode(x, y, size);\n _quadsInEstate[estateId].push(list[0]);\n emit QuadsAdded(estateId, list);\n return _ERC721_BATCH_RECEIVED;\n }\n\n function onERC721Received(\n address operator,\n address, /*from*/\n uint256, /*tokenId*/\n bytes calldata /*data*/\n ) external view returns (bytes4) {\n if (operator == address(this)) {\n return _ERC721_RECEIVED;\n }\n revert(\"ERC721_REJECTED\");\n }\n\n // override is not supported by prettier-plugin-solidity : https://github.com/prettier-solidity/prettier-plugin-solidity/issues/221\n // prettier-ignore\n function supportsInterface(bytes4 id) public override virtual pure returns (bool) {\n return super.supportsInterface(id) || id == 0x5e8bf644;\n }\n}\n"
},
"src/Interfaces/LandToken.sol": {
"content": "pragma solidity 0.6.5;\n\n\ninterface LandToken {\n function batchTransferQuad(\n address from,\n address to,\n uint256[] calldata sizes,\n uint256[] calldata xs,\n uint256[] calldata ys,\n bytes calldata data\n ) external;\n\n function transferQuad(\n address from,\n address to,\n uint256 size,\n uint256 x,\n uint256 y,\n bytes calldata data\n ) external;\n\n function batchTransferFrom(\n address from,\n address to,\n uint256[] calldata ids,\n bytes calldata data\n ) external;\n\n function transferFrom(\n address from,\n address to,\n uint256 id\n ) external;\n}\n"
},
"src/EstateSale/EstateSale.sol": {
"content": "/* solhint-disable not-rely-on-time, func-order */\npragma solidity 0.6.5;\n\nimport \"../contracts_common/src/Libraries/SafeMathWithRequire.sol\";\nimport \"./LandToken.sol\";\nimport \"../contracts_common/src/Interfaces/ERC1155.sol\";\nimport \"../contracts_common/src/Interfaces/ERC20.sol\";\nimport \"../contracts_common/src/BaseWithStorage/MetaTransactionReceiver.sol\";\nimport \"../contracts_common/src/Interfaces/Medianizer.sol\";\nimport \"../ReferralValidator/ReferralValidator.sol\";\n\n\n/**\n * @title Estate Sale contract with referral that supports also DAI and ETH as payment\n * @notice This contract mananges the sale of our lands as Estates\n */\ncontract EstateSale is MetaTransactionReceiver, ReferralValidator {\n using SafeMathWithRequire for uint256;\n\n uint256 internal constant GRID_SIZE = 408; // 408 is the size of the Land\n uint256 internal constant daiPrice = 14400000000000000;\n\n ERC1155 internal immutable _asset;\n LandToken internal immutable _land;\n ERC20 internal immutable _sand;\n Medianizer private immutable _medianizer;\n ERC20 private immutable _dai;\n address internal immutable _estate;\n\n address payable internal _wallet;\n uint256 internal immutable _expiryTime;\n bytes32 internal immutable _merkleRoot;\n\n bool _sandEnabled = false;\n bool _etherEnabled = true;\n bool _daiEnabled = false;\n\n event LandQuadPurchased(\n address indexed buyer,\n address indexed to,\n uint256 indexed topCornerId,\n uint256 size,\n uint256 price,\n address token,\n uint256 amountPaid\n );\n\n constructor(\n address landAddress,\n address sandContractAddress,\n address initialMetaTx,\n address admin,\n address payable initialWalletAddress,\n bytes32 merkleRoot,\n uint256 expiryTime,\n address medianizerContractAddress,\n address daiTokenContractAddress,\n address initialSigningWallet,\n uint256 initialMaxCommissionRate,\n address estate,\n address asset\n ) public ReferralValidator(initialSigningWallet, initialMaxCommissionRate) {\n _land = LandToken(landAddress);\n _sand = ERC20(sandContractAddress);\n _setMetaTransactionProcessor(initialMetaTx, true);\n _wallet = initialWalletAddress;\n _merkleRoot = merkleRoot;\n _expiryTime = expiryTime;\n _medianizer = Medianizer(medianizerContractAddress);\n _dai = ERC20(daiTokenContractAddress);\n _admin = admin;\n _estate = estate;\n _asset = ERC1155(asset);\n }\n\n /// @dev set the wallet receiving the proceeds\n /// @param newWallet address of the new receiving wallet\n function setReceivingWallet(address payable newWallet) external {\n require(newWallet != address(0), \"receiving wallet cannot be zero address\");\n require(msg.sender == _admin, \"only admin can change the receiving wallet\");\n _wallet = newWallet;\n }\n\n /// @dev enable/disable DAI payment for Lands\n /// @param enabled whether to enable or disable\n function setDAIEnabled(bool enabled) external {\n require(msg.sender == _admin, \"only admin can enable/disable DAI\");\n _daiEnabled = enabled;\n }\n\n /// @notice return whether DAI payments are enabled\n /// @return whether DAI payments are enabled\n function isDAIEnabled() external view returns (bool) {\n return _daiEnabled;\n }\n\n /// @notice enable/disable ETH payment for Lands\n /// @param enabled whether to enable or disable\n function setETHEnabled(bool enabled) external {\n require(msg.sender == _admin, \"only admin can enable/disable ETH\");\n _etherEnabled = enabled;\n }\n\n /// @notice return whether ETH payments are enabled\n /// @return whether ETH payments are enabled\n function isETHEnabled() external view returns (bool) {\n return _etherEnabled;\n }\n\n /// @dev enable/disable the specific SAND payment for Lands\n /// @param enabled whether to enable or disable\n function setSANDEnabled(bool enabled) external {\n require(msg.sender == _admin, \"only admin can enable/disable SAND\");\n _sandEnabled = enabled;\n }\n\n /// @notice return whether the specific SAND payments are enabled\n /// @return whether the specific SAND payments are enabled\n function isSANDEnabled() external view returns (bool) {\n return _sandEnabled;\n }\n\n function _checkValidity(\n address buyer,\n address reserved,\n uint256 x,\n uint256 y,\n uint256 size,\n uint256 price,\n bytes32 salt,\n uint256[] memory assetIds,\n bytes32[] memory proof\n ) internal view {\n /* solium-disable-next-line security/no-block-members */\n require(block.timestamp < _expiryTime, \"sale is over\");\n require(buyer == msg.sender || _metaTransactionContracts[msg.sender], \"not authorized\");\n require(reserved == address(0) || reserved == buyer, \"cannot buy reserved Land\");\n bytes32 leaf = _generateLandHash(x, y, size, price, reserved, salt, assetIds);\n\n require(_verify(proof, leaf), \"Invalid land provided\");\n }\n\n function _mint(\n address buyer,\n address to,\n uint256 x,\n uint256 y,\n uint256 size,\n uint256 price,\n address token,\n uint256 tokenAmount\n ) internal {\n if (size == 1 || _estate == address(0)) {\n _land.mintQuad(to, size, x, y, \"\");\n } else {\n _land.mintQuad(_estate, size, x, y, abi.encode(to));\n }\n emit LandQuadPurchased(buyer, to, x + (y * GRID_SIZE), size, price, token, tokenAmount);\n }\n\n /**\n * @notice buy Land with SAND using the merkle proof associated with it\n * @param buyer address that perform the payment\n * @param to address that will own the purchased Land\n * @param reserved the reserved address (if any)\n * @param x x coordinate of the Land\n * @param y y coordinate of the Land\n * @param size size of the pack of Land to purchase\n * @param priceInSand price in SAND to purchase that Land\n * @param proof merkleProof for that particular Land\n */\n function buyLandWithSand(\n address buyer,\n address to,\n address reserved,\n uint256 x,\n uint256 y,\n uint256 size,\n uint256 priceInSand,\n bytes32 salt,\n uint256[] calldata assetIds,\n bytes32[] calldata proof,\n bytes calldata referral\n ) external {\n require(_sandEnabled, \"sand payments not enabled\");\n _checkValidity(buyer, reserved, x, y, size, priceInSand, salt, assetIds, proof);\n\n handleReferralWithERC20(buyer, priceInSand, referral, _wallet, address(_sand));\n\n _mint(buyer, to, x, y, size, priceInSand, address(_sand), priceInSand);\n _sendAssets(to, assetIds);\n }\n\n /**\n * @notice buy Land with ETH using the merkle proof associated with it\n * @param buyer address that perform the payment\n * @param to address that will own the purchased Land\n * @param reserved the reserved address (if any)\n * @param x x coordinate of the Land\n * @param y y coordinate of the Land\n * @param size size of the pack of Land to purchase\n * @param priceInSand price in SAND to purchase that Land\n * @param proof merkleProof for that particular Land\n * @param referral the referral used by the buyer\n */\n function buyLandWithETH(\n address buyer,\n address to,\n address reserved,\n uint256 x,\n uint256 y,\n uint256 size,\n uint256 priceInSand,\n bytes32 salt,\n uint256[] calldata assetIds,\n bytes32[] calldata proof,\n bytes calldata referral\n ) external payable {\n require(_etherEnabled, \"ether payments not enabled\");\n _checkValidity(buyer, reserved, x, y, size, priceInSand, salt, assetIds, proof);\n\n uint256 ETHRequired = getEtherAmountWithSAND(priceInSand);\n require(msg.value >= ETHRequired, \"not enough ether sent\");\n\n if (msg.value - ETHRequired > 0) {\n msg.sender.transfer(msg.value - ETHRequired); // refund extra\n }\n\n handleReferralWithETH(ETHRequired, referral, _wallet);\n\n _mint(buyer, to, x, y, size, priceInSand, address(0), ETHRequired);\n _sendAssets(to, assetIds);\n }\n\n /**\n * @notice buy Land with DAI using the merkle proof associated with it\n * @param buyer address that perform the payment\n * @param to address that will own the purchased Land\n * @param reserved the reserved address (if any)\n * @param x x coordinate of the Land\n * @param y y coordinate of the Land\n * @param size size of the pack of Land to purchase\n * @param priceInSand price in SAND to purchase that Land\n * @param proof merkleProof for that particular Land\n */\n function buyLandWithDAI(\n address buyer,\n address to,\n address reserved,\n uint256 x,\n uint256 y,\n uint256 size,\n uint256 priceInSand,\n bytes32 salt,\n uint256[] calldata assetIds,\n bytes32[] calldata proof,\n bytes calldata referral\n ) external {\n require(_daiEnabled, \"dai payments not enabled\");\n _checkValidity(buyer, reserved, x, y, size, priceInSand, salt, assetIds, proof);\n\n uint256 DAIRequired = priceInSand.mul(daiPrice).div(1000000000000000000);\n\n handleReferralWithERC20(buyer, DAIRequired, referral, _wallet, address(_dai));\n\n _mint(buyer, to, x, y, size, priceInSand, address(_dai), DAIRequired);\n _sendAssets(to, assetIds);\n }\n\n /**\n * @notice Gets the expiry time for the current sale\n * @return The expiry time, as a unix epoch\n */\n function getExpiryTime() external view returns (uint256) {\n return _expiryTime;\n }\n\n /**\n * @notice Gets the Merkle root associated with the current sale\n * @return The Merkle root, as a bytes32 hash\n */\n function merkleRoot() external view returns (bytes32) {\n return _merkleRoot;\n }\n\n function _sendAssets(address to, uint256[] memory assetIds) internal {\n uint256[] memory values = new uint256[](assetIds.length);\n for (uint256 i = 0; i < assetIds.length; i++) {\n values[i] = 1;\n }\n _asset.safeBatchTransferFrom(address(this), to, assetIds, values, \"\");\n }\n\n function _generateLandHash(\n uint256 x,\n uint256 y,\n uint256 size,\n uint256 price,\n address reserved,\n bytes32 salt,\n uint256[] memory assetIds\n ) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(x, y, size, price, reserved, salt, assetIds));\n }\n\n function _verify(bytes32[] memory proof, bytes32 leaf) internal view returns (bool) {\n bytes32 computedHash = leaf;\n\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n\n if (computedHash < proofElement) {\n computedHash = keccak256(abi.encodePacked(computedHash, proofElement));\n } else {\n computedHash = keccak256(abi.encodePacked(proofElement, computedHash));\n }\n }\n\n return computedHash == _merkleRoot;\n }\n\n /**\n * @notice Returns the amount of ETH for a specific amount of SAND\n * @param sandAmount An amount of SAND\n * @return The amount of ETH\n */\n function getEtherAmountWithSAND(uint256 sandAmount) public view returns (uint256) {\n uint256 ethUsdPair = getEthUsdPair();\n return sandAmount.mul(daiPrice).div(ethUsdPair);\n }\n\n /**\n * @notice Gets the ETHUSD pair from the Medianizer contract\n * @return The pair as an uint256\n */\n function getEthUsdPair() internal view returns (uint256) {\n bytes32 pair = _medianizer.read();\n return uint256(pair);\n }\n\n function onERC1155Received(\n address, /*operator*/\n address, /*from*/\n uint256, /*id*/\n uint256, /*value*/\n bytes calldata /*data*/\n ) external pure returns (bytes4) {\n return 0xf23a6e61;\n }\n\n function onERC1155BatchReceived(\n address, /*operator*/\n address, /*from*/\n uint256[] calldata, /*ids*/\n uint256[] calldata, /*values*/\n bytes calldata /*data*/\n ) external pure returns (bytes4) {\n return 0xbc197c81;\n }\n\n function withdrawAssets(\n address to,\n uint256[] calldata assetIds,\n uint256[] calldata values\n ) external {\n require(msg.sender == _admin, \"NOT_AUTHORIZED\");\n require(block.timestamp > _expiryTime, \"SALE_NOT_OVER\");\n _asset.safeBatchTransferFrom(address(this), to, assetIds, values, \"\");\n }\n}\n"
},
"src/EstateSale/LandToken.sol": {
"content": "pragma solidity 0.6.5;\n\n\ninterface LandToken {\n function mintQuad(\n address to,\n uint256 size,\n uint256 x,\n uint256 y,\n bytes calldata data\n ) external;\n}\n"
},
"src/ReferralValidator/ReferralValidator.sol": {
"content": "/* solhint-disable not-rely-on-time, func-order */\npragma solidity 0.6.5;\n\nimport \"../contracts_common/src/Libraries/SigUtil.sol\";\nimport \"../contracts_common/src/Libraries/SafeMathWithRequire.sol\";\nimport \"../contracts_common/src/Interfaces/ERC20.sol\";\nimport \"../contracts_common/src/BaseWithStorage/Admin.sol\";\n\n\n/// @dev This contract verifies if a referral is valid\ncontract ReferralValidator is Admin {\n address private _signingWallet;\n uint256 private _maxCommissionRate;\n\n mapping(address => uint256) private _previousSigningWallets;\n uint256 private _previousSigningDelay = 60 * 60 * 24 * 10;\n\n event ReferralUsed(\n address indexed referrer,\n address indexed referee,\n address indexed token,\n uint256 amount,\n uint256 commission,\n uint256 commissionRate\n );\n\n constructor(address initialSigningWallet, uint256 initialMaxCommissionRate) public {\n _signingWallet = initialSigningWallet;\n _maxCommissionRate = initialMaxCommissionRate;\n }\n\n /**\n * @dev Update the signing wallet\n * @param newSigningWallet The new address of the signing wallet\n */\n function updateSigningWallet(address newSigningWallet) external {\n require(_admin == msg.sender, \"Sender not admin\");\n _previousSigningWallets[_signingWallet] = now + _previousSigningDelay;\n _signingWallet = newSigningWallet;\n }\n\n /**\n * @dev signing wallet authorized for referral\n * @return the address of the signing wallet\n */\n function getSigningWallet() external view returns (address) {\n return _signingWallet;\n }\n\n /**\n * @notice the max commision rate\n * @return the maximum commision rate that a referral can give\n */\n function getMaxCommisionRate() external view returns (uint256) {\n return _maxCommissionRate;\n }\n\n /**\n * @dev Update the maximum commission rate\n * @param newMaxCommissionRate The new maximum commission rate\n */\n function updateMaxCommissionRate(uint256 newMaxCommissionRate) external {\n require(_admin == msg.sender, \"Sender not admin\");\n _maxCommissionRate = newMaxCommissionRate;\n }\n\n function handleReferralWithETH(\n uint256 amount,\n bytes memory referral,\n address payable destination\n ) internal {\n uint256 amountForDestination = amount;\n\n if (referral.length > 0) {\n (bytes memory signature, address referrer, address referee, uint256 expiryTime, uint256 commissionRate) = decodeReferral(referral);\n\n uint256 commission = 0;\n\n if (isReferralValid(signature, referrer, referee, expiryTime, commissionRate)) {\n commission = SafeMathWithRequire.div(SafeMathWithRequire.mul(amount, commissionRate), 10000);\n\n emit ReferralUsed(referrer, referee, address(0), amount, commission, commissionRate);\n amountForDestination = SafeMathWithRequire.sub(amountForDestination, commission);\n }\n\n if (commission > 0) {\n address(uint160(referrer)).transfer(commission);\n }\n }\n\n destination.transfer(amountForDestination);\n }\n\n function handleReferralWithERC20(\n address buyer,\n uint256 amount,\n bytes memory referral,\n address payable destination,\n address tokenAddress\n ) internal {\n ERC20 token = ERC20(tokenAddress);\n uint256 amountForDestination = amount;\n\n if (referral.length > 0) {\n (bytes memory signature, address referrer, address referee, uint256 expiryTime, uint256 commissionRate) = decodeReferral(referral);\n\n uint256 commission = 0;\n\n if (isReferralValid(signature, referrer, referee, expiryTime, commissionRate)) {\n commission = SafeMathWithRequire.div(SafeMathWithRequire.mul(amount, commissionRate), 10000);\n\n emit ReferralUsed(referrer, referee, tokenAddress, amount, commission, commissionRate);\n amountForDestination = SafeMathWithRequire.sub(amountForDestination, commission);\n }\n\n if (commission > 0) {\n require(token.transferFrom(buyer, referrer, commission), \"commision transfer failed\");\n }\n }\n\n require(token.transferFrom(buyer, destination, amountForDestination), \"payment transfer failed\");\n }\n\n /**\n * @notice Check if a referral is valid\n * @param signature The signature to check (signed referral)\n * @param referrer The address of the referrer\n * @param referee The address of the referee\n * @param expiryTime The expiry time of the referral\n * @param commissionRate The commissionRate of the referral\n * @return True if the referral is valid\n */\n function isReferralValid(\n bytes memory signature,\n address referrer,\n address referee,\n uint256 expiryTime,\n uint256 commissionRate\n ) public view returns (bool) {\n if (commissionRate > _maxCommissionRate || referrer == referee || now > expiryTime) {\n return false;\n }\n\n bytes32 hashedData = keccak256(abi.encodePacked(referrer, referee, expiryTime, commissionRate));\n\n address signer = SigUtil.recover(keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hashedData)), signature);\n\n if (_previousSigningWallets[signer] >= now) {\n return true;\n }\n\n return _signingWallet == signer;\n }\n\n function decodeReferral(bytes memory referral)\n public\n pure\n returns (\n bytes memory,\n address,\n address,\n uint256,\n uint256\n )\n {\n (bytes memory signature, address referrer, address referee, uint256 expiryTime, uint256 commissionRate) = abi.decode(\n referral,\n (bytes, address, address, uint256, uint256)\n );\n\n return (signature, referrer, referee, expiryTime, commissionRate);\n }\n}\n"
},
"src/metatx/MetaTxWrapper.sol": {
"content": "pragma solidity 0.6.5;\n\n\ncontract MetaTxWrapper {\n address internal immutable _forwardTo;\n address internal immutable _forwarder;\n\n constructor(address forwarder, address forwardTo) public {\n _forwardTo = forwardTo;\n _forwarder = forwarder;\n }\n\n fallback() external {\n require(msg.sender == _forwarder, \"can only be called by a forwarder\");\n bytes memory data = msg.data;\n uint256 length = msg.data.length;\n\n address signer;\n assembly {\n signer := and(mload(sub(add(data, length), 0x00)), 0xffffffffffffffffffffffffffffffffffffffff)\n }\n\n uint256 firstParam;\n assembly {\n firstParam := and(mload(data), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)\n }\n require(uint256(signer) == firstParam, \"firstParam is not signer\");\n\n /*\n assembly {\n calldatacopy(0, 0, calldatasize())\n let result := call(gas(), _forwardTo, 0, calldatasize(), 0, 0)\n returndatacopy(0, 0, returndatasize())\n switch result\n case 0 {\n revert(0, returndatasize())\n }\n default {\n return(0, returndatasize())\n }\n }\n */\n }\n}\n"
},
"src/P2PERC721Sale/P2PERC721Sale.sol": {
"content": "pragma solidity 0.6.5;\npragma experimental ABIEncoderV2;\n\nimport \"../contracts_common/src/BaseWithStorage/Admin.sol\";\nimport \"../contracts_common/src/Libraries/SigUtil.sol\";\nimport \"../contracts_common/src/Libraries/PriceUtil.sol\";\nimport \"../contracts_common/src/BaseWithStorage/MetaTransactionReceiver.sol\";\nimport \"../contracts_common/src/Interfaces/ERC721.sol\";\nimport \"../contracts_common/src/Interfaces/ERC20.sol\";\nimport \"../contracts_common/src/Interfaces/ERC1271.sol\";\nimport \"../contracts_common/src/Interfaces/ERC1271Constants.sol\";\nimport \"../contracts_common/src/Interfaces/ERC1654.sol\";\nimport \"../contracts_common/src/Interfaces/ERC1654Constants.sol\";\nimport \"../contracts_common/src/Libraries/SafeMathWithRequire.sol\";\n\nimport \"../Base/TheSandbox712.sol\";\n\n\ncontract P2PERC721Sale is Admin, ERC1654Constants, ERC1271Constants, TheSandbox712, MetaTransactionReceiver {\n using SafeMathWithRequire for uint256;\n\n enum SignatureType {DIRECT, EIP1654, EIP1271}\n\n mapping(address => mapping(uint256 => uint256)) public claimed;\n\n uint256 private constant MAX_UINT256 = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\n ERC20 internal _sand;\n uint256 internal _fee;\n address internal _feeCollector;\n\n struct Auction {\n uint256 id;\n address tokenAddress; // TODO support bundle : tokenAddress and tokenId should be arrays\n uint256 tokenId;\n address seller;\n uint256 startingPrice; // TODO support any ERC20 or ethereum as payment\n uint256 endingPrice;\n uint256 startedAt;\n uint256 duration;\n }\n\n event OfferClaimed(\n address indexed seller,\n address indexed buyer,\n uint256 indexed offerId,\n address tokenAddress,\n uint256 tokenId,\n uint256 pricePaid,\n uint256 feePaid\n );\n\n event OfferCancelled(address indexed seller, uint256 indexed offerId);\n\n event FeeSetup(address feeCollector, uint256 fee10000th);\n\n constructor(\n address sand,\n address admin,\n address feeCollector,\n uint256 fee,\n address initialMetaTx\n ) public {\n _sand = ERC20(sand);\n _admin = admin;\n\n _fee = fee;\n _feeCollector = feeCollector;\n emit FeeSetup(feeCollector, fee);\n\n _setMetaTransactionProcessor(initialMetaTx, true);\n init712();\n }\n\n function setFee(address feeCollector, uint256 fee) external {\n require(msg.sender == _admin, \"Sender not admin\");\n _feeCollector = feeCollector;\n _fee = fee;\n emit FeeSetup(feeCollector, fee);\n }\n\n function _verifyParameters(address buyer, Auction memory auction) internal view {\n require(buyer == msg.sender || _metaTransactionContracts[msg.sender], \"not authorized\"); // if support any ERC20 :(token != address(0) &&\n\n require(claimed[auction.seller][auction.id] != MAX_UINT256, \"Auction canceled\");\n\n require(auction.startedAt <= now, \"Auction has not started yet\");\n\n require(auction.startedAt.add(auction.duration) > now, \"Auction finished\");\n }\n\n function claimSellerOffer(\n address buyer,\n address to,\n Auction calldata auction,\n bytes calldata signature,\n SignatureType signatureType,\n bool eip712\n ) external {\n _verifyParameters(buyer, auction);\n _ensureCorrectSigner(auction, signature, signatureType, eip712);\n _executeDeal(auction, buyer, to);\n }\n\n function _executeDeal(\n Auction memory auction,\n address buyer,\n address to\n ) internal {\n uint256 offer = PriceUtil.calculateCurrentPrice(auction.startingPrice, auction.endingPrice, auction.duration, now.sub(auction.startedAt));\n\n claimed[auction.seller][auction.id] = offer;\n\n uint256 fee = 0;\n\n if (_fee > 0) {\n fee = PriceUtil.calculateFee(offer, _fee);\n }\n\n require(_sand.transferFrom(buyer, auction.seller, offer.sub(fee)), \"Funds transfer failed\"); // TODO feeCollector\n\n ERC721 token = ERC721(auction.tokenAddress);\n\n token.safeTransferFrom(auction.seller, to, auction.tokenId); // TODO test safeTransferFrom fail\n }\n\n function cancelSellerOffer(uint256 id) external {\n claimed[msg.sender][id] = MAX_UINT256;\n emit OfferCancelled(msg.sender, id);\n }\n\n function _ensureCorrectSigner(\n Auction memory auction,\n bytes memory signature,\n SignatureType signatureType,\n bool eip712\n ) internal view returns (address) {\n bytes memory dataToHash;\n\n if (eip712) {\n dataToHash = abi.encodePacked(\"\\x19\\x01\", domainSeparator(), _hashAuction(auction));\n } else {\n dataToHash = _encodeBasicSignatureHash(auction);\n }\n\n if (signatureType == SignatureType.EIP1271) {\n require(ERC1271(auction.seller).isValidSignature(dataToHash, signature) == ERC1271_MAGICVALUE, \"Invalid 1271 sig\");\n } else if (signatureType == SignatureType.EIP1654) {\n require(ERC1654(auction.seller).isValidSignature(keccak256(dataToHash), signature) == ERC1654_MAGICVALUE, \"Invalid 1654 sig\");\n } else {\n address signer = SigUtil.recover(keccak256(dataToHash), signature);\n require(signer == auction.seller, \"Invalid sig\");\n }\n }\n\n function _encodeBasicSignatureHash(Auction memory auction) internal view returns (bytes memory) {\n return\n SigUtil.prefixed(\n keccak256(\n abi.encodePacked(\n address(this),\n auction.id,\n auction.tokenAddress,\n auction.tokenId,\n auction.seller,\n auction.startingPrice,\n auction.endingPrice,\n auction.startedAt,\n auction.duration\n )\n )\n );\n }\n\n function _hashAuction(Auction memory auction) internal pure returns (bytes32) {\n return\n keccak256(\n abi.encode(\n auction.id,\n auction.tokenAddress,\n auction.tokenId,\n auction.seller,\n auction.startingPrice,\n auction.endingPrice,\n auction.startedAt,\n auction.duration\n )\n );\n }\n}\n"
}
},
"settings": {
"metadata": {
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 2000
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": ["id", "ast"]
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment