Transaction Hash:
Block:
8857553 at Nov-02-2019 07:11:47 AM +UTC
Transaction Fee:
0.001162315 ETH
$2.92
Gas Used:
232,463 Gas / 5 Gwei
Emitted Events:
79 |
CodexRecordProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x0000000000000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000d1898665a01a91ac10bd2c6cb1899336df34ac33, 0x00000000000000000000000000000000000000000000000000000000000166d7 )
|
80 |
CodexRecordProxy.0x9573133e4bf0477d257d5e746e10de577953ee706da897be78cf668a64c16a16( 0x9573133e4bf0477d257d5e746e10de577953ee706da897be78cf668a64c16a16, 00000000000000000000000000000000000000000000000000000000000166d7, 0000000000000000000000000000000000000000000000000000000000000040, 000000000000000000000000000000000000000000000000000000000000001f, 636f6465783a3a35646264326331636235643564633637353337396462333400 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x8853B058...FA43d2a79 | |||||
0xAA5c4244...ba1aCF05E
Miner
| 44,589.092399706352163263 Eth | 44,589.093562021352163263 Eth | 0.001162315 | ||
0xD1898665...6df34AC33 |
0.133134749382485849 Eth
Nonce: 58
|
0.131972434382485849 Eth
Nonce: 59
| 0.001162315 |
Execution Trace
CodexRecordProxy.ee5301d5( )

-
CodexRecord.mint( )
mint[CodexRecordCore (ln:1112)]
CodexRecordData[CodexRecordCore (ln:1126)]
Minted[CodexRecordCore (ln:1132)]
File 1 of 2: CodexRecordProxy
File 2 of 2: CodexRecord
pragma solidity 0.4.24; // File: contracts/ERC165/ERC165.sol /** * @dev A standard for detecting smart contract interfaces. * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md */ contract ERC165 { // bytes4(keccak256('supportsInterface(bytes4)')); bytes4 constant INTERFACE_ERC165 = 0x01ffc9a7; /** * @dev Checks if the smart contract includes a specific interface. * @param _interfaceID The interface identifier, as specified in ERC-165. */ function supportsInterface(bytes4 _interfaceID) public pure returns (bool) { return _interfaceID == INTERFACE_ERC165; } } // File: contracts/ERC721/ERC721Basic.sol /** * @title ERC721 Non-Fungible Token Standard basic interface * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md */ contract ERC721Basic { // bytes4(keccak256('balanceOf(address)')) ^ // bytes4(keccak256('ownerOf(uint256)')) ^ // bytes4(keccak256('approve(address,uint256)')) ^ // bytes4(keccak256('getApproved(uint256)')) ^ // bytes4(keccak256('setApprovalForAll(address,bool)')) ^ // bytes4(keccak256('isApprovedForAll(address,address)')) ^ // bytes4(keccak256('transferFrom(address,address,uint256)')) ^ // bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^ // bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')); bytes4 constant INTERFACE_ERC721 = 0x80ac58cd; event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); event ApprovalForAll(address indexed _owner, address indexed _operator, bool indexed _approved); function balanceOf(address _owner) public view returns (uint256 _balance); function ownerOf(uint256 _tokenId) public view returns (address _owner); // Note: This is not in the official ERC-721 standard so it's not included in the interface hash function exists(uint256 _tokenId) public view returns (bool _exists); function approve(address _to, uint256 _tokenId) public; function getApproved(uint256 _tokenId) public view returns (address _operator); function setApprovalForAll(address _operator, bool _approved) public; function isApprovedForAll(address _owner, address _operator) public view returns (bool); function transferFrom( address _from, address _to, uint256 _tokenId) public; function safeTransferFrom( address _from, address _to, uint256 _tokenId) public; function safeTransferFrom( address _from, address _to, uint256 _tokenId, bytes _data) public; } // File: contracts/ERC721/ERC721.sol /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md */ contract ERC721Enumerable is ERC721Basic { // bytes4(keccak256('totalSupply()')) ^ // bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) ^ // bytes4(keccak256('tokenByIndex(uint256)')); bytes4 constant INTERFACE_ERC721_ENUMERABLE = 0x780e9d63; function totalSupply() public view returns (uint256); function tokenOfOwnerByIndex(address _owner, uint256 _index) public view returns (uint256 _tokenId); function tokenByIndex(uint256 _index) public view returns (uint256); } /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md */ contract ERC721Metadata is ERC721Basic { // bytes4(keccak256('name()')) ^ // bytes4(keccak256('symbol()')) ^ // bytes4(keccak256('tokenURI(uint256)')); bytes4 constant INTERFACE_ERC721_METADATA = 0x5b5e139f; function name() public view returns (string _name); function symbol() public view returns (string _symbol); function tokenURI(uint256 _tokenId) public view returns (string); } /** * @title ERC-721 Non-Fungible Token Standard, full implementation interface * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md */ /* solium-disable-next-line no-empty-blocks */ contract ERC721 is ERC721Basic, ERC721Enumerable, ERC721Metadata { } // File: contracts/library/ProxyOwnable.sol /** * @title ProxyOwnable * @dev Essentially the Ownable contract, renamed for the purposes of separating it from the * DelayedOwnable contract (the owner of the token contract). */ contract ProxyOwnable { address public proxyOwner; event ProxyOwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `proxyOwner` of the contract to the sender * account. */ constructor() public { proxyOwner = msg.sender; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(msg.sender == proxyOwner); _; } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param _newOwner The address to transfer ownership to. */ function transferProxyOwnership(address _newOwner) public onlyOwner { require(_newOwner != address(0)); emit ProxyOwnershipTransferred(proxyOwner, _newOwner); proxyOwner = _newOwner; } } // File: contracts/CodexRecordProxy.sol /** * @title CodexRecordProxy, a proxy contract for token storage * @dev This allows the token owner to optionally upgrade the token in the future * if there are changes needed in the business logic. See the upgradeTo function * for caveats. * Based on MIT licensed code from * https://github.com/zeppelinos/labs/tree/master/upgradeability_using_inherited_storage */ contract CodexRecordProxy is ProxyOwnable { event Upgraded(string version, address indexed implementation); string public version; address public implementation; constructor(address _implementation) public { upgradeTo("1", _implementation); } /** * @dev Fallback function. Any transaction sent to this contract that doesn't match the * upgradeTo signature will fallback to this function, which in turn will use * DELEGATECALL to delegate the transaction data to the implementation. */ function () payable public { address _implementation = implementation; // solium-disable-next-line security/no-inline-assembly assembly { let ptr := mload(0x40) calldatacopy(ptr, 0, calldatasize) let result := delegatecall(gas, _implementation, ptr, calldatasize, 0, 0) let size := returndatasize returndatacopy(ptr, 0, size) switch result case 0 { revert(ptr, size) } default { return(ptr, size) } } } /** * @dev Since name is passed into the ERC721 token constructor, it's not stored in the CodexRecordProxy * contract. Thus, we call into the contract directly to retrieve its value. * @return string The name of the token */ function name() external view returns (string) { ERC721Metadata tokenMetadata = ERC721Metadata(implementation); return tokenMetadata.name(); } /** * @dev Since symbol is passed into the ERC721 token constructor, it's not stored in the CodexRecordProxy * contract. Thus, we call into the contract directly to retrieve its value. * @return string The symbol of token */ function symbol() external view returns (string) { ERC721Metadata tokenMetadata = ERC721Metadata(implementation); return tokenMetadata.symbol(); } /** * @dev Upgrades the CodexRecordProxy to point at a new implementation. Only callable by the owner. * Only upgrade the token after extensive testing has been done. The storage is append only. * The new token must inherit from the previous token so the shape of the storage is maintained. * @param _version The version of the token * @param _implementation The address at which the implementation is available */ function upgradeTo(string _version, address _implementation) public onlyOwner { require( keccak256(abi.encodePacked(_version)) != keccak256(abi.encodePacked(version)), "The version cannot be the same"); require( _implementation != implementation, "The implementation cannot be the same"); require( _implementation != address(0), "The implementation cannot be the 0 address"); version = _version; implementation = _implementation; emit Upgraded(version, implementation); } }
File 2 of 2: CodexRecord
pragma solidity 0.4.24; // File: contracts/ERC20/ERC20Basic.sol /** * @title ERC20Basic * @dev Simpler version of ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/179 */ contract ERC20Basic { function totalSupply() public view returns (uint256); function balanceOf(address who) public view returns (uint256); function transfer(address to, uint256 value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } // File: contracts/ERC20/ERC20.sol /** * @title ERC20 interface * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md */ contract ERC20 is ERC20Basic { function allowance(address owner, address spender) public view returns (uint256); function transferFrom(address from, address to, uint256 value) public returns (bool); function approve(address spender, uint256 value) public returns (bool); event Approval(address indexed owner, address indexed spender, uint256 value); } // File: contracts/ERC721/ERC721Basic.sol /** * @title ERC721 Non-Fungible Token Standard basic interface * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md */ contract ERC721Basic { // bytes4(keccak256('balanceOf(address)')) ^ // bytes4(keccak256('ownerOf(uint256)')) ^ // bytes4(keccak256('approve(address,uint256)')) ^ // bytes4(keccak256('getApproved(uint256)')) ^ // bytes4(keccak256('setApprovalForAll(address,bool)')) ^ // bytes4(keccak256('isApprovedForAll(address,address)')) ^ // bytes4(keccak256('transferFrom(address,address,uint256)')) ^ // bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^ // bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')); bytes4 constant INTERFACE_ERC721 = 0x80ac58cd; event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); event ApprovalForAll(address indexed _owner, address indexed _operator, bool indexed _approved); function balanceOf(address _owner) public view returns (uint256 _balance); function ownerOf(uint256 _tokenId) public view returns (address _owner); // Note: This is not in the official ERC-721 standard so it's not included in the interface hash function exists(uint256 _tokenId) public view returns (bool _exists); function approve(address _to, uint256 _tokenId) public; function getApproved(uint256 _tokenId) public view returns (address _operator); function setApprovalForAll(address _operator, bool _approved) public; function isApprovedForAll(address _owner, address _operator) public view returns (bool); function transferFrom( address _from, address _to, uint256 _tokenId) public; function safeTransferFrom( address _from, address _to, uint256 _tokenId) public; function safeTransferFrom( address _from, address _to, uint256 _tokenId, bytes _data) public; } // File: contracts/ERC721/ERC721.sol /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md */ contract ERC721Enumerable is ERC721Basic { // bytes4(keccak256('totalSupply()')) ^ // bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) ^ // bytes4(keccak256('tokenByIndex(uint256)')); bytes4 constant INTERFACE_ERC721_ENUMERABLE = 0x780e9d63; function totalSupply() public view returns (uint256); function tokenOfOwnerByIndex(address _owner, uint256 _index) public view returns (uint256 _tokenId); function tokenByIndex(uint256 _index) public view returns (uint256); } /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md */ contract ERC721Metadata is ERC721Basic { // bytes4(keccak256('name()')) ^ // bytes4(keccak256('symbol()')) ^ // bytes4(keccak256('tokenURI(uint256)')); bytes4 constant INTERFACE_ERC721_METADATA = 0x5b5e139f; function name() public view returns (string _name); function symbol() public view returns (string _symbol); function tokenURI(uint256 _tokenId) public view returns (string); } /** * @title ERC-721 Non-Fungible Token Standard, full implementation interface * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md */ /* solium-disable-next-line no-empty-blocks */ contract ERC721 is ERC721Basic, ERC721Enumerable, ERC721Metadata { } // File: contracts/ERC165/ERC165.sol /** * @dev A standard for detecting smart contract interfaces. * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md */ contract ERC165 { // bytes4(keccak256('supportsInterface(bytes4)')); bytes4 constant INTERFACE_ERC165 = 0x01ffc9a7; /** * @dev Checks if the smart contract includes a specific interface. * @param _interfaceID The interface identifier, as specified in ERC-165. */ function supportsInterface(bytes4 _interfaceID) public pure returns (bool) { return _interfaceID == INTERFACE_ERC165; } } // File: contracts/library/AddressUtils.sol /** * @title Utility library of inline functions on addresses */ library AddressUtils { /** * @notice Returns whether there is code in the target address * @dev This function will return false if invoked during the constructor of a contract, * as the code is not actually created until after the constructor finishes. * @param addr address address to check * @return whether there is code in the target address */ function isContract(address addr) internal view returns (bool) { uint256 size; // solium-disable-next-line security/no-inline-assembly assembly { size := extcodesize(addr) } return size > 0; } } // File: contracts/library/SafeMath.sol /** * @title SafeMath * @dev Math operations with safety checks that throw on error */ library SafeMath { /** * @dev Multiplies two numbers, throws on overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { // Gas optimization: this is cheaper than asserting 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (a == 0) { return 0; } c = a * b; assert(c / a == b); return c; } /** * @dev Integer division of two numbers, truncating the quotient. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // assert(b > 0); // Solidity automatically throws when dividing by 0 // uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return a / b; } /** * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); return a - b; } /** * @dev Adds two numbers, throws on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256 c) { c = a + b; assert(c >= a); return c; } } // File: contracts/ERC721/ERC721Receiver.sol /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ contract ERC721Receiver { /** * @dev Magic value to be returned upon successful reception of an NFT * Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`, * which can be also obtained as `ERC721Receiver(0).onERC721Received.selector` */ bytes4 constant ERC721_RECEIVED = 0x150b7a02; /** * @notice Handle the receipt of an NFT * @dev The ERC721 smart contract calls this function on the recipient * after a `safetransfer`. This function MAY throw to revert and reject the * transfer. Returns other than the magic value MUST result in the * transaction being reverted. * Note: the contract address is always the message sender. * @param _from The sending address * @param _tokenId The NFT identifier which is being transfered * @param _data Additional data with no specified format * @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` */ function onERC721Received( address _operator, address _from, uint256 _tokenId, bytes _data) public returns(bytes4); } // File: contracts/ERC721/ERC721BasicToken.sol /** * @title ERC721 Non-Fungible Token Standard basic implementation * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md */ contract ERC721BasicToken is ERC721Basic, ERC165 { using SafeMath for uint256; using AddressUtils for address; // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` // which can be also obtained as `ERC721Receiver(0).onERC721Received.selector` bytes4 constant ERC721_RECEIVED = 0x150b7a02; // Mapping from token ID to owner mapping (uint256 => address) internal tokenOwner; // Mapping from token ID to approved address mapping (uint256 => address) internal tokenApprovals; // Mapping from owner to number of owned token mapping (address => uint256) internal ownedTokensCount; // Mapping from owner to operator approvals mapping (address => mapping (address => bool)) internal operatorApprovals; /** * @dev Guarantees msg.sender is owner of the given token * @param _tokenId uint256 ID of the token to validate its ownership belongs to msg.sender */ modifier onlyOwnerOf(uint256 _tokenId) { require(ownerOf(_tokenId) == msg.sender); _; } /** * @dev Checks if the smart contract includes a specific interface. * @param _interfaceID The interface identifier, as specified in ERC-165. */ function supportsInterface(bytes4 _interfaceID) public pure returns (bool) { return super.supportsInterface(_interfaceID) || _interfaceID == INTERFACE_ERC721; } /** * @dev Gets the balance of the specified address * @param _owner address to query the balance of * @return uint256 representing the amount owned by the passed address */ function balanceOf(address _owner) public view returns (uint256) { require(_owner != address(0)); return ownedTokensCount[_owner]; } /** * @dev Gets the owner of the specified token ID * @param _tokenId uint256 ID of the token to query the owner of * @return owner address currently marked as the owner of the given token ID */ function ownerOf(uint256 _tokenId) public view returns (address) { address owner = tokenOwner[_tokenId]; require(owner != address(0)); return owner; } /** * @dev Returns whether the specified token exists * @param _tokenId uint256 ID of the token to query the existance of * @return whether the token exists */ function exists(uint256 _tokenId) public view returns (bool) { address owner = tokenOwner[_tokenId]; return owner != address(0); } /** * @dev Approves another address to transfer the given token ID * @dev The zero address indicates there is no approved address. * @dev There can only be one approved address per token at a given time. * @dev Can only be called by the token owner or an approved operator. * @param _to address to be approved for the given token ID * @param _tokenId uint256 ID of the token to be approved */ function approve(address _to, uint256 _tokenId) public { address owner = ownerOf(_tokenId); require(_to != owner); require(msg.sender == owner || isApprovedForAll(owner, msg.sender)); if (getApproved(_tokenId) != address(0) || _to != address(0)) { tokenApprovals[_tokenId] = _to; emit Approval(owner, _to, _tokenId); } } /** * @dev Gets the approved address for a token ID, or zero if no address set * @param _tokenId uint256 ID of the token to query the approval of * @return address currently approved for a the given token ID */ function getApproved(uint256 _tokenId) public view returns (address) { return tokenApprovals[_tokenId]; } /** * @dev Sets or unsets the approval of a given operator * @dev An operator is allowed to transfer all tokens of the sender on their behalf * @param _to operator address to set the approval * @param _approved representing the status of the approval to be set */ function setApprovalForAll(address _to, bool _approved) public { require(_to != msg.sender); operatorApprovals[msg.sender][_to] = _approved; emit ApprovalForAll(msg.sender, _to, _approved); } /** * @dev Tells whether an operator is approved by a given owner * @param _owner owner address which you want to query the approval of * @param _operator operator address which you want to query the approval of * @return bool whether the given operator is approved by the given owner */ function isApprovedForAll(address _owner, address _operator) public view returns (bool) { return operatorApprovals[_owner][_operator]; } /** * @dev Transfers the ownership of a given token ID to another address * @dev Usage of this method is discouraged, use `safeTransferFrom` whenever possible * @dev Requires the msg sender to be the owner, approved, or operator * @param _from current owner of the token * @param _to address to receive the ownership of the given token ID * @param _tokenId uint256 ID of the token to be transferred */ function transferFrom( address _from, address _to, uint256 _tokenId ) public { internalTransferFrom( _from, _to, _tokenId); } /** * @dev Safely transfers the ownership of a given token ID to another address * @dev If the target address is a contract, it must implement `onERC721Received`, * which is called upon a safe transfer, and return the magic value * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, * the transfer is reverted. * @dev Requires the msg sender to be the owner, approved, or operator * @param _from current owner of the token * @param _to address to receive the ownership of the given token ID * @param _tokenId uint256 ID of the token to be transferred */ function safeTransferFrom( address _from, address _to, uint256 _tokenId ) public { internalSafeTransferFrom( _from, _to, _tokenId, ""); } /** * @dev Safely transfers the ownership of a given token ID to another address * @dev If the target address is a contract, it must implement `onERC721Received`, * which is called upon a safe transfer, and return the magic value * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, * the transfer is reverted. * @dev Requires the msg sender to be the owner, approved, or operator * @param _from current owner of the token * @param _to address to receive the ownership of the given token ID * @param _tokenId uint256 ID of the token to be transferred * @param _data bytes data to send along with a safe transfer check */ function safeTransferFrom( address _from, address _to, uint256 _tokenId, bytes _data ) public { internalSafeTransferFrom( _from, _to, _tokenId, _data); } function internalTransferFrom( address _from, address _to, uint256 _tokenId ) internal { address owner = ownerOf(_tokenId); require(_from == owner); require(_to != address(0)); address sender = msg.sender; require( sender == owner || isApprovedForAll(owner, sender) || getApproved(_tokenId) == sender, "Not authorized to transfer" ); // Resetting the approved address if it's set if (tokenApprovals[_tokenId] != address(0)) { tokenApprovals[_tokenId] = address(0); } tokenOwner[_tokenId] = _to; ownedTokensCount[_from] = ownedTokensCount[_from].sub(1); ownedTokensCount[_to] = ownedTokensCount[_to].add(1); emit Transfer(_from, _to, _tokenId); } function internalSafeTransferFrom( address _from, address _to, uint256 _tokenId, bytes _data ) internal { internalTransferFrom(_from, _to, _tokenId); require( checkAndCallSafeTransfer( _from, _to, _tokenId, _data) ); } /** * @dev Internal function to invoke `onERC721Received` on a target address * @dev The call is not executed if the target address is not a contract * @param _from address representing the previous owner of the given token ID * @param _to target address that will receive the tokens * @param _tokenId uint256 ID of the token to be transferred * @param _data bytes optional data to send along with the call * @return whether the call correctly returned the expected magic value */ function checkAndCallSafeTransfer( address _from, address _to, uint256 _tokenId, bytes _data ) internal returns (bool) { if (!_to.isContract()) { return true; } bytes4 retval = ERC721Receiver(_to) .onERC721Received( msg.sender, _from, _tokenId, _data ); return (retval == ERC721_RECEIVED); } } // File: contracts/ERC721/ERC721Token.sol /** * @title Full ERC721 Token * This implementation includes all the required and some optional functionality of the ERC721 standard * Moreover, it includes approve all functionality using operator terminology * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md */ contract ERC721Token is ERC721, ERC721BasicToken { // Token name string internal name_; // Token symbol string internal symbol_; // Mapping from owner to list of owned token IDs mapping (address => uint256[]) internal ownedTokens; // Mapping from token ID to index of the owner tokens list mapping(uint256 => uint256) internal ownedTokensIndex; // Array with all token ids, used for enumeration uint256[] internal allTokens; // Optional mapping for token URIs mapping(uint256 => string) internal tokenURIs; /** * @dev Constructor function */ constructor(string _name, string _symbol) public { name_ = _name; symbol_ = _symbol; } /** * @dev Checks if the smart contract includes a specific interface. * @param _interfaceID The interface identifier, as specified in ERC-165. */ function supportsInterface(bytes4 _interfaceID) public pure returns (bool) { return super.supportsInterface(_interfaceID) || _interfaceID == INTERFACE_ERC721_ENUMERABLE || _interfaceID == INTERFACE_ERC721_METADATA; } /** * @dev Gets the token name * @return string representing the token name */ function name() public view returns (string) { return name_; } /** * @dev Gets the token symbol * @return string representing the token symbol */ function symbol() public view returns (string) { return symbol_; } /** * @dev Returns an URI for a given token ID * @dev Throws if the token ID does not exist. May return an empty string. * @param _tokenId uint256 ID of the token to query */ function tokenURI(uint256 _tokenId) public view returns (string) { require(exists(_tokenId)); return tokenURIs[_tokenId]; } /** * @dev Gets the token ID at a given index of the tokens list of the requested owner * @param _owner address owning the tokens list to be accessed * @param _index uint256 representing the index to be accessed of the requested tokens list * @return uint256 token ID at the given index of the tokens list owned by the requested address */ function tokenOfOwnerByIndex(address _owner, uint256 _index) public view returns (uint256) { require(_index < balanceOf(_owner)); return ownedTokens[_owner][_index]; } /** * @dev Gets the total amount of tokens stored by the contract * @return uint256 representing the total amount of tokens */ function totalSupply() public view returns (uint256) { return allTokens.length; } /** * @dev Gets the token ID at a given index of all the tokens in this contract * @dev Reverts if the index is greater or equal to the total number of tokens * @param _index uint256 representing the index to be accessed of the tokens list * @return uint256 token ID at the given index of the tokens list */ function tokenByIndex(uint256 _index) public view returns (uint256) { require(_index < totalSupply()); return allTokens[_index]; } function internalTransferFrom( address _from, address _to, uint256 _tokenId ) internal { super.internalTransferFrom(_from, _to, _tokenId); uint256 removeTokenIndex = ownedTokensIndex[_tokenId]; uint256 lastTokenIndex = ownedTokens[_from].length.sub(1); uint256 lastToken = ownedTokens[_from][lastTokenIndex]; ownedTokens[_from][removeTokenIndex] = lastToken; ownedTokens[_from].length--; ownedTokensIndex[lastToken] = removeTokenIndex; ownedTokens[_to].push(_tokenId); ownedTokensIndex[_tokenId] = ownedTokens[_to].length - 1; } /** * @dev Internal function to set the token URI for a given token * @dev Reverts if the token ID does not exist * @param _tokenId uint256 ID of the token to set its URI * @param _uri string URI to assign */ function _setTokenURI(uint256 _tokenId, string _uri) internal { require(exists(_tokenId)); tokenURIs[_tokenId] = _uri; } } // File: contracts/CodexRecordMetadata.sol /** * @title CodexRecordMetadata * @dev Storage, mutators, and modifiers for CodexRecord metadata. */ contract CodexRecordMetadata is ERC721Token { struct CodexRecordData { bytes32 nameHash; bytes32 descriptionHash; bytes32[] fileHashes; } event Modified( address indexed _from, uint256 _tokenId, bytes32 _newNameHash, bytes32 _newDescriptionHash, bytes32[] _newFileHashes, bytes _data ); // Mapping from token ID to token data mapping(uint256 => CodexRecordData) internal tokenData; // Global tokenURIPrefix prefix. The token ID will be appended to the uri when accessed // via the tokenURI method string public tokenURIPrefix; /** * @dev Updates token metadata hashes to whatever is passed in * @param _tokenId uint256 The token ID * @param _newNameHash bytes32 The new sha3 hash of the name * @param _newDescriptionHash bytes32 The new sha3 hash of the description * @param _newFileHashes bytes32[] The new sha3 hashes of the files associated with the token * @param _data (optional) bytes Additional data that will be emitted with the Modified event */ function modifyMetadataHashes( uint256 _tokenId, bytes32 _newNameHash, bytes32 _newDescriptionHash, bytes32[] _newFileHashes, bytes _data ) public onlyOwnerOf(_tokenId) { // nameHash is only overridden if it's not a blank string, since name is a // required value. Emptiness is determined if the first element is the null-byte if (!bytes32IsEmpty(_newNameHash)) { tokenData[_tokenId].nameHash = _newNameHash; } // descriptionHash can always be overridden since it's an optional value // (e.g. you can "remove" a description by setting it to a blank string) tokenData[_tokenId].descriptionHash = _newDescriptionHash; // fileHashes is only overridden if it has one or more value, since at // least one file (i.e. mainImage) is required bool containsNullHash = false; for (uint i = 0; i < _newFileHashes.length; i++) { if (bytes32IsEmpty(_newFileHashes[i])) { containsNullHash = true; break; } } if (_newFileHashes.length > 0 && !containsNullHash) { tokenData[_tokenId].fileHashes = _newFileHashes; } emit Modified( msg.sender, _tokenId, tokenData[_tokenId].nameHash, tokenData[_tokenId].descriptionHash, tokenData[_tokenId].fileHashes, _data ); } /** * @dev Gets the token given a token ID. * @param _tokenId token ID * @return CodexRecordData token data for the given token ID */ function getTokenById( uint256 _tokenId ) public view returns (bytes32 nameHash, bytes32 descriptionHash, bytes32[] fileHashes) { return ( tokenData[_tokenId].nameHash, tokenData[_tokenId].descriptionHash, tokenData[_tokenId].fileHashes ); } /** * @dev Returns an URI for a given token ID * @dev Throws if the token ID does not exist. * * @dev To save on gas, we will host a standard metadata endpoint for each token. * For Collector privacy, specific token metadata is stored off chain, which means * the metadata returned by this endpoint cannot include specific details about * the physical asset the token represents unless the Collector has made it public. * * @dev This metadata will be a JSON blob that includes: * name - Codex Record * description - Information about the Provider that is hosting the off-chain metadata * imageUri - A generic Codex Record image * * @param _tokenId uint256 ID of the token to query */ function tokenURI( uint256 _tokenId ) public view returns (string) { bytes memory prefix = bytes(tokenURIPrefix); if (prefix.length == 0) { return ""; } // Rather than store a string representation of _tokenId, we just convert it on the fly // since this is just a 'view' function (i.e., there's no gas cost if called off chain) bytes memory tokenId = uint2bytes(_tokenId); bytes memory output = new bytes(prefix.length + tokenId.length); // Index counters uint256 i; uint256 outputIndex = 0; // Copy over the prefix into the new bytes array for (i = 0; i < prefix.length; i++) { output[outputIndex++] = prefix[i]; } // Copy over the tokenId into the new bytes array for (i = 0; i < tokenId.length; i++) { output[outputIndex++] = tokenId[i]; } return string(output); } /** * @dev Based on MIT licensed code @ https://github.com/oraclize/ethereum-api * @dev Converts an incoming uint256 to a dynamic byte array */ function uint2bytes(uint256 i) internal pure returns (bytes) { if (i == 0) { return "0"; } uint256 j = i; uint256 length; while (j != 0) { length++; j /= 10; } bytes memory bstr = new bytes(length); uint256 k = length - 1; j = i; while (j != 0) { bstr[k--] = byte(48 + j % 10); j /= 10; } return bstr; } /** * @dev Returns whether or not a bytes32 array is empty (all null-bytes) * @param _data bytes32 The array to check * @return bool Whether or not the array is empty */ function bytes32IsEmpty(bytes32 _data) internal pure returns (bool) { for (uint256 i = 0; i < 32; i++) { if (_data[i] != 0x0) { return false; } } return true; } } // File: contracts/ERC900/ERC900.sol /** * @title ERC900 Simple Staking Interface * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-900.md */ contract ERC900 { event Staked(address indexed user, uint256 amount, uint256 total, bytes data); event Unstaked(address indexed user, uint256 amount, uint256 total, bytes data); function stake(uint256 amount, bytes data) public; function stakeFor(address user, uint256 amount, bytes data) public; function unstake(uint256 amount, bytes data) public; function totalStakedFor(address addr) public view returns (uint256); function totalStaked() public view returns (uint256); function token() public view returns (address); function supportsHistory() public pure returns (bool); // NOTE: Not implementing the optional functions // function lastStakedFor(address addr) public view returns (uint256); // function totalStakedForAt(address addr, uint256 blockNumber) public view returns (uint256); // function totalStakedAt(uint256 blockNumber) public view returns (uint256); } // File: contracts/CodexStakeContractInterface.sol contract CodexStakeContractInterface is ERC900 { function stakeForDuration( address user, uint256 amount, uint256 lockInDuration, bytes data) public; function spendCredits( address user, uint256 amount) public; function creditBalanceOf( address user) public view returns (uint256); } // File: contracts/library/DelayedOwnable.sol /** * @title DelayedOwnable * @dev The DelayedOwnable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". * @dev This is different than the original Ownable contract because intializeOwnable * must be specifically called after creation to create an owner. */ contract DelayedOwnable { address public owner; bool public isInitialized = false; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(msg.sender == owner); _; } function initializeOwnable(address _owner) external { require( !isInitialized, "The owner has already been set"); isInitialized = true; owner = _owner; } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param _newOwner The address to transfer ownership to. */ function transferOwnership(address _newOwner) public onlyOwner { require(_newOwner != address(0)); emit OwnershipTransferred(owner, _newOwner); owner = _newOwner; } } // File: contracts/library/DelayedPausable.sol /** * @title Pausable * @dev Base contract which allows children to implement an emergency stop mechanism. */ contract DelayedPausable is DelayedOwnable { event Pause(); event Unpause(); bool public paused = false; /** * @dev Modifier to make a function callable only when the contract is not paused. */ modifier whenNotPaused() { require(!paused); _; } /** * @dev Modifier to make a function callable only when the contract is paused. */ modifier whenPaused() { require(paused); _; } /** * @dev called by the owner to pause, triggers stopped state */ function pause() onlyOwner whenNotPaused public { paused = true; emit Pause(); } /** * @dev called by the owner to unpause, returns to normal state */ function unpause() onlyOwner whenPaused public { paused = false; emit Unpause(); } } // File: contracts/CodexRecordFees.sol /** * @title CodexRecordFees * @dev Storage, mutators, and modifiers for fees when using the token. * This also includes the DelayedPausable contract for the onlyOwner modifier. */ contract CodexRecordFees is CodexRecordMetadata, DelayedPausable { // Implementation of the ERC20 Codex Protocol Token, used for fees in the contract ERC20 public codexCoin; // Implementation of the ERC900 Codex Protocol Stake Container, // used to calculate discounts on fees CodexStakeContractInterface public codexStakeContract; // Address where all contract fees are sent, i.e., the Community Fund address public feeRecipient; // Fee to create new tokens. 10^18 = 1 token uint256 public creationFee = 0; // Fee to transfer tokens. 10^18 = 1 token uint256 public transferFee = 0; // Fee to modify tokens. 10^18 = 1 token uint256 public modificationFee = 0; modifier canPayFees(uint256 _baseFee) { if (feeRecipient != address(0) && _baseFee > 0) { bool feePaid = false; if (codexStakeContract != address(0)) { uint256 discountCredits = codexStakeContract.creditBalanceOf(msg.sender); // Regardless of what the baseFee is, all transactions can be paid by using exactly one credit if (discountCredits > 0) { codexStakeContract.spendCredits(msg.sender, 1); feePaid = true; } } if (!feePaid) { require( codexCoin.transferFrom(msg.sender, feeRecipient, _baseFee), "Insufficient funds"); } } _; } /** * @dev Sets the address of the ERC20 token used for fees in the contract. * Fees are in the smallest denomination, e.g., 10^18 is 1 token. * @param _codexCoin ERC20 The address of the ERC20 Codex Protocol Token * @param _feeRecipient address The address where the fees are sent * @param _creationFee uint256 The new creation fee. * @param _transferFee uint256 The new transfer fee. * @param _modificationFee uint256 The new modification fee. */ function setFees( ERC20 _codexCoin, address _feeRecipient, uint256 _creationFee, uint256 _transferFee, uint256 _modificationFee ) external onlyOwner { codexCoin = _codexCoin; feeRecipient = _feeRecipient; creationFee = _creationFee; transferFee = _transferFee; modificationFee = _modificationFee; } function setStakeContract(CodexStakeContractInterface _codexStakeContract) external onlyOwner { codexStakeContract = _codexStakeContract; } } // File: contracts/CodexRecordCore.sol /** * @title CodexRecordCore * @dev Core functionality of the token, namely minting. */ contract CodexRecordCore is CodexRecordFees { /** * @dev This event is emitted when a new token is minted and allows providers * to discern which Minted events came from transactions they submitted vs * transactions submitted by other platforms, as well as providing information * about what metadata record the newly minted token should be associated with. */ event Minted(uint256 _tokenId, bytes _data); /** * @dev Sets the global tokenURIPrefix for use when returning token metadata. * Only callable by the owner. * @param _tokenURIPrefix string The new tokenURIPrefix */ function setTokenURIPrefix(string _tokenURIPrefix) external onlyOwner { tokenURIPrefix = _tokenURIPrefix; } /** * @dev Creates a new token * @param _to address The address the token will get transferred to after minting * @param _nameHash bytes32 The sha3 hash of the name * @param _descriptionHash bytes32 The sha3 hash of the description * @param _data (optional) bytes Additional data that will be emitted with the Minted event */ function mint( address _to, bytes32 _nameHash, bytes32 _descriptionHash, bytes32[] _fileHashes, bytes _data ) public { // All new tokens will be the last entry in the array uint256 newTokenId = allTokens.length; internalMint(_to, newTokenId); // Add metadata to the newly created token tokenData[newTokenId] = CodexRecordData({ nameHash: _nameHash, descriptionHash: _descriptionHash, fileHashes: _fileHashes }); emit Minted(newTokenId, _data); } function internalMint(address _to, uint256 _tokenId) internal { require(_to != address(0)); tokenOwner[_tokenId] = _to; ownedTokensCount[_to] = ownedTokensCount[_to].add(1); ownedTokensIndex[_tokenId] = ownedTokens[_to].length; ownedTokens[_to].push(_tokenId); allTokens.push(_tokenId); emit Transfer(address(0), _to, _tokenId); } } // File: contracts/CodexRecordAccess.sol /** * @title CodexRecordAccess * @dev Override contract functions */ contract CodexRecordAccess is CodexRecordCore { /** * @dev Make mint() pausable */ function mint( address _to, bytes32 _nameHash, bytes32 _descriptionHash, bytes32[] _fileHashes, bytes _data ) public whenNotPaused canPayFees(creationFee) { return super.mint( _to, _nameHash, _descriptionHash, _fileHashes, _data); } /** * @dev Make trasferFrom() pausable */ function transferFrom( address _from, address _to, uint256 _tokenId ) public whenNotPaused canPayFees(transferFee) { return super.transferFrom( _from, _to, _tokenId); } /** * @dev Make safeTrasferFrom() pausable */ function safeTransferFrom( address _from, address _to, uint256 _tokenId ) public whenNotPaused canPayFees(transferFee) { return super.safeTransferFrom( _from, _to, _tokenId); } /** * @dev Make safeTrasferFrom() pausable */ function safeTransferFrom( address _from, address _to, uint256 _tokenId, bytes _data ) public whenNotPaused canPayFees(transferFee) { return super.safeTransferFrom( _from, _to, _tokenId, _data ); } /** * @dev Make modifyMetadataHashes() pausable */ function modifyMetadataHashes( uint256 _tokenId, bytes32 _newNameHash, bytes32 _newDescriptionHash, bytes32[] _newFileHashes, bytes _data ) public whenNotPaused canPayFees(modificationFee) { return super.modifyMetadataHashes( _tokenId, _newNameHash, _newDescriptionHash, _newFileHashes, _data); } } // File: contracts/CodexRecord.sol /** * @title CodexRecord, an ERC721 token for arts & collectables * @dev Developers should never interact with this smart contract directly! * All transactions/calls should be made through CodexRecordProxy. Storage will be maintained * in that smart contract so that the governing body has the ability * to upgrade the contract in the future in the event of an emergency or new functionality. */ contract CodexRecord is CodexRecordAccess { /** * @dev Constructor function */ constructor() public ERC721Token("Codex Record", "CR") { } /** * @dev Reclaim all ERC20Basic compatible tokens * @param token ERC20Basic The address of the token contract */ function reclaimToken(ERC20Basic token) external onlyOwner { uint256 balance = token.balanceOf(this); token.transfer(owner, balance); } }