ETH Price: $3,177.39 (-8.18%)
Gas: 3 Gwei

Token

CryptoRome-Land-NFT (CRLAND)
 

Overview

Max Total Supply

4,995 CRLAND

Holders

143

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Balance
1 CRLAND
0xbe38d786dccefb5a909967c65ebe6a4e385d9fb3
Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

A game of economic, political and military strategy

# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
CryptoRomeLandComposableNFT

Compiler Version
v0.4.24+commit.e67f0147

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2018-09-04
*/

pragma solidity ^0.4.24;

/**
 * @summary: CryptoRome Land ERC-998 Bottom-Up Composable NFT Contract (and additional helper contracts)
 * @author: GigLabs, LLC
 */

/**
 * @title SafeMath
 * @dev Math operations with safety checks that revert on error
 */
library SafeMath {

  /**
  * @dev Multiplies two numbers, reverts on overflow.
  */
  function mul(uint256 _a, uint256 _b) internal pure returns (uint256) {
    // Gas optimization: this is cheaper than requiring '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;
    }

    uint256 c = _a * _b;
    require(c / _a == _b);

    return c;
  }

  /**
  * @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
  */
  function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
    require(_b > 0); // Solidity only automatically asserts 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 c;
  }

  /**
  * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
  */
  function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
    require(_b <= _a);
    uint256 c = _a - _b;

    return c;
  }

  /**
  * @dev Adds two numbers, reverts on overflow.
  */
  function add(uint256 _a, uint256 _b) internal pure returns (uint256) {
    uint256 c = _a + _b;
    require(c >= _a);

    return c;
  }

  /**
  * @dev Divides two numbers and returns the remainder (unsigned integer modulo),
  * reverts when dividing by zero.
  */
  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b != 0);
    return a % b;
  }
}


/**
 * @title ERC721 Non-Fungible Token Standard basic interface
 * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
 *  Note: the ERC-165 identifier for this interface is 0x80ac58cd.
 */
interface ERC721 /* is ERC165 */ {
    event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
    event Approval(address indexed _tokenOwner, address indexed _approved, uint256 indexed _tokenId);
    event ApprovalForAll(address indexed _tokenOwner, address indexed _operator, bool _approved);

    function balanceOf(address _tokenOwner) external view returns (uint256 _balance);
    function ownerOf(uint256 _tokenId) external view returns (address _tokenOwner);
    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes _data) external;
    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external;
    function transferFrom(address _from, address _to, uint256 _tokenId) external;
    function approve(address _to, uint256 _tokenId) external;
    function setApprovalForAll(address _operator, bool _approved) external;
    function getApproved(uint256 _tokenId) external view returns (address _operator);
    function isApprovedForAll(address _tokenOwner, address _operator) external view returns (bool);
}
 
 
/**
 * @notice Query if a contract implements an interface
 * @dev Interface identification is specified in ERC-165. This function
 * uses less than 30,000 gas.
 */
interface ERC165 {
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

interface ERC721TokenReceiver {
    /** 
     * @notice Handle the receipt of an NFT
     * @dev The ERC721 smart contract calls this function on the recipient
     * after a `transfer`. This function MAY throw to revert and reject the
     * transfer. Return of other than the magic value MUST result in the
     * transaction being reverted.
     * Note: the contract address is always the message sender.
     * @param _operator The address which called `safeTransferFrom` function
     * @param _from The address which previously owned the token
     * @param _tokenId The NFT identifier which is being transferred
     * @param _data Additional data with no specified format
     * @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
     * unless throwing
     */
    function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns(bytes4);
}

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
 * Note: the ERC-165 identifier for this interface is 0x5b5e139f.
 */
interface ERC721Metadata /* is ERC721 */ {
    function name() external view returns (string _name);
    function symbol() external view returns (string _symbol);
    function tokenURI(uint256 _tokenId) external view returns (string);
}

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
 * Note: the ERC-165 identifier for this interface is 0x780e9d63.
 */
interface ERC721Enumerable /* is ERC721 */ {
    function totalSupply() external view returns (uint256);
    function tokenByIndex(uint256 _index) external view returns (uint256);
    function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
}

/**
 * @title ERC998ERC721 Bottom-Up Composable Non-Fungible Token
 * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-998.md
 * Note: the ERC-165 identifier for this interface is 0xa1b23002
 */
interface ERC998ERC721BottomUp {
    event TransferToParent(address indexed _toContract, uint256 indexed _toTokenId, uint256 _tokenId);
    event TransferFromParent(address indexed _fromContract, uint256 indexed _fromTokenId, uint256 _tokenId);


    function rootOwnerOf(uint256 _tokenId) public view returns (bytes32 rootOwner);

    /**
    * The tokenOwnerOf function gets the owner of the _tokenId which can be a user address or another ERC721 token.
    * The tokenOwner address return value can be either a user address or an ERC721 contract address.
    * If the tokenOwner address is a user address then parentTokenId will be 0 and should not be used or considered.
    * If tokenOwner address is a user address then isParent is false, otherwise isChild is true, which means that
    * tokenOwner is an ERC721 contract address and _tokenId is a child of tokenOwner and parentTokenId.
    */
    function tokenOwnerOf(uint256 _tokenId) external view returns (bytes32 tokenOwner, uint256 parentTokenId, bool isParent);

    // Transfers _tokenId as a child to _toContract and _toTokenId
    function transferToParent(address _from, address _toContract, uint256 _toTokenId, uint256 _tokenId, bytes _data) public;
    // Transfers _tokenId from a parent ERC721 token to a user address.
    function transferFromParent(address _fromContract, uint256 _fromTokenId, address _to, uint256 _tokenId, bytes _data) public;
    // Transfers _tokenId from a parent ERC721 token to a parent ERC721 token.
    function transferAsChild(address _fromContract, uint256 _fromTokenId, address _toContract, uint256 _toTokenId, uint256 _tokenId, bytes _data) external;

}

/**
 * @title ERC998ERC721 Bottom-Up Composable, optional enumerable extension
 * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-998.md
 * Note: The ERC-165 identifier for this interface is 0x8318b539
 */
interface ERC998ERC721BottomUpEnumerable {
    function totalChildTokens(address _parentContract, uint256 _parentTokenId) external view returns (uint256);
    function childTokenByIndex(address _parentContract, uint256 _parentTokenId, uint256 _index) external view returns (uint256);
}

contract ERC998ERC721BottomUpToken is ERC721, ERC721Metadata, ERC721Enumerable, ERC165, ERC998ERC721BottomUp, ERC998ERC721BottomUpEnumerable {
    using SafeMath for uint256;

    struct TokenOwner {
        address tokenOwner;
        uint256 parentTokenId;
    }

    // return this.rootOwnerOf.selector ^ this.rootOwnerOfChild.selector ^
    //   this.tokenOwnerOf.selector ^ this.ownerOfChild.selector;
    bytes32 constant ERC998_MAGIC_VALUE = 0xcd740db5;

    // total number of tokens
    uint256 internal tokenCount;

    // tokenId => token owner
    mapping(uint256 => TokenOwner) internal tokenIdToTokenOwner;

    // 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;

    // root token owner address => (tokenId => approved address)
    mapping(address => mapping(uint256 => address)) internal rootOwnerAndTokenIdToApprovedAddress;

    // parent address => (parent tokenId => array of child tokenIds)
    mapping(address => mapping(uint256 => uint256[])) internal parentToChildTokenIds;

    // tokenId => position in childTokens array
    mapping(uint256 => uint256) internal tokenIdToChildTokenIdsIndex;

    // token owner => (operator address => bool)
    mapping(address => mapping(address => bool)) internal tokenOwnerToOperators;

    // Token name
    string internal name_;

    // Token symbol
    string internal symbol_;

    // Token URI
    string internal tokenURIBase;

    mapping(bytes4 => bool) internal supportedInterfaces;

    //from zepellin ERC721Receiver.sol
    //old version
    bytes4 constant ERC721_RECEIVED = 0x150b7a02;

    function isContract(address _addr) internal view returns (bool) {
        uint256 size;
        assembly {size := extcodesize(_addr)}
        return size > 0;
    }

    constructor () public {
        //ERC165
        supportedInterfaces[0x01ffc9a7] = true;
        //ERC721
        supportedInterfaces[0x80ac58cd] = true;
        //ERC721Metadata
        supportedInterfaces[0x5b5e139f] = true;
        //ERC721Enumerable
        supportedInterfaces[0x780e9d63] = true;
        //ERC998ERC721BottomUp
        supportedInterfaces[0xa1b23002] = true;
        //ERC998ERC721BottomUpEnumerable
        supportedInterfaces[0x8318b539] = true;
    }

    /////////////////////////////////////////////////////////////////////////////
    //
    // ERC165Impl
    //
    /////////////////////////////////////////////////////////////////////////////
    function supportsInterface(bytes4 _interfaceID) external view returns (bool) {
        return supportedInterfaces[_interfaceID];
    }

    /////////////////////////////////////////////////////////////////////////////
    //
    // ERC721 implementation & ERC998 Authentication
    //
    /////////////////////////////////////////////////////////////////////////////
    function balanceOf(address _tokenOwner) public view returns (uint256) {
        require(_tokenOwner != address(0));
        return ownedTokens[_tokenOwner].length;
    }

    // returns the immediate owner of the token
    function ownerOf(uint256 _tokenId) public view returns (address) {
        address tokenOwner = tokenIdToTokenOwner[_tokenId].tokenOwner;
        require(tokenOwner != address(0));
        return tokenOwner;
    }

    function transferFrom(address _from, address _to, uint256 _tokenId) external {
        require(_to != address(this));
        _transferFromOwnerCheck(_from, _to, _tokenId);
        _transferFrom(_from, _to, _tokenId);
    }

    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external {
        _transferFromOwnerCheck(_from, _to, _tokenId);
        _transferFrom(_from, _to, _tokenId);
        require(_checkAndCallSafeTransfer(_from, _to, _tokenId, ""));

    }

    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes _data) external {
        _transferFromOwnerCheck(_from, _to, _tokenId);
        _transferFrom(_from, _to, _tokenId);
        require(_checkAndCallSafeTransfer(_from, _to, _tokenId, _data));
    }

    function _checkAndCallSafeTransfer(address _from, address _to, uint256 _tokenId, bytes _data) internal view returns (bool) {
        if (!isContract(_to)) {
            return true;
        }
        bytes4 retval = ERC721TokenReceiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data);
        return (retval == ERC721_RECEIVED);
    }

    function _transferFromOwnerCheck(address _from, address _to, uint256 _tokenId) internal {
        require(_from != address(0));
        require(_to != address(0));
        require(tokenIdToTokenOwner[_tokenId].tokenOwner == _from);
        require(tokenIdToTokenOwner[_tokenId].parentTokenId == 0);

        // check child approved
        address approvedAddress = rootOwnerAndTokenIdToApprovedAddress[_from][_tokenId];
        if(msg.sender != _from) {
            bytes32 tokenOwner;
            bool callSuccess;
            // 0xeadb80b8 == ownerOfChild(address,uint256)
            bytes memory calldata = abi.encodeWithSelector(0xed81cdda, address(this), _tokenId);
            assembly {
                callSuccess := staticcall(gas, _from, add(calldata, 0x20), mload(calldata), calldata, 0x20)
                if callSuccess {
                    tokenOwner := mload(calldata)
                }
            }
            if(callSuccess == true) {
                require(tokenOwner >> 224 != ERC998_MAGIC_VALUE);
            }
            require(tokenOwnerToOperators[_from][msg.sender] || approvedAddress == msg.sender);
        }

        // clear approval
        if (approvedAddress != address(0)) {
            delete rootOwnerAndTokenIdToApprovedAddress[_from][_tokenId];
            emit Approval(_from, address(0), _tokenId);
        }
    }

    function _transferFrom(address _from, address _to, uint256 _tokenId) internal {
        // first remove the token from the owner list of owned tokens
        uint256 lastTokenIndex = ownedTokens[_from].length.sub(1);
        uint256 lastTokenId = ownedTokens[_from][lastTokenIndex];
        if (lastTokenId != _tokenId) {
            // replace the _tokenId in the list of ownedTokens with the
            // last token id in the list. Make sure ownedTokensIndex gets updated
            // with the new position of the last token id as well.
            uint256 tokenIndex = ownedTokensIndex[_tokenId];
            ownedTokens[_from][tokenIndex] = lastTokenId;
            ownedTokensIndex[lastTokenId] = tokenIndex;
        }

        // resize ownedTokens array (automatically deletes the last array entry)
        ownedTokens[_from].length--;

        // transfer token
        tokenIdToTokenOwner[_tokenId].tokenOwner = _to;
        
        // add token to the new owner's list of owned tokens
        ownedTokensIndex[_tokenId] = ownedTokens[_to].length;
        ownedTokens[_to].push(_tokenId);

        emit Transfer(_from, _to, _tokenId);
    }

    function approve(address _approved, uint256 _tokenId) external {
        address tokenOwner = tokenIdToTokenOwner[_tokenId].tokenOwner;
        require(tokenOwner != address(0));
        address rootOwner = address(rootOwnerOf(_tokenId));
        require(rootOwner == msg.sender || tokenOwnerToOperators[rootOwner][msg.sender]);

        rootOwnerAndTokenIdToApprovedAddress[rootOwner][_tokenId] = _approved;
        emit Approval(rootOwner, _approved, _tokenId);
    }

    function getApproved(uint256 _tokenId) public view returns (address)  {
        address rootOwner = address(rootOwnerOf(_tokenId));
        return rootOwnerAndTokenIdToApprovedAddress[rootOwner][_tokenId];
    }

    function setApprovalForAll(address _operator, bool _approved) external {
        require(_operator != address(0));
        tokenOwnerToOperators[msg.sender][_operator] = _approved;
        emit ApprovalForAll(msg.sender, _operator, _approved);
    }

    function isApprovedForAll(address _owner, address _operator) external view returns (bool)  {
        require(_owner != address(0));
        require(_operator != address(0));
        return tokenOwnerToOperators[_owner][_operator];
    }

    function _tokenOwnerOf(uint256 _tokenId) internal view returns (address tokenOwner, uint256 parentTokenId, bool isParent) {
        tokenOwner = tokenIdToTokenOwner[_tokenId].tokenOwner;
        require(tokenOwner != address(0));
        parentTokenId = tokenIdToTokenOwner[_tokenId].parentTokenId;
        if (parentTokenId > 0) {
            isParent = true;
            parentTokenId--;
        }
        else {
            isParent = false;
        }
        return (tokenOwner, parentTokenId, isParent);
    }

    
    function tokenOwnerOf(uint256 _tokenId) external view returns (bytes32 tokenOwner, uint256 parentTokenId, bool isParent) {
        address tokenOwnerAddress = tokenIdToTokenOwner[_tokenId].tokenOwner;
        require(tokenOwnerAddress != address(0));
        parentTokenId = tokenIdToTokenOwner[_tokenId].parentTokenId;
        if (parentTokenId > 0) {
            isParent = true;
            parentTokenId--;
        }
        else {
            isParent = false;
        }
        return (ERC998_MAGIC_VALUE << 224 | bytes32(tokenOwnerAddress), parentTokenId, isParent);
    }

    // Use Cases handled:
    // Case 1: Token owner is this contract and no parent tokenId.
    // Case 2: Token owner is this contract and token
    // Case 3: Token owner is top-down composable
    // Case 4: Token owner is an unknown contract
    // Case 5: Token owner is a user
    // Case 6: Token owner is a bottom-up composable
    // Case 7: Token owner is ERC721 token owned by top-down token
    // Case 8: Token owner is ERC721 token owned by unknown contract
    // Case 9: Token owner is ERC721 token owned by user
    function rootOwnerOf(uint256 _tokenId) public view returns (bytes32 rootOwner) {
        address rootOwnerAddress = tokenIdToTokenOwner[_tokenId].tokenOwner;
        require(rootOwnerAddress != address(0));
        uint256 parentTokenId = tokenIdToTokenOwner[_tokenId].parentTokenId;
        bool isParent = parentTokenId > 0;
        if (isParent) {
            parentTokenId--;
        }

        if((rootOwnerAddress == address(this))) {
            do {
                if(isParent == false) {
                    // Case 1: Token owner is this contract and no token.
                    // This case should not happen.
                    return ERC998_MAGIC_VALUE << 224 | bytes32(rootOwnerAddress);
                }
                else {
                    // Case 2: Token owner is this contract and token
                    (rootOwnerAddress, parentTokenId, isParent) = _tokenOwnerOf(parentTokenId);
                }
            } while(rootOwnerAddress == address(this));
            _tokenId = parentTokenId;
        }

        bytes memory calldata;
        bool callSuccess;

        if (isParent == false) {

            // success if this token is owned by a top-down token
            // 0xed81cdda == rootOwnerOfChild(address, uint256)
            calldata = abi.encodeWithSelector(0xed81cdda, address(this), _tokenId);
            assembly {
                callSuccess := staticcall(gas, rootOwnerAddress, add(calldata, 0x20), mload(calldata), calldata, 0x20)
                if callSuccess {
                    rootOwner := mload(calldata)
                }
            }
            if(callSuccess == true && rootOwner >> 224 == ERC998_MAGIC_VALUE) {
                // Case 3: Token owner is top-down composable
                return rootOwner;
            }
            else {
                // Case 4: Token owner is an unknown contract
                // Or
                // Case 5: Token owner is a user
                return ERC998_MAGIC_VALUE << 224 | bytes32(rootOwnerAddress);
            }
        }
        else {

            // 0x43a61a8e == rootOwnerOf(uint256)
            calldata = abi.encodeWithSelector(0x43a61a8e, parentTokenId);
            assembly {
                callSuccess := staticcall(gas, rootOwnerAddress, add(calldata, 0x20), mload(calldata), calldata, 0x20)
                if callSuccess {
                    rootOwner := mload(calldata)
                }
            }
            if (callSuccess == true && rootOwner >> 224 == ERC998_MAGIC_VALUE) {
                // Case 6: Token owner is a bottom-up composable
                // Or
                // Case 2: Token owner is top-down composable
                return rootOwner;
            }
            else {
                // token owner is ERC721
                address childContract = rootOwnerAddress;
                //0x6352211e == "ownerOf(uint256)"
                calldata = abi.encodeWithSelector(0x6352211e, parentTokenId);
                assembly {
                    callSuccess := staticcall(gas, rootOwnerAddress, add(calldata, 0x20), mload(calldata), calldata, 0x20)
                    if callSuccess {
                        rootOwnerAddress := mload(calldata)
                    }
                }
                require(callSuccess);

                // 0xed81cdda == rootOwnerOfChild(address,uint256)
                calldata = abi.encodeWithSelector(0xed81cdda, childContract, parentTokenId);
                assembly {
                    callSuccess := staticcall(gas, rootOwnerAddress, add(calldata, 0x20), mload(calldata), calldata, 0x20)
                    if callSuccess {
                        rootOwner := mload(calldata)
                    }
                }
                if(callSuccess == true && rootOwner >> 224 == ERC998_MAGIC_VALUE) {
                    // Case 7: Token owner is ERC721 token owned by top-down token
                    return rootOwner;
                }
                else {
                    // Case 8: Token owner is ERC721 token owned by unknown contract
                    // Or
                    // Case 9: Token owner is ERC721 token owned by user
                    return ERC998_MAGIC_VALUE << 224 | bytes32(rootOwnerAddress);
                }
            }
        }
    }

    // List of all Land Tokens assigned to an address.
    function tokensOfOwner(address _owner) external view returns(uint256[] ownerTokens) {
        return ownedTokens[_owner];
    }

    /////////////////////////////////////////////////////////////////////////////
    //
    // ERC721MetadataImpl
    //
    /////////////////////////////////////////////////////////////////////////////

    function tokenURI(uint256 _tokenId) external view returns (string) {
        require (exists(_tokenId));
        return _appendUintToString(tokenURIBase, _tokenId);
    }

    function name() external view returns (string) {
        return name_;
    }

    function symbol() external view returns (string) {
        return symbol_;
    }

    function _appendUintToString(string inStr, uint v) private pure returns (string str) {
        uint maxlength = 100;
        bytes memory reversed = new bytes(maxlength);
        uint i = 0;
        while (v != 0) {
            uint remainder = v % 10;
            v = v / 10;
            reversed[i++] = byte(48 + remainder);
        }
        bytes memory inStrb = bytes(inStr);
        bytes memory s = new bytes(inStrb.length + i);
        uint j;
        for (j = 0; j < inStrb.length; j++) {
            s[j] = inStrb[j];
        }
        for (j = 0; j < i; j++) {
            s[j + inStrb.length] = reversed[i - 1 - j];
        }
        str = string(s);
    }

    /////////////////////////////////////////////////////////////////////////////
    //
    // ERC721EnumerableImpl
    //
    /////////////////////////////////////////////////////////////////////////////

    function exists(uint256 _tokenId) public view returns (bool) {
        return _tokenId < tokenCount;
    }
 
    function totalSupply() external view returns (uint256) {
        return tokenCount;
    }

    function tokenOfOwnerByIndex(address _tokenOwner, uint256 _index) external view returns (uint256 tokenId) {
        require(_index < ownedTokens[_tokenOwner].length);
        return ownedTokens[_tokenOwner][_index];
    }

    function tokenByIndex(uint256 _index) external view returns (uint256 tokenId) {
        require(_index < tokenCount);
        return _index;
    }

    function _mint(address _to, uint256 _tokenId) internal {
        require (_to != address(0));
        require (tokenIdToTokenOwner[_tokenId].tokenOwner == address(0));
        tokenIdToTokenOwner[_tokenId].tokenOwner = _to;
        ownedTokensIndex[_tokenId] = ownedTokens[_to].length;
        ownedTokens[_to].push(_tokenId);
        tokenCount++;

        emit Transfer(address(0), _to, _tokenId);
    }

    /////////////////////////////////////////////////////////////////////////////
    //
    // ERC998 Bottom-Up implementation (extenstion of ERC-721)
    //
    /////////////////////////////////////////////////////////////////////////////

    function _removeChild(address _fromContract, uint256 _fromTokenId, uint256 _tokenId) internal {
        uint256 lastChildTokenIndex = parentToChildTokenIds[_fromContract][_fromTokenId].length - 1;
        uint256 lastChildTokenId = parentToChildTokenIds[_fromContract][_fromTokenId][lastChildTokenIndex];

        if (_tokenId != lastChildTokenId) {
            uint256 currentChildTokenIndex = tokenIdToChildTokenIdsIndex[_tokenId];
            parentToChildTokenIds[_fromContract][_fromTokenId][currentChildTokenIndex] = lastChildTokenId;
            tokenIdToChildTokenIdsIndex[lastChildTokenId] = currentChildTokenIndex;
        }
        parentToChildTokenIds[_fromContract][_fromTokenId].length--;
    }

    function _transferChild(address _from, address _toContract, uint256 _toTokenId, uint256 _tokenId) internal {
        tokenIdToTokenOwner[_tokenId].parentTokenId = _toTokenId.add(1);
        uint256 index = parentToChildTokenIds[_toContract][_toTokenId].length;
        parentToChildTokenIds[_toContract][_toTokenId].push(_tokenId);
        tokenIdToChildTokenIdsIndex[_tokenId] = index;

        _transferFrom(_from, _toContract, _tokenId);
        
        require(ERC721(_toContract).ownerOf(_toTokenId) != address(0));
        emit TransferToParent(_toContract, _toTokenId, _tokenId);
    }

    function _removeFromToken(address _fromContract, uint256 _fromTokenId, address _to, uint256 _tokenId) internal {
        require(_fromContract != address(0));
        require(_to != address(0));
        require(tokenIdToTokenOwner[_tokenId].tokenOwner == _fromContract);
        uint256 parentTokenId = tokenIdToTokenOwner[_tokenId].parentTokenId;
        require(parentTokenId != 0);
        require(parentTokenId - 1 == _fromTokenId);

        // authenticate
        address rootOwner = address(rootOwnerOf(_tokenId));
        address approvedAddress = rootOwnerAndTokenIdToApprovedAddress[rootOwner][_tokenId];
        require(rootOwner == msg.sender || tokenOwnerToOperators[rootOwner][msg.sender] || approvedAddress == msg.sender);

        // clear approval
        if (approvedAddress != address(0)) {
            delete rootOwnerAndTokenIdToApprovedAddress[rootOwner][_tokenId];
            emit Approval(rootOwner, address(0), _tokenId);
        }

        tokenIdToTokenOwner[_tokenId].parentTokenId = 0;

        _removeChild(_fromContract, _fromTokenId, _tokenId);
        emit TransferFromParent(_fromContract, _fromTokenId, _tokenId);
    }

    function transferFromParent(address _fromContract, uint256 _fromTokenId, address _to, uint256 _tokenId, bytes _data) public {
        _removeFromToken(_fromContract, _fromTokenId, _to, _tokenId);
        delete tokenIdToChildTokenIdsIndex[_tokenId];
        _transferFrom(_fromContract, _to, _tokenId);
        require(_checkAndCallSafeTransfer(_fromContract, _to, _tokenId, _data));
    }

    function transferToParent(address _from, address _toContract, uint256 _toTokenId, uint256 _tokenId, bytes _data) public {
        _transferFromOwnerCheck(_from, _toContract, _tokenId);
        _transferChild(_from, _toContract, _toTokenId, _tokenId);
    }

    function transferAsChild(address _fromContract, uint256 _fromTokenId, address _toContract, uint256 _toTokenId, uint256 _tokenId, bytes _data) external {
        _removeFromToken(_fromContract, _fromTokenId, _toContract, _tokenId);
        _transferChild(_fromContract, _toContract, _toTokenId, _tokenId);
    }

    /////////////////////////////////////////////////////////////////////////////
    //
    // ERC998 Bottom-Up Enumerable Implementation
    //
    /////////////////////////////////////////////////////////////////////////////

    function totalChildTokens(address _parentContract, uint256 _parentTokenId) public view returns (uint256) {
        return parentToChildTokenIds[_parentContract][_parentTokenId].length;
    }

    function childTokenByIndex(address _parentContract, uint256 _parentTokenId, uint256 _index) public view returns (uint256) {
        require(parentToChildTokenIds[_parentContract][_parentTokenId].length > _index);
        return parentToChildTokenIds[_parentContract][_parentTokenId][_index];
    }
}


contract CryptoRomeControl {

    // Emited when contract is upgraded or ownership changed
    event ContractUpgrade(address newContract);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    // Has control of (most) contract elements
    address public ownerPrimary;
    address public ownerSecondary;

    // Address of owner wallet to transfer funds
    address public ownerWallet;
    address public cryptoRomeWallet;

    // Contracts that need access for gameplay
    // (state = 1 means access is active, state = 0 means disabled)
    mapping(address => uint8) public otherOperators;

    // Improvement contract is the only authorized address that can modify 
    // existing land data (ex. when player purchases a land improvement). No one else can
    // modify land - even owners of this contract
    address public improvementContract;

    // Tracks if contract is paused or not. If paused, most actions are blocked
    bool public paused = false;

    constructor() public {
        ownerPrimary = msg.sender;
        ownerSecondary = msg.sender;
        ownerWallet = msg.sender;
        cryptoRomeWallet = msg.sender;
    }

    modifier onlyOwner() {
        require (msg.sender == ownerPrimary || msg.sender == ownerSecondary);
        _;
    }

    modifier anyOperator() {
        require (
            msg.sender == ownerPrimary ||
            msg.sender == ownerSecondary ||
            otherOperators[msg.sender] == 1
        );
        _;
    }

    modifier onlyOtherOperators() {
        require (otherOperators[msg.sender] == 1);
        _;
    }

    modifier onlyImprovementContract() {
        require (msg.sender == improvementContract);
        _;
    }

    function setPrimaryOwner(address _newOwner) external onlyOwner {
        require (_newOwner != address(0));
        emit OwnershipTransferred(ownerPrimary, _newOwner);
        ownerPrimary = _newOwner;
    }

    function setSecondaryOwner(address _newOwner) external onlyOwner {
        require (_newOwner != address(0));
        emit OwnershipTransferred(ownerSecondary, _newOwner);
        ownerSecondary = _newOwner;
    }

    function setOtherOperator(address _newOperator, uint8 _state) external onlyOwner {
        require (_newOperator != address(0));
        otherOperators[_newOperator] = _state;
    }

    function setImprovementContract(address _improvementContract) external onlyOwner {
        require (_improvementContract != address(0));
        emit OwnershipTransferred(improvementContract, _improvementContract);
        improvementContract = _improvementContract;
    }

    function transferOwnerWalletOwnership(address newWalletAddress) onlyOwner external {
        require(newWalletAddress != address(0));
        ownerWallet = newWalletAddress;
    }

    function transferCryptoRomeWalletOwnership(address newWalletAddress) onlyOwner external {
        require(newWalletAddress != address(0));
        cryptoRomeWallet = newWalletAddress;
    }

    modifier whenNotPaused() {
        require(!paused);
        _;
    }

    modifier whenPaused {
        require(paused);
        _;
    }

    function pause() public onlyOwner whenNotPaused {
        paused = true;
    }

    function unpause() public onlyOwner whenPaused {
        paused = false;
    }

    function withdrawBalance() public onlyOwner {
        ownerWallet.transfer(address(this).balance);
    }
}

contract CryptoRomeLandComposableNFT is ERC998ERC721BottomUpToken, CryptoRomeControl {
    using SafeMath for uint256;

    // Set in case the contract needs to be updated
    address public newContractAddress;

    struct LandInfo {
        uint256 landType;  // 0-4  unit, plot, village, town, city (unit unused)
        uint256 landImprovements; 
        uint256 askingPrice;
    }

    mapping(uint256 => LandInfo) internal tokenIdToLand;

    // for sale state of all tokens. tokens map to bits. 0 = not for sale; 1 = for sale
    // 256 token states per index of this array
    uint256[] internal allLandForSaleState;

    // landType => land count
    mapping(uint256 => uint256) internal landTypeToCount;

    // total number of villages in existence is 50000 (no more can be created)
    uint256 constant internal MAX_VILLAGES = 50000;

    constructor () public {
        paused = true;
        name_ = "CryptoRome-Land-NFT";
        symbol_ = "CRLAND";
    }

    function isCryptoRomeLandComposableNFT() external pure returns (bool) {
        return true;
    }

    function getLandTypeCount(uint256 _landType) public view returns (uint256) {
        return landTypeToCount[_landType];
    }

    function setTokenURI(string _tokenURI) external anyOperator {
        tokenURIBase = _tokenURI;
    }

    function setNewAddress(address _v2Address) external onlyOwner {
        require (_v2Address != address(0));
        newContractAddress = _v2Address;
        emit ContractUpgrade(_v2Address);
    }

    /////////////////////////////////////////////////////////////////////////////
    // Get Land
    //   Token Owner: Address of the token owner
    //   Parent Token Id: If parentTokenId is > 0, then this land
    //      token is owned by another token (i.e. it is attached bottom-up).
    //      parentTokenId is the id of the owner token, and tokenOwner
    //      address (the first parameter) is the ERC721 contract address of the  
    //      parent token. If parentTokenId == 0, then this land token is owned
    //      by a user address.
    //   Land Types: village=1, town=2, city=3
    //   Land Improvements: improvements and upgrades
    //      to each land NFT are coded into a single uint256 value
    //   Asking Price (in wei): 0 if land is not for sale
    /////////////////////////////////////////////////////////////////////////////
    function getLand(uint256 _tokenId) external view
        returns (
            address tokenOwner,
            uint256 parentTokenId,
            uint256 landType,
            uint256 landImprovements,
            uint256 askingPrice
        ) {
        TokenOwner storage owner = tokenIdToTokenOwner[_tokenId];
        LandInfo storage land = tokenIdToLand[_tokenId];

        parentTokenId = owner.parentTokenId;
        if (parentTokenId > 0) {
            parentTokenId--;
        }
        tokenOwner = owner.tokenOwner;
        parentTokenId = owner.parentTokenId;
        landType = land.landType;
        landImprovements = land.landImprovements;
        askingPrice = land.askingPrice;
    }

    /////////////////////////////////////////////////////////////////////////////
    // Create Land NFT
    //   Land Types: village=1, town=2, city=3
    //   Land Improvements: improvements and upgrades
    //      to each land NFT are the coded into a uint256 value
    /////////////////////////////////////////////////////////////////////////////
    function _createLand (address _tokenOwner, uint256 _landType, uint256 _landImprovements) internal returns (uint256 tokenId) {
        require(_tokenOwner != address(0));
        require(landTypeToCount[1] < MAX_VILLAGES);
        tokenId = tokenCount;

        LandInfo memory land = LandInfo({
            landType: _landType,  // 1-3  village, town, city
            landImprovements: _landImprovements,
            askingPrice: 0
        });
        
        // map new tokenId to the newly created land      
        tokenIdToLand[tokenId] = land;
        landTypeToCount[_landType]++;

        if (tokenId % 256 == 0) {
            // create new land sale state entry in storage
            allLandForSaleState.push(0);
        }

        _mint(_tokenOwner, tokenId);

        return tokenId;
    }
    
    function createLand (address _tokenOwner, uint256 _landType, uint256 _landImprovements) external anyOperator whenNotPaused returns (uint256 tokenId) {
        return _createLand (_tokenOwner, _landType, _landImprovements);
    }

    ////////////////////////////////////////////////////////////////////////////////
    // Land Improvement Data
    //   This uint256 land "dna" value describes all improvements and upgrades 
    //   to a piece of land. After land token distribution, only the Improvement
    //   Contract can ever update or modify the land improvement data of a piece
    //   of land (contract owner cannot modify land).
    //
    // For villages, improvementData is a uint256 value containing village
    // improvement data with the following slot bit mapping
    //     0-31:     slot 1 improvement info
    //     32-63:    slot 2 improvement info
    //     64-95:    slot 3 improvement info
    //     96-127:   slot 4 improvement info
    //     128-159:  slot 5 improvement info
    //     160-191:  slot 6 improvement info
    //     192-255:  reserved for additional land information
    //
    // Each 32 bit slot in the above structure has the following bit mapping
    //     0-7:      improvement type (index to global list of possible types)
    //     8-14:     upgrade type 1 - level 0-99  (0 for no upgrade present)
    //     15-21:    upgrade type 2 - level 0-99  (0 for no upgrade present)
    //     22:       upgrade type 3 - 1 if upgrade present, 0 if not (no leveling)
    ////////////////////////////////////////////////////////////////////////////////
    function getLandImprovementData(uint256 _tokenId) external view returns (uint256) {
        return tokenIdToLand[_tokenId].landImprovements;
    }

    function updateLandImprovementData(uint256 _tokenId, uint256 _newLandImprovementData) external whenNotPaused onlyImprovementContract {
        require(_tokenId <= tokenCount);
        tokenIdToLand[_tokenId].landImprovements = _newLandImprovementData;
    }

    /////////////////////////////////////////////////////////////////////////////
    // Land Compose/Decompose functions
    //   Towns are composed of 3 Villages
    //   Cities are composed of 3 Towns
    /////////////////////////////////////////////////////////////////////////////

    // Attach three child land tokens onto a parent land token (ex. 3 villages onto a town).
    // This function is called when the parent does not exist yet, so create parent land token first
    // Ownership of the child lands transfers from the existing owner (sender) to the parent land token
    function composeNewLand(uint256 _landType, uint256 _childLand1, uint256 _childLand2, uint256 _childLand3) external whenNotPaused returns(uint256) {
        uint256 parentTokenId = _createLand(msg.sender, _landType, 0);
        return composeLand(parentTokenId, _childLand1, _childLand2, _childLand3);
    }

    // Attach three child land tokens onto a parent land token (ex. 3 villages into a town).
    // All three children and an existing parent need to be passed into this function.
    // Ownership of the child lands transfers from the existing owner (sender) to the parent land token
    function composeLand(uint256 _parentLandId, uint256 _childLand1, uint256 _childLand2, uint256 _childLand3) public whenNotPaused returns(uint256) {
        require (tokenIdToLand[_parentLandId].landType == 2 || tokenIdToLand[_parentLandId].landType == 3);
        uint256 validChildLandType = tokenIdToLand[_parentLandId].landType.sub(1);
        require(tokenIdToLand[_childLand1].landType == validChildLandType &&
                tokenIdToLand[_childLand2].landType == validChildLandType &&
                tokenIdToLand[_childLand3].landType == validChildLandType);

        // transfer ownership of child land tokens to parent land token
        transferToParent(tokenIdToTokenOwner[_childLand1].tokenOwner, address(this), _parentLandId, _childLand1, "");
        transferToParent(tokenIdToTokenOwner[_childLand2].tokenOwner, address(this), _parentLandId, _childLand2, "");
        transferToParent(tokenIdToTokenOwner[_childLand3].tokenOwner, address(this), _parentLandId, _childLand3, "");

        // if this contract is owner of the parent land token, transfer ownership to msg.sender
        if (tokenIdToTokenOwner[_parentLandId].tokenOwner == address(this)) {
            _transferFrom(address(this), msg.sender, _parentLandId);
        }

        return _parentLandId;
    }

    // Decompose a parent land back to it's attached child land token components (ex. a town into 3 villages).
    // The existing owner of the parent land becomes the owner of the three child tokens
    // This contract takes over ownership of the parent land token (for later reuse)
    // Loop to remove and transfer all land tokens in case other land tokens are attached.
    function decomposeLand(uint256 _tokenId) external whenNotPaused {
        uint256 numChildren = totalChildTokens(address(this), _tokenId);
        require (numChildren > 0);

        // it is lower gas cost to remove children starting from the end of the array
        for (uint256 numChild = numChildren; numChild > 0; numChild--) {
            uint256 childTokenId = childTokenByIndex(address(this), _tokenId, numChild-1);

            // transfer ownership of underlying lands to msg.sender
            transferFromParent(address(this), _tokenId, msg.sender, childTokenId, "");
        }

        // transfer ownership of parent land back to this contract owner for reuse
        _transferFrom(msg.sender, address(this), _tokenId);
    }

    /////////////////////////////////////////////////////////////////////////////
    // Sale functions
    /////////////////////////////////////////////////////////////////////////////
    function _updateSaleData(uint256 _tokenId, uint256 _askingPrice) internal {
        tokenIdToLand[_tokenId].askingPrice = _askingPrice;
        if (_askingPrice > 0) {
            // Item is for sale - set bit
            allLandForSaleState[_tokenId.div(256)] = allLandForSaleState[_tokenId.div(256)] | (1 << (_tokenId % 256));
        } else {
            // Item is no longer for sale - clear bit
            allLandForSaleState[_tokenId.div(256)] = allLandForSaleState[_tokenId.div(256)] & ~(1 << (_tokenId % 256));
        }
    }

    function sellLand(uint256 _tokenId, uint256 _askingPrice) public whenNotPaused {
        require(tokenIdToTokenOwner[_tokenId].tokenOwner == msg.sender);
        require(tokenIdToTokenOwner[_tokenId].parentTokenId == 0);
        require(_askingPrice > 0);
        // Put the land token on the market
        _updateSaleData(_tokenId, _askingPrice);
    }

    function cancelLandSale(uint256 _tokenId) public whenNotPaused {
        require(tokenIdToTokenOwner[_tokenId].tokenOwner == msg.sender);
        // Take the land token off the market
        _updateSaleData(_tokenId, 0);
    }

    function purchaseLand(uint256 _tokenId) public whenNotPaused payable {
        uint256 price = tokenIdToLand[_tokenId].askingPrice;
        require(price <= msg.value);

        // Take the land token off the market
        _updateSaleData(_tokenId, 0);

        // Marketplace fee
        uint256 marketFee = computeFee(price);
        uint256 sellerProceeds = msg.value.sub(marketFee);
        cryptoRomeWallet.transfer(marketFee);

        // Return excess payment to sender
        uint256 excessPayment = msg.value.sub(price);
        msg.sender.transfer(excessPayment);

        // Transfer proceeds to seller. Sale was removed above before this transfer()
        // to guard against reentrancy attacks
        tokenIdToTokenOwner[_tokenId].tokenOwner.transfer(sellerProceeds);
        // Transfer token to buyer
        _transferFrom(tokenIdToTokenOwner[_tokenId].tokenOwner, msg.sender, _tokenId);
    }

    function getAllForSaleStatus() external view returns(uint256[]) {
        // return uint256[] bitmap values up to max tokenId (for ease of querying from UI for marketplace)
        //   index 0 of the uint256 holds first 256 land token status; index 1 is next 256 land tokens, etc
        //   value of 1 = For Sale; 0 = Not for Sale
        return allLandForSaleState;
    }

    function computeFee(uint256 amount) internal pure returns(uint256) {
        // 3% marketplace fee, most of which will be distributed to the Caesar and Senators of CryptoRome
        return amount.mul(3).div(100);
    }
}

contract CryptoRomeLandDistribution is CryptoRomeControl {
    using SafeMath for uint256;

    // Set in case the contract needs to be updated
    address public newContractAddress;

    CryptoRomeLandComposableNFT public cryptoRomeLandNFTContract;
    ImprovementGeneration public improvementGenContract;
    uint256 public villageInventoryPrice;
    uint256 public numImprovementsPerVillage;

    uint256 constant public LOWEST_VILLAGE_INVENTORY_PRICE = 100000000000000000; // 0.1 ETH

    constructor (address _cryptoRomeLandNFTContractAddress, address _improvementGenContractAddress) public {
        require (_cryptoRomeLandNFTContractAddress != address(0));
        require (_improvementGenContractAddress != address(0));

        paused = true;

        cryptoRomeLandNFTContract = CryptoRomeLandComposableNFT(_cryptoRomeLandNFTContractAddress);
        improvementGenContract = ImprovementGeneration(_improvementGenContractAddress);

        villageInventoryPrice = LOWEST_VILLAGE_INVENTORY_PRICE;
        numImprovementsPerVillage = 3;
    }

    function setNewAddress(address _v2Address) external onlyOwner {
        require (_v2Address != address(0));
        newContractAddress = _v2Address;
        emit ContractUpgrade(_v2Address);
    }

    function setCryptoRomeLandNFTContract(address _cryptoRomeLandNFTContract) external onlyOwner {
        require (_cryptoRomeLandNFTContract != address(0));
        cryptoRomeLandNFTContract = CryptoRomeLandComposableNFT(_cryptoRomeLandNFTContract);
    }

    function setImprovementGenContract(address _improvementGenContractAddress) external onlyOwner {
        require (_improvementGenContractAddress != address(0));
        improvementGenContract = ImprovementGeneration(_improvementGenContractAddress);
    }

    function setVillageInventoryPrice(uint256 _price) external onlyOwner {
        require(_price >= LOWEST_VILLAGE_INVENTORY_PRICE);
        villageInventoryPrice = _price;
    }

    function setNumImprovementsPerVillage(uint256 _numImprovements) external onlyOwner {
        require(_numImprovements <= 6);
        numImprovementsPerVillage = _numImprovements;
    }

    function purchaseFromVillageInventory(uint256 _num) external whenNotPaused payable {
        uint256 price = villageInventoryPrice.mul(_num);
        require (msg.value >= price);
        require (_num > 0 && _num <= 50);

        // Marketplace fee
        uint256 marketFee = computeFee(price);
        cryptoRomeWallet.transfer(marketFee);

        // Return excess payment to sender
        uint256 excessPayment = msg.value.sub(price);
        msg.sender.transfer(excessPayment);

        for (uint256 i = 0; i < _num; i++) {
            // create a new village w/ random improvements and transfer the NFT to caller
            _createVillageWithImprovementsFromInv(msg.sender);
        }
    }

    function computeFee(uint256 amount) internal pure returns(uint256) {
        // 3% marketplace fee, most of which will be distributed to the Caesar and Senators of CryptoRome
        return amount.mul(3).div(100);
    }

    function batchIssueLand(address _toAddress, uint256[] _landType) external onlyOwner {
        require (_toAddress != address(0));
        require (_landType.length > 0);

        for (uint256 i = 0; i < _landType.length; i++) {
            issueLand(_toAddress, _landType[i]);
        }
    }

    function batchIssueVillages(address _toAddress, uint256 _num) external onlyOwner {
        require (_toAddress != address(0));
        require (_num > 0);

        for (uint256 i = 0; i < _num; i++) {
            _createVillageWithImprovements(_toAddress);
        }
    }

    function issueLand(address _toAddress, uint256 _landType) public onlyOwner returns (uint256) {
        require (_toAddress != address(0));

        return _createLandWithImprovements(_toAddress, _landType);
    }

    function batchCreateLand(uint256[] _landType) external onlyOwner {
        require (_landType.length > 0);

        for (uint256 i = 0; i < _landType.length; i++) {
            // land created is owned by this contract for staging purposes
            // (must later use transferTo or batchTransferTo)
            _createLandWithImprovements(address(this), _landType[i]);
        }
    }

    function batchCreateVillages(uint256 _num) external onlyOwner {
        require (_num > 0);

        for (uint256 i = 0; i < _num; i++) {
            // land created is owned by this contract for staging purposes
            // (must later use transferTo or batchTransferTo)
            _createVillageWithImprovements(address(this));
        }
    }

    function createLand(uint256 _landType) external onlyOwner {
        // land created is owned by this contract for staging purposes
        // (must later use transferTo or batchTransferTo)
        _createLandWithImprovements(address(this), _landType);
    }

    function batchTransferTo(uint256[] _tokenIds, address _to) external onlyOwner {
        require (_tokenIds.length > 0);
        require (_to != address(0));

        for (uint256 i = 0; i < _tokenIds.length; ++i) {
            // transfers staged land out of this contract to the owners
            cryptoRomeLandNFTContract.transferFrom(address(this), _to, _tokenIds[i]);
        }
    }

    function transferTo(uint256 _tokenId, address _to) external onlyOwner {
        require (_to != address(0));

        // transfers staged land out of this contract to the owners
        cryptoRomeLandNFTContract.transferFrom(address(this), _to, _tokenId);
    }

    function issueVillageWithImprovementsForPromo(address _toAddress, uint256 numImprovements) external onlyOwner returns (uint256) {
        uint256 landImprovements = improvementGenContract.genInitialResourcesForVillage(numImprovements, false);
        return cryptoRomeLandNFTContract.createLand(_toAddress, 1, landImprovements);
    }

    function _createVillageWithImprovementsFromInv(address _toAddress) internal returns (uint256) {
        uint256 landImprovements = improvementGenContract.genInitialResourcesForVillage(numImprovementsPerVillage, true);
        return cryptoRomeLandNFTContract.createLand(_toAddress, 1, landImprovements);
    }

    function _createVillageWithImprovements(address _toAddress) internal returns (uint256) {
        uint256 landImprovements = improvementGenContract.genInitialResourcesForVillage(3, false);
        return cryptoRomeLandNFTContract.createLand(_toAddress, 1, landImprovements);
    }

    function _createLandWithImprovements(address _toAddress, uint256 _landType) internal returns (uint256) {
        require (_landType > 0 && _landType < 4);

        if (_landType == 1) {
            return _createVillageWithImprovements(_toAddress);
        } else if (_landType == 2) {
            uint256 village1TokenId = _createLandWithImprovements(address(this), 1);
            uint256 village2TokenId = _createLandWithImprovements(address(this), 1);
            uint256 village3TokenId = _createLandWithImprovements(address(this), 1);
            uint256 townTokenId = cryptoRomeLandNFTContract.createLand(_toAddress, 2, 0);
            cryptoRomeLandNFTContract.composeLand(townTokenId, village1TokenId, village2TokenId, village3TokenId);
            return townTokenId;
        } else if (_landType == 3) {
            uint256 town1TokenId = _createLandWithImprovements(address(this), 2);
            uint256 town2TokenId = _createLandWithImprovements(address(this), 2);
            uint256 town3TokenId = _createLandWithImprovements(address(this), 2);
            uint256 cityTokenId = cryptoRomeLandNFTContract.createLand(_toAddress, 3, 0);
            cryptoRomeLandNFTContract.composeLand(cityTokenId, town1TokenId, town2TokenId, town3TokenId);
            return cityTokenId;
        }
    }
}

interface RandomNumGeneration {
    function getRandomNumber(uint256 seed) external returns (uint256);
}

contract ImprovementGeneration is CryptoRomeControl {
    using SafeMath for uint256;
    
    // Set in case the contract needs to be updated
    address public newContractAddress;

    RandomNumGeneration public randomNumberSource; 
    uint256 public rarityValueMax;
    uint256 public latestPseudoRandomNumber;
    uint8 public numResourceImprovements;

    mapping(uint8 => uint256) private improvementIndexToRarityValue;

    constructor () public {
        // Starting Improvements
        // improvement => rarity value (lower number = higher rarity) 
        improvementIndexToRarityValue[1] = 256;  // Wheat
        improvementIndexToRarityValue[2] = 256;  // Wood
        improvementIndexToRarityValue[3] = 128;  // Grapes
        improvementIndexToRarityValue[4] = 128;  // Stone
        improvementIndexToRarityValue[5] = 64;   // Clay
        improvementIndexToRarityValue[6] = 64;   // Fish
        improvementIndexToRarityValue[7] = 32;   // Horse
        improvementIndexToRarityValue[8] = 16;   // Iron
        improvementIndexToRarityValue[9] = 8;    // Marble
        // etc --> More can be added in the future

        // max resource improvement types is 63
        numResourceImprovements = 9;
        rarityValueMax = 952;
    }

    function setNewAddress(address _v2Address) external onlyOwner {
        require (_v2Address != address(0));
        newContractAddress = _v2Address;
        emit ContractUpgrade(_v2Address);
    }

    function setRandomNumGenerationContract(address _randomNumberGenAddress) external onlyOwner {
        require (_randomNumberGenAddress != address(0));
        randomNumberSource = RandomNumGeneration(_randomNumberGenAddress);
    }

    function genInitialResourcesForVillage(uint256 numImprovements, bool useRandomInput) external anyOperator returns(uint256) {
        require(numImprovements <= 6);
        uint256 landImprovements;

        // each improvement takes up one village slot (max 6 slots)
        for (uint256 i = 0; i < numImprovements; i++) {
            uint8 newImprovement = generateImprovement(useRandomInput);
            // each slot is a 32 bit section in the 256 bit landImprovement value
            landImprovements |= uint256(newImprovement) << (32*i);
        }
        
        return landImprovements;
    }

    function generateImprovement(bool useRandomSource) public anyOperator returns (uint8 newImprovement) {     
        // seed does not need to be anything super fancy for initial improvement generation for villages...
        // players will not be performing that operation, so this should be random enough
        uint256 seed = latestPseudoRandomNumber.add(now);
        if (useRandomSource) {
            // for cases where players are generating land (i.e. after initial distribution of villages), there
            // will need to be a better source of randomness
            seed = randomNumberSource.getRandomNumber(seed);
        }
        
        latestPseudoRandomNumber = addmod(uint256(blockhash(block.number-1)), seed, rarityValueMax);
        
        // do lookup for the improvement
        newImprovement = lookupImprovementTypeByRarity(latestPseudoRandomNumber);
    }

    function lookupImprovementTypeByRarity(uint256 rarityNum) public view returns (uint8 improvementType) {
        uint256 rarityIndexValue;
        for (uint8 i = 1; i <= numResourceImprovements; i++) {
            rarityIndexValue += improvementIndexToRarityValue[i];
            if (rarityNum < rarityIndexValue) {
                return i;
            }
        }
        return 0;
    }

    function addNewResourceImprovementType(uint256 rarityValue) external onlyOwner {
        require(rarityValue > 0);
        require(numResourceImprovements < 63);

        numResourceImprovements++;
        rarityValueMax += rarityValue;
        improvementIndexToRarityValue[numResourceImprovements] = rarityValue;
    }

    function updateImprovementRarityValue(uint256 rarityValue, uint8 improvementIndex) external onlyOwner {
        require(rarityValue > 0);
        require(improvementIndex <= numResourceImprovements);

        rarityValueMax -= improvementIndexToRarityValue[improvementIndex];
        rarityValueMax += rarityValue;
        improvementIndexToRarityValue[improvementIndex] = rarityValue;
    }
}

Contract Security Audit

Contract ABI

[{"constant":true,"inputs":[{"name":"_interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_parentContract","type":"address"},{"name":"_parentTokenId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"childTokenByIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_approved","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"approve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newWalletAddress","type":"address"}],"name":"transferCryptoRomeWalletOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_tokenOwner","type":"address"},{"name":"_landType","type":"uint256"},{"name":"_landImprovements","type":"uint256"}],"name":"createLand","outputs":[{"name":"tokenId","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getAllForSaleStatus","outputs":[{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_tokenOwner","type":"address"},{"name":"_index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"name":"tokenId","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"cryptoRomeWallet","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"rootOwnerOf","outputs":[{"name":"rootOwner","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"setPrimaryOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"exists","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"name":"tokenId","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_fromContract","type":"address"},{"name":"_fromTokenId","type":"uint256"},{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"transferFromParent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"withdrawBalance","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"newContractAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"otherOperators","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_tokenOwner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_v2Address","type":"address"}],"name":"setNewAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_landType","type":"uint256"},{"name":"_childLand1","type":"uint256"},{"name":"_childLand2","type":"uint256"},{"name":"_childLand3","type":"uint256"}],"name":"composeNewLand","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"purchaseLand","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"tokensOfOwner","outputs":[{"name":"ownerTokens","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_parentContract","type":"address"},{"name":"_parentTokenId","type":"uint256"}],"name":"totalChildTokens","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"tokenOwnerOf","outputs":[{"name":"tokenOwner","type":"bytes32"},{"name":"parentTokenId","type":"uint256"},{"name":"isParent","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"decomposeLand","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"ownerWallet","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ownerPrimary","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_operator","type":"address"},{"name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_tokenId","type":"uint256"},{"name":"_askingPrice","type":"uint256"}],"name":"sellLand","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_landType","type":"uint256"}],"name":"getLandTypeCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"getLandImprovementData","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_fromContract","type":"address"},{"name":"_fromTokenId","type":"uint256"},{"name":"_toContract","type":"address"},{"name":"_toTokenId","type":"uint256"},{"name":"_tokenId","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"transferAsChild","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_parentLandId","type":"uint256"},{"name":"_childLand1","type":"uint256"},{"name":"_childLand2","type":"uint256"},{"name":"_childLand3","type":"uint256"}],"name":"composeLand","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"ownerSecondary","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newWalletAddress","type":"address"}],"name":"transferOwnerWalletOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"isCryptoRomeLandComposableNFT","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"setSecondaryOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"improvementContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newOperator","type":"address"},{"name":"_state","type":"uint8"}],"name":"setOtherOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_improvementContract","type":"address"}],"name":"setImprovementContract","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_tokenURI","type":"string"}],"name":"setTokenURI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_tokenId","type":"uint256"},{"name":"_newLandImprovementData","type":"uint256"}],"name":"updateLandImprovementData","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"cancelLandSale","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"getLand","outputs":[{"name":"tokenOwner","type":"address"},{"name":"parentTokenId","type":"uint256"},{"name":"landType","type":"uint256"},{"name":"landImprovements","type":"uint256"},{"name":"askingPrice","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_toContract","type":"address"},{"name":"_toTokenId","type":"uint256"},{"name":"_tokenId","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"transferToParent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newContract","type":"address"}],"name":"ContractUpgrade","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_toContract","type":"address"},{"indexed":true,"name":"_toTokenId","type":"uint256"},{"indexed":false,"name":"_tokenId","type":"uint256"}],"name":"TransferToParent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_fromContract","type":"address"},{"indexed":true,"name":"_fromTokenId","type":"uint256"},{"indexed":false,"name":"_tokenId","type":"uint256"}],"name":"TransferFromParent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":true,"name":"_tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_tokenOwner","type":"address"},{"indexed":true,"name":"_approved","type":"address"},{"indexed":true,"name":"_tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_tokenOwner","type":"address"},{"indexed":true,"name":"_operator","type":"address"},{"indexed":false,"name":"_approved","type":"bool"}],"name":"ApprovalForAll","type":"event"}]

60806040526011805460a060020a60ff02191690553480156200002157600080fd5b50600b60209081527f6fc4fe54b7713e8c3beb98c1633f1a7c51390dad7f13255e19999c5edaf38b65805460ff1990811660019081179092557f58dbcb8b42477ba587235ed21c9227789266bd956417ae5420ec8c31552e276280548216831790557f392a5f45591c4d9c05a109aeb535f975c0e2d81925e3ac029c52e6ec2139a20b80548216831790557f9ea35b7873c8b046fb963897c29b313fe2a41ca6b497dee659b16c91e3b8a50280548216831790557fff2ba62c5c6f4e0b72ee7054c587fbb2ff1ec14aa579cbc64a86f76ec6cb296e80548216831790557f8318b539000000000000000000000000000000000000000000000000000000006000527f9e33802b94a5b5ebfeaa1630ee645e08a3449bd86e190a9ecd7ced7baf89913280549091169091179055600c8054600160a060020a031990811633908117909255600d8054821683179055600e8054821683179055600f805490911690911790556011805460a060020a60ff021916740100000000000000000000000000000000000000001790556040805180820190915260138082527f43727970746f526f6d652d4c616e642d4e46540000000000000000000000000091909201908152620001f191600891906200023f565b506040805180820190915260068082527f43524c414e440000000000000000000000000000000000000000000000000000602090920191825262000238916009916200023f565b50620002e4565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200028257805160ff1916838001178555620002b2565b82800160010185558215620002b2579182015b82811115620002b257825182559160200191906001019062000295565b50620002c0929150620002c4565b5090565b620002e191905b80821115620002c05760008155600101620002cb565b90565b61314780620002f46000396000f30060806040526004361061028f5763ffffffff60e060020a60003504166301ffc9a78114610294578063051847d5146102df57806306fdde0314610318578063081812fc146103a2578063095ea7b3146103d65780630b1ad18d146103fc57806318160ddd1461041d5780631e1e3c5b14610432578063216a55431461045957806323b872dd146104be5780632f745c59146104e857806337efa3971461050c5780633f4ba83a1461052157806342842e0e1461053657806343a61a8e1461056057806343bad081146105785780634f558e79146105995780634f6ccce7146105b15780635c975abb146105c95780635e3e2687146105de5780635fd8c710146106575780636352211e1461066c5780636af04a57146106845780636eccc6a31461069957806370a08231146106d057806371587988146106f15780637fcdcb9a146107125780638009d5d7146107335780638456cb591461073e5780638462151c146107535780638600f2ec1461077457806389885a591461079857806390b62297146107d05780639335dcb7146107e857806395910d46146107fd57806395d89b4114610812578063a22cb46514610827578063ae9409031461084d578063b5f4968c14610868578063b88d4fde14610880578063bd2f37ba146108b9578063c0a899f2146108d1578063c87b56dd14610911578063cfef941b14610929578063d00155001461094a578063d16d9f411461095f578063d1ce65ab14610980578063d52e7f9314610995578063d621c878146109b6578063d8bbe8cf146109cb578063dbd1a08e146109f2578063e0df5b6f14610a13578063e11304f914610a33578063e87596c014610a4e578063e985e9c514610a66578063f02dd53f14610a8d578063f50acfa014610ada575b600080fd5b3480156102a057600080fd5b506102cb7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1960043516610b51565b604080519115158252519081900360200190f35b3480156102eb57600080fd5b50610306600160a060020a0360043516602435604435610b85565b60408051918252519081900360200190f35b34801561032457600080fd5b5061032d610bf7565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561036757818101518382015260200161034f565b50505050905090810190601f1680156103945780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156103ae57600080fd5b506103ba600435610c8e565b60408051600160a060020a039092168252519081900360200190f35b3480156103e257600080fd5b506103fa600160a060020a0360043516602435610cca565b005b34801561040857600080fd5b506103fa600160a060020a0360043516610da6565b34801561042957600080fd5b50610306610e0b565b34801561043e57600080fd5b50610306600160a060020a0360043516602435604435610e11565b34801561046557600080fd5b5061046e610e89565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156104aa578181015183820152602001610492565b505050509050019250505060405180910390f35b3480156104ca57600080fd5b506103fa600160a060020a0360043581169060243516604435610ee0565b3480156104f457600080fd5b50610306600160a060020a0360043516602435610f11565b34801561051857600080fd5b506103ba610f6c565b34801561052d57600080fd5b506103fa610f7b565b34801561054257600080fd5b506103fa600160a060020a0360043581169060243516604435610fe1565b34801561056c57600080fd5b5061030660043561101e565b34801561058457600080fd5b506103fa600160a060020a0360043516611360565b3480156105a557600080fd5b506102cb6004356113ff565b3480156105bd57600080fd5b50610306600435611406565b3480156105d557600080fd5b506102cb611419565b3480156105ea57600080fd5b50604080516020601f6084356004818101359283018490048402850184019095528184526103fa94600160a060020a0381358116956024803596604435909316956064359536959460a4949391909101919081908401838280828437509497506114299650505050505050565b34801561066357600080fd5b506103fa61146d565b34801561067857600080fd5b506103ba6004356114d8565b34801561069057600080fd5b506103ba611502565b3480156106a557600080fd5b506106ba600160a060020a0360043516611511565b6040805160ff9092168252519081900360200190f35b3480156106dc57600080fd5b50610306600160a060020a0360043516611526565b3480156106fd57600080fd5b506103fa600160a060020a0360043516611559565b34801561071e57600080fd5b506103066004356024356044356064356115f0565b6103fa600435611632565b34801561074a57600080fd5b506103fa61177e565b34801561075f57600080fd5b5061046e600160a060020a03600435166117e9565b34801561078057600080fd5b50610306600160a060020a0360043516602435611855565b3480156107a457600080fd5b506107b060043561187d565b604080519384526020840192909252151582820152519081900360600190f35b3480156107dc57600080fd5b506103fa600435611908565b3480156107f457600080fd5b506103ba611996565b34801561080957600080fd5b506103ba6119a5565b34801561081e57600080fd5b5061032d6119b4565b34801561083357600080fd5b506103fa600160a060020a03600435166024351515611a15565b34801561085957600080fd5b506103fa600435602435611a98565b34801561087457600080fd5b50610306600435611b0a565b34801561088c57600080fd5b506103fa600160a060020a0360048035821691602480359091169160443591606435908101910135611b1c565b3480156108c557600080fd5b50610306600435611b6e565b3480156108dd57600080fd5b506103fa60048035600160a060020a039081169160248035926044351691606435916084359160a435918201910135611b83565b34801561091d57600080fd5b5061032d600435611ba4565b34801561093557600080fd5b50610306600435602435604435606435611c52565b34801561095657600080fd5b506103ba611deb565b34801561096b57600080fd5b506103fa600160a060020a0360043516611dfa565b34801561098c57600080fd5b506102cb611e5f565b3480156109a157600080fd5b506103fa600160a060020a0360043516611e64565b3480156109c257600080fd5b506103ba611f03565b3480156109d757600080fd5b506103fa600160a060020a036004351660ff60243516611f12565b3480156109fe57600080fd5b506103fa600160a060020a0360043516611f82565b348015610a1f57600080fd5b506103fa6004803560248101910135612021565b348015610a3f57600080fd5b506103fa600435602435612078565b348015610a5a57600080fd5b506103fa6004356120ca565b348015610a7257600080fd5b506102cb600160a060020a036004358116906024351661210f565b348015610a9957600080fd5b50610aa560043561216a565b60408051600160a060020a03909616865260208601949094528484019290925260608401526080830152519081900360a00190f35b348015610ae657600080fd5b50604080516020601f6084356004818101359283018490048402850184019095528184526103fa94600160a060020a0381358116956024803590921695604435956064359536959460a494939101919081908401838280828437509497506121ce9650505050505050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166000908152600b602052604090205460ff1690565b600160a060020a03831660009081526005602090815260408083208584529091528120548210610bb457600080fd5b600160a060020a03841660009081526005602090815260408083208684529091529020805483908110610be357fe5b906000526020600020015490509392505050565b60088054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610c835780601f10610c5857610100808354040283529160200191610c83565b820191906000526020600020905b815481529060010190602001808311610c6657829003601f168201915b505050505090505b90565b600080610c9a8361101e565b600160a060020a038082166000908152600460209081526040808320888452909152902054169250905050919050565b600081815260016020526040812054600160a060020a031690811515610cef57600080fd5b610cf88361101e565b9050600160a060020a038116331480610d345750600160a060020a038116600090815260076020908152604080832033845290915290205460ff165b1515610d3f57600080fd5b600160a060020a0381811660008181526004602090815260408083208884529091528082208054600160a060020a031916948916948517905551869392917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a450505050565b600c54600160a060020a0316331480610dc95750600d54600160a060020a031633145b1515610dd457600080fd5b600160a060020a0381161515610de957600080fd5b600f8054600160a060020a031916600160a060020a0392909216919091179055565b60005490565b600c54600090600160a060020a0316331480610e375750600d54600160a060020a031633145b80610e5457503360009081526010602052604090205460ff166001145b1515610e5f57600080fd5b60115460a060020a900460ff1615610e7657600080fd5b610e818484846121e5565b949350505050565b60606014805480602002602001604051908101604052809291908181526020018280548015610c8357602002820191906000526020600020905b815481526020019060010190808311610ec3575050505050905090565b600160a060020a038216301415610ef657600080fd5b610f018383836122e6565b610f0c8383836124d0565b505050565b600160a060020a0382166000908152600260205260408120548210610f3557600080fd5b600160a060020a0383166000908152600260205260409020805483908110610f5957fe5b9060005260206000200154905092915050565b600f54600160a060020a031681565b600c54600160a060020a0316331480610f9e5750600d54600160a060020a031633145b1515610fa957600080fd5b60115460a060020a900460ff161515610fc157600080fd5b6011805474ff000000000000000000000000000000000000000019169055565b610fec8383836122e6565b610ff78383836124d0565b611013838383602060405190810160405280600081525061264c565b1515610f0c57600080fd5b600081815260016020526040812054600160a060020a031681806060818085151561104857600080fd5b600088815260016020819052604082200154955085119350831561106e57600019909401935b600160a060020a0386163014156110e4575b8315156110ba577fcd740db500000000000000000000000000000000000000000000000000000000600160a060020a038716179650611355565b6110c3856127c0565b91975095509350600160a060020a0386163014156110e057611080565b8497505b8315156111b4576040805130602482015260448082018b905282518083039091018152606490910190915260208181018051600160e060020a03167fed81cdda00000000000000000000000000000000000000000000000000000000178152825192955090918591895afa9150811561115c57825196505b6001821515148015611177575060e060020a870463cd740db5145b1561118157611355565b7fcd740db500000000000000000000000000000000000000000000000000000000600160a060020a038716179650611355565b60408051602480820188905282518083039091018152604490910190915260208181018051600160e060020a03167f43a61a8e00000000000000000000000000000000000000000000000000000000178152825192955090918591895afa9150811561121f57825196505b600182151514801561123a575060e060020a870463cd740db5145b1561124457611355565b5060408051602480820187905282518083039091018152604490910190915260208181018051600160e060020a03167f6352211e00000000000000000000000000000000000000000000000000000000178152825192945087928591845afa915081156112b057825195505b8115156112bc57600080fd5b60408051600160a060020a0383166024820152604480820188905282518083039091018152606490910190915260208181018051600160e060020a03167fed81cdda00000000000000000000000000000000000000000000000000000000178152825192955090918591895afa9150811561115c57825196506001821515148015611177575060e060020a870463cd740db51415611181575b505050505050919050565b600c54600160a060020a03163314806113835750600d54600160a060020a031633145b151561138e57600080fd5b600160a060020a03811615156113a357600080fd5b600c54604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600c8054600160a060020a031916600160a060020a0392909216919091179055565b6000541190565b60008054821061141557600080fd5b5090565b60115460a060020a900460ff1681565b61143585858585612818565b60008281526006602052604081205561144f8584846124d0565b61145b8584848461264c565b151561146657600080fd5b5050505050565b600c54600160a060020a03163314806114905750600d54600160a060020a031633145b151561149b57600080fd5b600e54604051600160a060020a0390911690303180156108fc02916000818181858888f193505050501580156114d5573d6000803e3d6000fd5b50565b600081815260016020526040812054600160a060020a03168015156114fc57600080fd5b92915050565b601254600160a060020a031681565b60106020526000908152604090205460ff1681565b6000600160a060020a038216151561153d57600080fd5b50600160a060020a031660009081526002602052604090205490565b600c54600160a060020a031633148061157c5750600d54600160a060020a031633145b151561158757600080fd5b600160a060020a038116151561159c57600080fd5b60128054600160a060020a038316600160a060020a0319909116811790915560408051918252517f450db8da6efbe9c22f2347f7c2021231df1fc58d3ae9a2fa75d39fa4461993059181900360200190a150565b601154600090819060a060020a900460ff161561160c57600080fd5b611618338760006121e5565b905061162681868686611c52565b91505b50949350505050565b60115460009081908190819060a060020a900460ff161561165257600080fd5b60008581526013602052604090206002015493503484111561167357600080fd5b61167e8560006129f1565b61168784612ad0565b9250611699348463ffffffff612af416565b600f54604051919350600160a060020a03169084156108fc029085906000818181858888f193505050501580156116d4573d6000803e3d6000fd5b506116e5348563ffffffff612af416565b604051909150339082156108fc029083906000818181858888f19350505050158015611715573d6000803e3d6000fd5b50600085815260016020526040808220549051600160a060020a039091169184156108fc02918591818181858888f1935050505015801561175a573d6000803e3d6000fd5b5060008581526001602052604090205461146690600160a060020a031633876124d0565b600c54600160a060020a03163314806117a15750600d54600160a060020a031633145b15156117ac57600080fd5b60115460a060020a900460ff16156117c357600080fd5b6011805474ff0000000000000000000000000000000000000000191660a060020a179055565b600160a060020a03811660009081526002602090815260409182902080548351818402810184019094528084526060939283018282801561184957602002820191906000526020600020905b815481526020019060010190808311611835575b50505050509050919050565b600160a060020a03919091166000908152600560209081526040808320938352929052205490565b60008181526001602052604081205481908190600160a060020a03168015156118a557600080fd5b60008581526001602081905260408220015493508311156118d05760001990920191600191506118d5565b600091505b600160a060020a03167fcd740db50000000000000000000000000000000000000000000000000000000017949193509150565b6011546000908190819060a060020a900460ff161561192657600080fd5b6119303085611855565b92506000831161193f57600080fd5b8291505b60008211156119855761195a308560018503610b85565b9050611979308533846020604051908101604052806000815250611429565b60001990910190611943565b6119903330866124d0565b50505050565b600e54600160a060020a031681565b600c54600160a060020a031681565b60098054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610c835780601f10610c5857610100808354040283529160200191610c83565b600160a060020a0382161515611a2a57600080fd5b336000818152600760209081526040808320600160a060020a03871680855290835292819020805460ff1916861515908117909155815190815290519293927f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31929181900390910190a35050565b60115460a060020a900460ff1615611aaf57600080fd5b600082815260016020526040902054600160a060020a03163314611ad257600080fd5b6000828152600160208190526040909120015415611aef57600080fd5b60008111611afc57600080fd5b611b0682826129f1565b5050565b60009081526015602052604090205490565b611b278585856122e6565b611b328585856124d0565b61145b85858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375061264c945050505050565b60009081526013602052604090206001015490565b611b8f87878786612818565b611b9b87868686612b12565b50505050505050565b6060611baf826113ff565b1515611bba57600080fd5b600a8054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526114fc9390929091830182828015611c475780601f10611c1c57610100808354040283529160200191611c47565b820191906000526020600020905b815481529060010190602001808311611c2a57829003601f168201915b505050505083612c5d565b601154600090819060a060020a900460ff1615611c6e57600080fd5b60008681526013602052604090205460021480611c9957506000868152601360205260409020546003145b1515611ca457600080fd5b600086815260136020526040902054611cc490600163ffffffff612af416565b60008681526013602052604090205490915081148015611cf1575060008481526013602052604090205481145b8015611d0a575060008381526013602052604090205481145b1515611d1557600080fd5b6000858152600160209081526040808320548151928301909152918152611d4b91600160a060020a0316903090899089906121ce565b6000848152600160209081526040808320548151928301909152918152611d8191600160a060020a0316903090899088906121ce565b6000838152600160209081526040808320548151928301909152918152611db791600160a060020a0316903090899087906121ce565b600086815260016020526040902054600160a060020a0316301415611de157611de13033886124d0565b5093949350505050565b600d54600160a060020a031681565b600c54600160a060020a0316331480611e1d5750600d54600160a060020a031633145b1515611e2857600080fd5b600160a060020a0381161515611e3d57600080fd5b600e8054600160a060020a031916600160a060020a0392909216919091179055565b600190565b600c54600160a060020a0316331480611e875750600d54600160a060020a031633145b1515611e9257600080fd5b600160a060020a0381161515611ea757600080fd5b600d54604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600d8054600160a060020a031916600160a060020a0392909216919091179055565b601154600160a060020a031681565b600c54600160a060020a0316331480611f355750600d54600160a060020a031633145b1515611f4057600080fd5b600160a060020a0382161515611f5557600080fd5b600160a060020a03919091166000908152601060205260409020805460ff191660ff909216919091179055565b600c54600160a060020a0316331480611fa55750600d54600160a060020a031633145b1515611fb057600080fd5b600160a060020a0381161515611fc557600080fd5b601154604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a360118054600160a060020a031916600160a060020a0392909216919091179055565b600c54600160a060020a03163314806120445750600d54600160a060020a031633145b8061206157503360009081526010602052604090205460ff166001145b151561206c57600080fd5b610f0c600a8383613045565b60115460a060020a900460ff161561208f57600080fd5b601154600160a060020a031633146120a657600080fd5b6000548211156120b557600080fd5b60009182526013602052604090912060010155565b60115460a060020a900460ff16156120e157600080fd5b600081815260016020526040902054600160a060020a0316331461210457600080fd5b6114d58160006129f1565b6000600160a060020a038316151561212657600080fd5b600160a060020a038216151561213b57600080fd5b50600160a060020a03918216600090815260076020908152604080832093909416825291909152205460ff1690565b6000818152600160208181526040808420601390925283209181015491839182918291908286111561219e57600019909501945b8154600192830154825493830154600290930154600160a060020a039092169a9099509297509095509350915050565b6121d98585846122e6565b61146685858585612b12565b60006121ef6130bf565b600160a060020a038516151561220457600080fd5b600160005260156020527f27739e4bb5e6f8b5e4b57a047dca8767cc9b982a011081e086cbb0dfa9de818d5461c3501161223d57600080fd5b5050600080546040805160608101825285815260208082018681528284018681528587526013835284872084518155915160018084019190915590516002909201919091558786526015909152919093208054909101905590610100820615156122d4576014805460018101825560009182527fce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec01555b6122de8583612e2c565b509392505050565b600080806060600160a060020a038716151561230157600080fd5b600160a060020a038616151561231657600080fd5b600085815260016020526040902054600160a060020a0388811691161461233c57600080fd5b600085815260016020819052604090912001541561235957600080fd5b600160a060020a0380881660008181526004602090815260408083208a84529091529020549091169450331461245d575060408051306024820152604480820187905282518083039091018152606490910190915260208181018051600160e060020a03167fed81cdda00000000000000000000000000000000000000000000000000000000178152825183918a5afa915081156123f657805192505b600182151514156124185760e060020a830463cd740db5141561241857600080fd5b600160a060020a038716600090815260076020908152604080832033845290915290205460ff16806124525750600160a060020a03841633145b151561245d57600080fd5b600160a060020a03841615611b9b57600160a060020a03871660008181526004602090815260408083208984529091528082208054600160a060020a0319169055518792907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925908390a450505050505050565b600160a060020a038316600090815260026020526040812054819081906124fe90600163ffffffff612af416565b600160a060020a03871660009081526002602052604090208054919450908490811061252657fe5b9060005260206000200154915083821415156125935750600083815260036020908152604080832054600160a060020a0389168452600290925290912080548391908390811061257257fe5b60009182526020808320909101929092558381526003909152604090208190555b600160a060020a03861660009081526002602052604090208054906125bc9060001983016130e1565b5060008481526001602081815260408084208054600160a060020a031916600160a060020a038b8116918217909255808652600280855283872080548c895260038752858920819055918652958101865594865292852090930188905551879391928a16917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050505050565b60008061265885612ef2565b15156126675760019150611629565b6040517f150b7a020000000000000000000000000000000000000000000000000000000081523360048201818152600160a060020a03898116602485015260448401889052608060648501908152875160848601528751918a169463150b7a0294938c938b938b93909160a490910190602085019080838360005b838110156126fa5781810151838201526020016126e2565b50505050905090810190601f1680156127275780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b15801561274957600080fd5b505af115801561275d573d6000803e3d6000fd5b505050506040513d602081101561277357600080fd5b50517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f150b7a0200000000000000000000000000000000000000000000000000000000149695505050505050565b600081815260016020526040812054600160a060020a031690808215156127e657600080fd5b600084815260016020819052604082200154925082111561280d5750600019016001612811565b5060005b9193909250565b60008080600160a060020a038716151561283157600080fd5b600160a060020a038516151561284657600080fd5b600084815260016020526040902054600160a060020a0388811691161461286c57600080fd5b60008481526001602081905260409091200154925082151561288d57600080fd5b6000198301861461289d57600080fd5b6128a68461101e565b600160a060020a0380821660008181526004602090815260408083208a8452909152902054929450911691503314806129025750600160a060020a038216600090815260076020908152604080832033845290915290205460ff165b806129155750600160a060020a03811633145b151561292057600080fd5b600160a060020a0381161561298b57600160a060020a03821660008181526004602090815260408083208884529091528082208054600160a060020a0319169055518692907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925908390a45b6000848152600160208190526040822001556129a8878786612efa565b6040805185815290518791600160a060020a038a16917f3c619d5b30fb8431c0c0094f4485f1859d63f222f36cc2104cc13e56c2b993d39181900360200190a350505050505050565b6000828152601360205260408120600201829055811115612a6e57610100820660020a6014612a288461010063ffffffff612fdb16565b81548110612a3257fe5b600091825260209091200154176014612a538461010063ffffffff612fdb16565b81548110612a5d57fe5b600091825260209091200155611b06565b610100820660020a196014612a8b8461010063ffffffff612fdb16565b81548110612a9557fe5b600091825260209091200154166014612ab68461010063ffffffff612fdb16565b81548110612ac057fe5b6000918252602090912001555050565b60006114fc6064612ae884600363ffffffff612ffe16565b9063ffffffff612fdb16565b60008083831115612b0457600080fd5b5050808203805b5092915050565b6000612b2583600163ffffffff61303316565b6000838152600160208181526040808420830194909455600160a060020a03881683526005815283832087845281528383208054928301815583528083208201869055858352600690529190208190559050612b828585846124d0565b6000600160a060020a031684600160a060020a0316636352211e856040518263ffffffff1660e060020a02815260040180828152602001915050602060405180830381600087803b158015612bd657600080fd5b505af1158015612bea573d6000803e3d6000fd5b505050506040513d6020811015612c0057600080fd5b5051600160a060020a03161415612c1657600080fd5b6040805183815290518491600160a060020a038716917fda19c10bf4b88776cd85f9091592a44edff2d94035ec670ebd9e8356f56f887d9181900360200190a35050505050565b60408051606480825260a0820190925260609190829060009081908390819083908760208201610c8080388339019050509550600094505b8815612cf8578551600a808b049a6001880197919006955060f860020a6030870102918891908110612cc357fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350612c95565b899250848351016040519080825280601f01601f191660200182016040528015612d2c578160200160208202803883390190505b509150600090505b8251811015612da4578281815181101515612d4b57fe5b90602001015160f860020a900460f860020a028282815181101515612d6c57fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600101612d34565b5060005b84811015612e1f5785816001870303815181101515612dc357fe5b90602001015160f860020a900460f860020a028284518301815181101515612de757fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600101612da8565b5098975050505050505050565b600160a060020a0382161515612e4157600080fd5b600081815260016020526040902054600160a060020a031615612e6357600080fd5b60008181526001602081815260408084208054600160a060020a031916600160a060020a0388169081179091558085526002808452828620805488885260038652848820819055918552818601815586529285209092018590558354909201835590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000903b1190565b600160a060020a03831660009081526005602090815260408083208584529091528120805460001981019291829184908110612f3257fe5b906000526020600020015491508184141515612fa75750600083815260066020908152604080832054600160a060020a038916845260058352818420888552909252909120805483919083908110612f8657fe5b60009182526020808320909101929092558381526006909152604090208190555b600160a060020a03861660009081526005602090815260408083208884529091529020805490611b9b9060001983016130e1565b600080808311612fea57600080fd5b8284811515612ff557fe5b04949350505050565b6000808315156130115760009150612b0b565b5082820282848281151561302157fe5b041461302c57600080fd5b9392505050565b60008282018381101561302c57600080fd5b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106130865782800160ff198235161785556130b3565b828001600101855582156130b3579182015b828111156130b3578235825591602001919060010190613098565b50611415929150613101565b6060604051908101604052806000815260200160008152602001600081525090565b815481835581811115610f0c57600083815260209020610f0c9181019083015b610c8b91905b8082111561141557600081556001016131075600a165627a7a723058203bac0f675bcdf51c3197b6eda1a5774c29cb9df158ccff4398ebc9bf256d99900029

Deployed Bytecode

0x60806040526004361061028f5763ffffffff60e060020a60003504166301ffc9a78114610294578063051847d5146102df57806306fdde0314610318578063081812fc146103a2578063095ea7b3146103d65780630b1ad18d146103fc57806318160ddd1461041d5780631e1e3c5b14610432578063216a55431461045957806323b872dd146104be5780632f745c59146104e857806337efa3971461050c5780633f4ba83a1461052157806342842e0e1461053657806343a61a8e1461056057806343bad081146105785780634f558e79146105995780634f6ccce7146105b15780635c975abb146105c95780635e3e2687146105de5780635fd8c710146106575780636352211e1461066c5780636af04a57146106845780636eccc6a31461069957806370a08231146106d057806371587988146106f15780637fcdcb9a146107125780638009d5d7146107335780638456cb591461073e5780638462151c146107535780638600f2ec1461077457806389885a591461079857806390b62297146107d05780639335dcb7146107e857806395910d46146107fd57806395d89b4114610812578063a22cb46514610827578063ae9409031461084d578063b5f4968c14610868578063b88d4fde14610880578063bd2f37ba146108b9578063c0a899f2146108d1578063c87b56dd14610911578063cfef941b14610929578063d00155001461094a578063d16d9f411461095f578063d1ce65ab14610980578063d52e7f9314610995578063d621c878146109b6578063d8bbe8cf146109cb578063dbd1a08e146109f2578063e0df5b6f14610a13578063e11304f914610a33578063e87596c014610a4e578063e985e9c514610a66578063f02dd53f14610a8d578063f50acfa014610ada575b600080fd5b3480156102a057600080fd5b506102cb7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1960043516610b51565b604080519115158252519081900360200190f35b3480156102eb57600080fd5b50610306600160a060020a0360043516602435604435610b85565b60408051918252519081900360200190f35b34801561032457600080fd5b5061032d610bf7565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561036757818101518382015260200161034f565b50505050905090810190601f1680156103945780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156103ae57600080fd5b506103ba600435610c8e565b60408051600160a060020a039092168252519081900360200190f35b3480156103e257600080fd5b506103fa600160a060020a0360043516602435610cca565b005b34801561040857600080fd5b506103fa600160a060020a0360043516610da6565b34801561042957600080fd5b50610306610e0b565b34801561043e57600080fd5b50610306600160a060020a0360043516602435604435610e11565b34801561046557600080fd5b5061046e610e89565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156104aa578181015183820152602001610492565b505050509050019250505060405180910390f35b3480156104ca57600080fd5b506103fa600160a060020a0360043581169060243516604435610ee0565b3480156104f457600080fd5b50610306600160a060020a0360043516602435610f11565b34801561051857600080fd5b506103ba610f6c565b34801561052d57600080fd5b506103fa610f7b565b34801561054257600080fd5b506103fa600160a060020a0360043581169060243516604435610fe1565b34801561056c57600080fd5b5061030660043561101e565b34801561058457600080fd5b506103fa600160a060020a0360043516611360565b3480156105a557600080fd5b506102cb6004356113ff565b3480156105bd57600080fd5b50610306600435611406565b3480156105d557600080fd5b506102cb611419565b3480156105ea57600080fd5b50604080516020601f6084356004818101359283018490048402850184019095528184526103fa94600160a060020a0381358116956024803596604435909316956064359536959460a4949391909101919081908401838280828437509497506114299650505050505050565b34801561066357600080fd5b506103fa61146d565b34801561067857600080fd5b506103ba6004356114d8565b34801561069057600080fd5b506103ba611502565b3480156106a557600080fd5b506106ba600160a060020a0360043516611511565b6040805160ff9092168252519081900360200190f35b3480156106dc57600080fd5b50610306600160a060020a0360043516611526565b3480156106fd57600080fd5b506103fa600160a060020a0360043516611559565b34801561071e57600080fd5b506103066004356024356044356064356115f0565b6103fa600435611632565b34801561074a57600080fd5b506103fa61177e565b34801561075f57600080fd5b5061046e600160a060020a03600435166117e9565b34801561078057600080fd5b50610306600160a060020a0360043516602435611855565b3480156107a457600080fd5b506107b060043561187d565b604080519384526020840192909252151582820152519081900360600190f35b3480156107dc57600080fd5b506103fa600435611908565b3480156107f457600080fd5b506103ba611996565b34801561080957600080fd5b506103ba6119a5565b34801561081e57600080fd5b5061032d6119b4565b34801561083357600080fd5b506103fa600160a060020a03600435166024351515611a15565b34801561085957600080fd5b506103fa600435602435611a98565b34801561087457600080fd5b50610306600435611b0a565b34801561088c57600080fd5b506103fa600160a060020a0360048035821691602480359091169160443591606435908101910135611b1c565b3480156108c557600080fd5b50610306600435611b6e565b3480156108dd57600080fd5b506103fa60048035600160a060020a039081169160248035926044351691606435916084359160a435918201910135611b83565b34801561091d57600080fd5b5061032d600435611ba4565b34801561093557600080fd5b50610306600435602435604435606435611c52565b34801561095657600080fd5b506103ba611deb565b34801561096b57600080fd5b506103fa600160a060020a0360043516611dfa565b34801561098c57600080fd5b506102cb611e5f565b3480156109a157600080fd5b506103fa600160a060020a0360043516611e64565b3480156109c257600080fd5b506103ba611f03565b3480156109d757600080fd5b506103fa600160a060020a036004351660ff60243516611f12565b3480156109fe57600080fd5b506103fa600160a060020a0360043516611f82565b348015610a1f57600080fd5b506103fa6004803560248101910135612021565b348015610a3f57600080fd5b506103fa600435602435612078565b348015610a5a57600080fd5b506103fa6004356120ca565b348015610a7257600080fd5b506102cb600160a060020a036004358116906024351661210f565b348015610a9957600080fd5b50610aa560043561216a565b60408051600160a060020a03909616865260208601949094528484019290925260608401526080830152519081900360a00190f35b348015610ae657600080fd5b50604080516020601f6084356004818101359283018490048402850184019095528184526103fa94600160a060020a0381358116956024803590921695604435956064359536959460a494939101919081908401838280828437509497506121ce9650505050505050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166000908152600b602052604090205460ff1690565b600160a060020a03831660009081526005602090815260408083208584529091528120548210610bb457600080fd5b600160a060020a03841660009081526005602090815260408083208684529091529020805483908110610be357fe5b906000526020600020015490509392505050565b60088054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610c835780601f10610c5857610100808354040283529160200191610c83565b820191906000526020600020905b815481529060010190602001808311610c6657829003601f168201915b505050505090505b90565b600080610c9a8361101e565b600160a060020a038082166000908152600460209081526040808320888452909152902054169250905050919050565b600081815260016020526040812054600160a060020a031690811515610cef57600080fd5b610cf88361101e565b9050600160a060020a038116331480610d345750600160a060020a038116600090815260076020908152604080832033845290915290205460ff165b1515610d3f57600080fd5b600160a060020a0381811660008181526004602090815260408083208884529091528082208054600160a060020a031916948916948517905551869392917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a450505050565b600c54600160a060020a0316331480610dc95750600d54600160a060020a031633145b1515610dd457600080fd5b600160a060020a0381161515610de957600080fd5b600f8054600160a060020a031916600160a060020a0392909216919091179055565b60005490565b600c54600090600160a060020a0316331480610e375750600d54600160a060020a031633145b80610e5457503360009081526010602052604090205460ff166001145b1515610e5f57600080fd5b60115460a060020a900460ff1615610e7657600080fd5b610e818484846121e5565b949350505050565b60606014805480602002602001604051908101604052809291908181526020018280548015610c8357602002820191906000526020600020905b815481526020019060010190808311610ec3575050505050905090565b600160a060020a038216301415610ef657600080fd5b610f018383836122e6565b610f0c8383836124d0565b505050565b600160a060020a0382166000908152600260205260408120548210610f3557600080fd5b600160a060020a0383166000908152600260205260409020805483908110610f5957fe5b9060005260206000200154905092915050565b600f54600160a060020a031681565b600c54600160a060020a0316331480610f9e5750600d54600160a060020a031633145b1515610fa957600080fd5b60115460a060020a900460ff161515610fc157600080fd5b6011805474ff000000000000000000000000000000000000000019169055565b610fec8383836122e6565b610ff78383836124d0565b611013838383602060405190810160405280600081525061264c565b1515610f0c57600080fd5b600081815260016020526040812054600160a060020a031681806060818085151561104857600080fd5b600088815260016020819052604082200154955085119350831561106e57600019909401935b600160a060020a0386163014156110e4575b8315156110ba577fcd740db500000000000000000000000000000000000000000000000000000000600160a060020a038716179650611355565b6110c3856127c0565b91975095509350600160a060020a0386163014156110e057611080565b8497505b8315156111b4576040805130602482015260448082018b905282518083039091018152606490910190915260208181018051600160e060020a03167fed81cdda00000000000000000000000000000000000000000000000000000000178152825192955090918591895afa9150811561115c57825196505b6001821515148015611177575060e060020a870463cd740db5145b1561118157611355565b7fcd740db500000000000000000000000000000000000000000000000000000000600160a060020a038716179650611355565b60408051602480820188905282518083039091018152604490910190915260208181018051600160e060020a03167f43a61a8e00000000000000000000000000000000000000000000000000000000178152825192955090918591895afa9150811561121f57825196505b600182151514801561123a575060e060020a870463cd740db5145b1561124457611355565b5060408051602480820187905282518083039091018152604490910190915260208181018051600160e060020a03167f6352211e00000000000000000000000000000000000000000000000000000000178152825192945087928591845afa915081156112b057825195505b8115156112bc57600080fd5b60408051600160a060020a0383166024820152604480820188905282518083039091018152606490910190915260208181018051600160e060020a03167fed81cdda00000000000000000000000000000000000000000000000000000000178152825192955090918591895afa9150811561115c57825196506001821515148015611177575060e060020a870463cd740db51415611181575b505050505050919050565b600c54600160a060020a03163314806113835750600d54600160a060020a031633145b151561138e57600080fd5b600160a060020a03811615156113a357600080fd5b600c54604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600c8054600160a060020a031916600160a060020a0392909216919091179055565b6000541190565b60008054821061141557600080fd5b5090565b60115460a060020a900460ff1681565b61143585858585612818565b60008281526006602052604081205561144f8584846124d0565b61145b8584848461264c565b151561146657600080fd5b5050505050565b600c54600160a060020a03163314806114905750600d54600160a060020a031633145b151561149b57600080fd5b600e54604051600160a060020a0390911690303180156108fc02916000818181858888f193505050501580156114d5573d6000803e3d6000fd5b50565b600081815260016020526040812054600160a060020a03168015156114fc57600080fd5b92915050565b601254600160a060020a031681565b60106020526000908152604090205460ff1681565b6000600160a060020a038216151561153d57600080fd5b50600160a060020a031660009081526002602052604090205490565b600c54600160a060020a031633148061157c5750600d54600160a060020a031633145b151561158757600080fd5b600160a060020a038116151561159c57600080fd5b60128054600160a060020a038316600160a060020a0319909116811790915560408051918252517f450db8da6efbe9c22f2347f7c2021231df1fc58d3ae9a2fa75d39fa4461993059181900360200190a150565b601154600090819060a060020a900460ff161561160c57600080fd5b611618338760006121e5565b905061162681868686611c52565b91505b50949350505050565b60115460009081908190819060a060020a900460ff161561165257600080fd5b60008581526013602052604090206002015493503484111561167357600080fd5b61167e8560006129f1565b61168784612ad0565b9250611699348463ffffffff612af416565b600f54604051919350600160a060020a03169084156108fc029085906000818181858888f193505050501580156116d4573d6000803e3d6000fd5b506116e5348563ffffffff612af416565b604051909150339082156108fc029083906000818181858888f19350505050158015611715573d6000803e3d6000fd5b50600085815260016020526040808220549051600160a060020a039091169184156108fc02918591818181858888f1935050505015801561175a573d6000803e3d6000fd5b5060008581526001602052604090205461146690600160a060020a031633876124d0565b600c54600160a060020a03163314806117a15750600d54600160a060020a031633145b15156117ac57600080fd5b60115460a060020a900460ff16156117c357600080fd5b6011805474ff0000000000000000000000000000000000000000191660a060020a179055565b600160a060020a03811660009081526002602090815260409182902080548351818402810184019094528084526060939283018282801561184957602002820191906000526020600020905b815481526020019060010190808311611835575b50505050509050919050565b600160a060020a03919091166000908152600560209081526040808320938352929052205490565b60008181526001602052604081205481908190600160a060020a03168015156118a557600080fd5b60008581526001602081905260408220015493508311156118d05760001990920191600191506118d5565b600091505b600160a060020a03167fcd740db50000000000000000000000000000000000000000000000000000000017949193509150565b6011546000908190819060a060020a900460ff161561192657600080fd5b6119303085611855565b92506000831161193f57600080fd5b8291505b60008211156119855761195a308560018503610b85565b9050611979308533846020604051908101604052806000815250611429565b60001990910190611943565b6119903330866124d0565b50505050565b600e54600160a060020a031681565b600c54600160a060020a031681565b60098054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610c835780601f10610c5857610100808354040283529160200191610c83565b600160a060020a0382161515611a2a57600080fd5b336000818152600760209081526040808320600160a060020a03871680855290835292819020805460ff1916861515908117909155815190815290519293927f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31929181900390910190a35050565b60115460a060020a900460ff1615611aaf57600080fd5b600082815260016020526040902054600160a060020a03163314611ad257600080fd5b6000828152600160208190526040909120015415611aef57600080fd5b60008111611afc57600080fd5b611b0682826129f1565b5050565b60009081526015602052604090205490565b611b278585856122e6565b611b328585856124d0565b61145b85858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375061264c945050505050565b60009081526013602052604090206001015490565b611b8f87878786612818565b611b9b87868686612b12565b50505050505050565b6060611baf826113ff565b1515611bba57600080fd5b600a8054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526114fc9390929091830182828015611c475780601f10611c1c57610100808354040283529160200191611c47565b820191906000526020600020905b815481529060010190602001808311611c2a57829003601f168201915b505050505083612c5d565b601154600090819060a060020a900460ff1615611c6e57600080fd5b60008681526013602052604090205460021480611c9957506000868152601360205260409020546003145b1515611ca457600080fd5b600086815260136020526040902054611cc490600163ffffffff612af416565b60008681526013602052604090205490915081148015611cf1575060008481526013602052604090205481145b8015611d0a575060008381526013602052604090205481145b1515611d1557600080fd5b6000858152600160209081526040808320548151928301909152918152611d4b91600160a060020a0316903090899089906121ce565b6000848152600160209081526040808320548151928301909152918152611d8191600160a060020a0316903090899088906121ce565b6000838152600160209081526040808320548151928301909152918152611db791600160a060020a0316903090899087906121ce565b600086815260016020526040902054600160a060020a0316301415611de157611de13033886124d0565b5093949350505050565b600d54600160a060020a031681565b600c54600160a060020a0316331480611e1d5750600d54600160a060020a031633145b1515611e2857600080fd5b600160a060020a0381161515611e3d57600080fd5b600e8054600160a060020a031916600160a060020a0392909216919091179055565b600190565b600c54600160a060020a0316331480611e875750600d54600160a060020a031633145b1515611e9257600080fd5b600160a060020a0381161515611ea757600080fd5b600d54604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600d8054600160a060020a031916600160a060020a0392909216919091179055565b601154600160a060020a031681565b600c54600160a060020a0316331480611f355750600d54600160a060020a031633145b1515611f4057600080fd5b600160a060020a0382161515611f5557600080fd5b600160a060020a03919091166000908152601060205260409020805460ff191660ff909216919091179055565b600c54600160a060020a0316331480611fa55750600d54600160a060020a031633145b1515611fb057600080fd5b600160a060020a0381161515611fc557600080fd5b601154604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a360118054600160a060020a031916600160a060020a0392909216919091179055565b600c54600160a060020a03163314806120445750600d54600160a060020a031633145b8061206157503360009081526010602052604090205460ff166001145b151561206c57600080fd5b610f0c600a8383613045565b60115460a060020a900460ff161561208f57600080fd5b601154600160a060020a031633146120a657600080fd5b6000548211156120b557600080fd5b60009182526013602052604090912060010155565b60115460a060020a900460ff16156120e157600080fd5b600081815260016020526040902054600160a060020a0316331461210457600080fd5b6114d58160006129f1565b6000600160a060020a038316151561212657600080fd5b600160a060020a038216151561213b57600080fd5b50600160a060020a03918216600090815260076020908152604080832093909416825291909152205460ff1690565b6000818152600160208181526040808420601390925283209181015491839182918291908286111561219e57600019909501945b8154600192830154825493830154600290930154600160a060020a039092169a9099509297509095509350915050565b6121d98585846122e6565b61146685858585612b12565b60006121ef6130bf565b600160a060020a038516151561220457600080fd5b600160005260156020527f27739e4bb5e6f8b5e4b57a047dca8767cc9b982a011081e086cbb0dfa9de818d5461c3501161223d57600080fd5b5050600080546040805160608101825285815260208082018681528284018681528587526013835284872084518155915160018084019190915590516002909201919091558786526015909152919093208054909101905590610100820615156122d4576014805460018101825560009182527fce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec01555b6122de8583612e2c565b509392505050565b600080806060600160a060020a038716151561230157600080fd5b600160a060020a038616151561231657600080fd5b600085815260016020526040902054600160a060020a0388811691161461233c57600080fd5b600085815260016020819052604090912001541561235957600080fd5b600160a060020a0380881660008181526004602090815260408083208a84529091529020549091169450331461245d575060408051306024820152604480820187905282518083039091018152606490910190915260208181018051600160e060020a03167fed81cdda00000000000000000000000000000000000000000000000000000000178152825183918a5afa915081156123f657805192505b600182151514156124185760e060020a830463cd740db5141561241857600080fd5b600160a060020a038716600090815260076020908152604080832033845290915290205460ff16806124525750600160a060020a03841633145b151561245d57600080fd5b600160a060020a03841615611b9b57600160a060020a03871660008181526004602090815260408083208984529091528082208054600160a060020a0319169055518792907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925908390a450505050505050565b600160a060020a038316600090815260026020526040812054819081906124fe90600163ffffffff612af416565b600160a060020a03871660009081526002602052604090208054919450908490811061252657fe5b9060005260206000200154915083821415156125935750600083815260036020908152604080832054600160a060020a0389168452600290925290912080548391908390811061257257fe5b60009182526020808320909101929092558381526003909152604090208190555b600160a060020a03861660009081526002602052604090208054906125bc9060001983016130e1565b5060008481526001602081815260408084208054600160a060020a031916600160a060020a038b8116918217909255808652600280855283872080548c895260038752858920819055918652958101865594865292852090930188905551879391928a16917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050505050565b60008061265885612ef2565b15156126675760019150611629565b6040517f150b7a020000000000000000000000000000000000000000000000000000000081523360048201818152600160a060020a03898116602485015260448401889052608060648501908152875160848601528751918a169463150b7a0294938c938b938b93909160a490910190602085019080838360005b838110156126fa5781810151838201526020016126e2565b50505050905090810190601f1680156127275780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b15801561274957600080fd5b505af115801561275d573d6000803e3d6000fd5b505050506040513d602081101561277357600080fd5b50517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f150b7a0200000000000000000000000000000000000000000000000000000000149695505050505050565b600081815260016020526040812054600160a060020a031690808215156127e657600080fd5b600084815260016020819052604082200154925082111561280d5750600019016001612811565b5060005b9193909250565b60008080600160a060020a038716151561283157600080fd5b600160a060020a038516151561284657600080fd5b600084815260016020526040902054600160a060020a0388811691161461286c57600080fd5b60008481526001602081905260409091200154925082151561288d57600080fd5b6000198301861461289d57600080fd5b6128a68461101e565b600160a060020a0380821660008181526004602090815260408083208a8452909152902054929450911691503314806129025750600160a060020a038216600090815260076020908152604080832033845290915290205460ff165b806129155750600160a060020a03811633145b151561292057600080fd5b600160a060020a0381161561298b57600160a060020a03821660008181526004602090815260408083208884529091528082208054600160a060020a0319169055518692907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925908390a45b6000848152600160208190526040822001556129a8878786612efa565b6040805185815290518791600160a060020a038a16917f3c619d5b30fb8431c0c0094f4485f1859d63f222f36cc2104cc13e56c2b993d39181900360200190a350505050505050565b6000828152601360205260408120600201829055811115612a6e57610100820660020a6014612a288461010063ffffffff612fdb16565b81548110612a3257fe5b600091825260209091200154176014612a538461010063ffffffff612fdb16565b81548110612a5d57fe5b600091825260209091200155611b06565b610100820660020a196014612a8b8461010063ffffffff612fdb16565b81548110612a9557fe5b600091825260209091200154166014612ab68461010063ffffffff612fdb16565b81548110612ac057fe5b6000918252602090912001555050565b60006114fc6064612ae884600363ffffffff612ffe16565b9063ffffffff612fdb16565b60008083831115612b0457600080fd5b5050808203805b5092915050565b6000612b2583600163ffffffff61303316565b6000838152600160208181526040808420830194909455600160a060020a03881683526005815283832087845281528383208054928301815583528083208201869055858352600690529190208190559050612b828585846124d0565b6000600160a060020a031684600160a060020a0316636352211e856040518263ffffffff1660e060020a02815260040180828152602001915050602060405180830381600087803b158015612bd657600080fd5b505af1158015612bea573d6000803e3d6000fd5b505050506040513d6020811015612c0057600080fd5b5051600160a060020a03161415612c1657600080fd5b6040805183815290518491600160a060020a038716917fda19c10bf4b88776cd85f9091592a44edff2d94035ec670ebd9e8356f56f887d9181900360200190a35050505050565b60408051606480825260a0820190925260609190829060009081908390819083908760208201610c8080388339019050509550600094505b8815612cf8578551600a808b049a6001880197919006955060f860020a6030870102918891908110612cc357fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350612c95565b899250848351016040519080825280601f01601f191660200182016040528015612d2c578160200160208202803883390190505b509150600090505b8251811015612da4578281815181101515612d4b57fe5b90602001015160f860020a900460f860020a028282815181101515612d6c57fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600101612d34565b5060005b84811015612e1f5785816001870303815181101515612dc357fe5b90602001015160f860020a900460f860020a028284518301815181101515612de757fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600101612da8565b5098975050505050505050565b600160a060020a0382161515612e4157600080fd5b600081815260016020526040902054600160a060020a031615612e6357600080fd5b60008181526001602081815260408084208054600160a060020a031916600160a060020a0388169081179091558085526002808452828620805488885260038652848820819055918552818601815586529285209092018590558354909201835590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000903b1190565b600160a060020a03831660009081526005602090815260408083208584529091528120805460001981019291829184908110612f3257fe5b906000526020600020015491508184141515612fa75750600083815260066020908152604080832054600160a060020a038916845260058352818420888552909252909120805483919083908110612f8657fe5b60009182526020808320909101929092558381526006909152604090208190555b600160a060020a03861660009081526005602090815260408083208884529091529020805490611b9b9060001983016130e1565b600080808311612fea57600080fd5b8284811515612ff557fe5b04949350505050565b6000808315156130115760009150612b0b565b5082820282848281151561302157fe5b041461302c57600080fd5b9392505050565b60008282018381101561302c57600080fd5b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106130865782800160ff198235161785556130b3565b828001600101855582156130b3579182015b828111156130b3578235825591602001919060010190613098565b50611415929150613101565b6060604051908101604052806000815260200160008152602001600081525090565b815481835581811115610f0c57600083815260209020610f0c9181019083015b610c8b91905b8082111561141557600081556001016131075600a165627a7a723058203bac0f675bcdf51c3197b6eda1a5774c29cb9df158ccff4398ebc9bf256d99900029

Swarm Source

bzzr://3bac0f675bcdf51c3197b6eda1a5774c29cb9df158ccff4398ebc9bf256d9990
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.