Contract 0x1d57b453df7483c4b16c0ea67a12c8d2f4133d7f

Contract Overview

Balance:
0 Ether
TxHash Block Age From To Value [TxFee]
0xaaff9b52187a61a93a51bdcea6cbf890a3b6238774643c97f1295b376fa30a2040343696 days 18 hrs ago0xf9196f9f176fd2ef9243e8960817d5fbe63d79aa IN  0x1d57b453df7483c4b16c0ea67a12c8d2f4133d7f0 Ether0.000101244
0x690c5bca7a28da814afeae667b02e97657af30f0f1d21508d6e77541529bf73c40343686 days 18 hrs ago0xf9196f9f176fd2ef9243e8960817d5fbe63d79aa IN  0x1d57b453df7483c4b16c0ea67a12c8d2f4133d7f0 Ether0.000101244
0x3f364bbfab6c0cbeb0ccf05f30fae3fc5dc58118138f192a77854f4e27b8777140343676 days 18 hrs ago0xf9196f9f176fd2ef9243e8960817d5fbe63d79aa IN  0x1d57b453df7483c4b16c0ea67a12c8d2f4133d7f0 Ether0.000101244
0x16fe5b48f7d442aacd8b41543b96b9ae0a6f061d3e1b4bb54e8d2a4753adaec940343666 days 18 hrs ago0xf9196f9f176fd2ef9243e8960817d5fbe63d79aa IN  0x1d57b453df7483c4b16c0ea67a12c8d2f4133d7f0 Ether0.000131244
0x9d272387fcedac0830fadadc23bb73eb085e09043bdefb4ac04b70085ee4c37140343636 days 18 hrs ago0xf9196f9f176fd2ef9243e8960817d5fbe63d79aa IN  0x1d57b453df7483c4b16c0ea67a12c8d2f4133d7f0 Ether0.000061296
0x753994afe8378c70d1f0e771b685f4914fa0f332b06bf3027e24978945e8025340343586 days 18 hrs ago0xf9196f9f176fd2ef9243e8960817d5fbe63d79aa IN  Contract Creation0 Ether0.003759644
[ Download CSV Export 

Internal Transactions as a result of Contract Execution

Parent TxHash Block Age From To Value
Warning: The compiled contract might be susceptible to DoubleShiftSizeOverflow (low-severity) Solidity Compiler Bugs.

Contract Source Code Verified (Exact Match)

Contract Name:
OrderGateway

Compiler Version
v0.5.5+commit.47a71e8f

Optimization Enabled:
Yes

Runs (Optimizer):
200

Contract Source Code

pragma solidity 0.5.5;

/**
 * @dev Standard interface for a dex proxy contract.
 */
interface Proxy {

  /**
   * @dev Executes an action.
   * @param _target Target of execution.
   * @param _a Address usually representing from.
   * @param _b Address usually representing to.
   * @param _c Integer usually repersenting amount/value/id.
   */
  function execute(
    address _target,
    address _a,
    address _b,
    uint256 _c
  )
    external;
    
}

/**
 * @dev Xcert interface.
 */
interface Xcert // is ERC721 metadata enumerable
{

  /**
   * @dev Creates a new Xcert.
   * @param _to The address that will own the created Xcert.
   * @param _id The Xcert to be created by the msg.sender.
   * @param _imprint Cryptographic asset imprint.
   */
  function create(
    address _to,
    uint256 _id,
    bytes32 _imprint
  )
    external;

  /**
   * @dev Change URI base.
   * @param _uriBase New uriBase.
   */
  function setUriBase(
    string calldata _uriBase
  )
    external;

  /**
   * @dev Returns a bytes4 of keccak256 of json schema representing 0xcert Protocol convention.
   * @return Schema id.
   */
  function schemaId()
    external
    view
    returns (bytes32 _schemaId);

  /**
   * @dev Returns imprint for Xcert.
   * @param _tokenId Id of the Xcert.
   * @return Token imprint.
   */
  function tokenImprint(
    uint256 _tokenId
  )
    external
    view
    returns(bytes32 imprint);

}

/**
 * @dev Xcert burnable interface.
 */
interface XcertBurnable // is Xcert
{

  /**
   * @dev Destroys a specified Xcert. Reverts if not called from Xcert owner or operator.
   * @param _tokenId Id of the Xcert we want to destroy.
   */
  function destroy(
    uint256 _tokenId
  )
    external;

}

/**
 * @dev Xcert nutable interface.
 */
interface XcertMutable // is Xcert
{
  
  /**
   * @dev Updates Xcert imprint.
   * @param _tokenId Id of the Xcert.
   * @param _imprint New imprint.
   */
  function updateTokenImprint(
    uint256 _tokenId,
    bytes32 _imprint
  )
    external;

}

/**
 * @dev Xcert pausable interface.
 */
interface XcertPausable // is Xcert
{

  /**
   * @dev Sets if Xcerts transfers are paused (can be performed) or not.
   * @param _isPaused Pause status.
   */
  function setPause(
    bool _isPaused
  )
    external;
    
}

/**
 * @dev Xcert revokable interface.
 */
interface XcertRevokable // is Xcert
{
  
  /**
   * @dev Revokes a specified Xcert. Reverts if not called from contract owner or authorized 
   * address.
   * @param _tokenId Id of the Xcert we want to destroy.
   */
  function revoke(
    uint256 _tokenId
  )
    external;

}

/**
 * @dev Math operations with safety checks that throw on error. This contract is based on the 
 * source code at: 
 * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol.
 */
library SafeMath
{

  /**
   * @dev Error constants.
   */
  string constant OVERFLOW = "008001";
  string constant SUBTRAHEND_GREATER_THEN_MINUEND = "008002";
  string constant DIVISION_BY_ZERO = "008003";

  /**
   * @dev Multiplies two numbers, reverts on overflow.
   * @param _factor1 Factor number.
   * @param _factor2 Factor number.
   * @return The product of the two factors.
   */
  function mul(
    uint256 _factor1,
    uint256 _factor2
  )
    internal
    pure
    returns (uint256 product)
  {
    // 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 (_factor1 == 0)
    {
      return 0;
    }

    product = _factor1 * _factor2;
    require(product / _factor1 == _factor2, OVERFLOW);
  }

  /**
   * @dev Integer division of two numbers, truncating the quotient, reverts on division by zero.
   * @param _dividend Dividend number.
   * @param _divisor Divisor number.
   * @return The quotient.
   */
  function div(
    uint256 _dividend,
    uint256 _divisor
  )
    internal
    pure
    returns (uint256 quotient)
  {
    // Solidity automatically asserts when dividing by 0, using all gas.
    require(_divisor > 0, DIVISION_BY_ZERO);
    quotient = _dividend / _divisor;
    // assert(_dividend == _divisor * quotient + _dividend % _divisor); // There is no case in which this doesn't hold.
  }

  /**
   * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
   * @param _minuend Minuend number.
   * @param _subtrahend Subtrahend number.
   * @return Difference.
   */
  function sub(
    uint256 _minuend,
    uint256 _subtrahend
  )
    internal
    pure
    returns (uint256 difference)
  {
    require(_subtrahend <= _minuend, SUBTRAHEND_GREATER_THEN_MINUEND);
    difference = _minuend - _subtrahend;
  }

  /**
   * @dev Adds two numbers, reverts on overflow.
   * @param _addend1 Number.
   * @param _addend2 Number.
   * @return Sum.
   */
  function add(
    uint256 _addend1,
    uint256 _addend2
  )
    internal
    pure
    returns (uint256 sum)
  {
    sum = _addend1 + _addend2;
    require(sum >= _addend1, OVERFLOW);
  }

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

}

/**
 * @title Contract for setting abilities.
 * @dev For optimization purposes the abilities are represented as a bitfield. Maximum number of
 * abilities is therefore 256. This is an example(for simplicity is made for max 8 abilities) of how
 * this works. 
 * 00000001 Ability A - number representation 1
 * 00000010 Ability B - number representation 2
 * 00000100 Ability C - number representation 4
 * 00001000 Ability D - number representation 8
 * 00010000 Ability E - number representation 16
 * etc ... 
 * To grant abilities B and C, we would need a bitfield of 00000110 which is represented by number
 * 6, in other words, the sum of abilities B and C. The same concept works for revoking abilities
 * and checking if someone has multiple abilities.
 */
contract Abilitable
{
  using SafeMath for uint;

  /**
   * @dev Error constants.
   */
  string constant NOT_AUTHORIZED = "017001";
  string constant CANNOT_REVOKE_OWN_SUPER_ABILITY = "017002";
  string constant INVALID_INPUT = "017003";

  /**
   * @dev Ability 1 (00000001) is a reserved ability called super ability. It is an
   * ability to grant or revoke abilities of other accounts. Other abilities are determined by the
   * implementing contract.
   */
  uint8 constant SUPER_ABILITY = 1;

  /**
   * @dev Maps address to ability ids.
   */
  mapping(address => uint256) public addressToAbility;

  /**
   * @dev Emits when an address is granted an ability.
   * @param _target Address to which we are granting abilities.
   * @param _abilities Number representing bitfield of abilities we are granting.
   */
  event GrantAbilities(
    address indexed _target,
    uint256 indexed _abilities
  );

  /**
   * @dev Emits when an address gets an ability revoked.
   * @param _target Address of which we are revoking an ability.
   * @param _abilities Number representing bitfield of abilities we are revoking.
   */
  event RevokeAbilities(
    address indexed _target,
    uint256 indexed _abilities
  );

  /**
   * @dev Guarantees that msg.sender has certain abilities.
   */
  modifier hasAbilities(
    uint256 _abilities
  ) 
  {
    require(_abilities > 0, INVALID_INPUT);
    require(
      addressToAbility[msg.sender] & _abilities == _abilities,
      NOT_AUTHORIZED
    );
    _;
  }

  /**
   * @dev Contract constructor.
   * Sets SUPER_ABILITY ability to the sender account.
   */
  constructor()
    public
  {
    addressToAbility[msg.sender] = SUPER_ABILITY;
    emit GrantAbilities(msg.sender, SUPER_ABILITY);
  }

  /**
   * @dev Grants specific abilities to specified address.
   * @param _target Address to grant abilities to.
   * @param _abilities Number representing bitfield of abilities we are granting.
   */
  function grantAbilities(
    address _target,
    uint256 _abilities
  )
    external
    hasAbilities(SUPER_ABILITY)
  {
    addressToAbility[_target] |= _abilities;
    emit GrantAbilities(_target, _abilities);
  }

  /**
   * @dev Unassigns specific abilities from specified address.
   * @param _target Address of which we revoke abilites.
   * @param _abilities Number representing bitfield of abilities we are revoking.
   * @param _allowSuperRevoke Additional check that prevents you from removing your own super
   * ability by mistake.
   */
  function revokeAbilities(
    address _target,
    uint256 _abilities,
    bool _allowSuperRevoke
  )
    external
    hasAbilities(SUPER_ABILITY)
  {
    if (!_allowSuperRevoke && msg.sender == _target)
    {
      require((_abilities & 1) == 0, CANNOT_REVOKE_OWN_SUPER_ABILITY);
    }
    addressToAbility[_target] &= ~_abilities;
    emit RevokeAbilities(_target, _abilities);
  }

  /**
   * @dev Check if an address has a specific ability. Throws if checking for 0.
   * @param _target Address for which we want to check if it has a specific abilities.
   * @param _abilities Number representing bitfield of abilities we are checking.
   */
  function isAble(
    address _target,
    uint256 _abilities
  )
    external
    view
    returns (bool)
  {
    require(_abilities > 0, INVALID_INPUT);
    return (addressToAbility[_target] & _abilities) == _abilities;
  }
  
}

/**
 * @dev ERC-721 non-fungible token standard. 
 * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
 */
interface ERC721
{

  /**
   * @dev Emits when ownership of any NFT changes by any mechanism. This event emits when NFTs are
   * created (`from` == 0) and destroyed (`to` == 0). Exception: during contract creation, any
   * number of NFTs may be created and assigned without emitting Transfer. At the time of any
   * transfer, the approved address for that NFT (if any) is reset to none.
   */
  event Transfer(
    address indexed _from,
    address indexed _to,
    uint256 indexed _tokenId
  );

  /**
   * @dev This emits when the approved address for an NFT is changed or reaffirmed. The zero
   * address indicates there is no approved address. When a Transfer event emits, this also
   * indicates that the approved address for that NFT (if any) is reset to none.
   */
  event Approval(
    address indexed _owner,
    address indexed _approved,
    uint256 indexed _tokenId
  );

  /**
   * @dev This emits when an operator is enabled or disabled for an owner. The operator can manage
   * all NFTs of the owner.
   */
  event ApprovalForAll(
    address indexed _owner,
    address indexed _operator,
    bool _approved
  );

  /**
   * @dev Transfers the ownership of an NFT from one address to another address.
   * @notice Throws unless `msg.sender` is the current owner, an authorized operator, or the
   * approved address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is
   * the zero address. Throws if `_tokenId` is not a valid NFT. When transfer is complete, this
   * function checks if `_to` is a smart contract (code size > 0). If so, it calls
   * `onERC721Received` on `_to` and throws if the return value is not 
   * `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   * @param _data Additional data with no specified format, sent in call to `_to`.
   */
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId,
    bytes calldata _data
  )
    external;

  /**
   * @dev Transfers the ownership of an NFT from one address to another address.
   * @notice This works identically to the other function with an extra data parameter, except this
   * function just sets data to ""
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   */
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    external;

  /**
   * @dev Throws unless `msg.sender` is the current owner, an authorized operator, or the approved
   * address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is the zero
   * address. Throws if `_tokenId` is not a valid NFT.
   * @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else
   * they mayb be permanently lost.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   */
  function transferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    external;

  /**
   * @dev Set or reaffirm the approved address for an NFT.
   * @notice The zero address indicates there is no approved address. Throws unless `msg.sender` is
   * the current NFT owner, or an authorized operator of the current owner.
   * @param _approved The new approved NFT controller.
   * @param _tokenId The NFT to approve.
   */
  function approve(
    address _approved,
    uint256 _tokenId
  )
    external;

  /**
   * @dev Enables or disables approval for a third party ("operator") to manage all of
   * `msg.sender`'s assets. It also emits the ApprovalForAll event.
   * @notice The contract MUST allow multiple operators per owner.
   * @param _operator Address to add to the set of authorized operators.
   * @param _approved True if the operators is approved, false to revoke approval.
   */
  function setApprovalForAll(
    address _operator,
    bool _approved
  )
    external;

  /**
   * @dev Returns the number of NFTs owned by `_owner`. NFTs assigned to the zero address are
   * considered invalid, and this function throws for queries about the zero address.
   * @param _owner Address for whom to query the balance.
   * @return Balance of _owner.
   */
  function balanceOf(
    address _owner
  )
    external
    view
    returns (uint256);

  /**
   * @dev Returns the address of the owner of the NFT. NFTs assigned to zero address are considered
   * invalid, and queries about them do throw.
   * @param _tokenId The identifier for an NFT.
   * @return Address of _tokenId owner.
   */
  function ownerOf(
    uint256 _tokenId
  )
    external
    view
    returns (address);
    
  /**
   * @dev Get the approved address for a single NFT.
   * @notice Throws if `_tokenId` is not a valid NFT.
   * @param _tokenId The NFT to find the approved address for.
   * @return Address that _tokenId is approved for. 
   */
  function getApproved(
    uint256 _tokenId
  )
    external
    view
    returns (address);

  /**
   * @dev Returns true if `_operator` is an approved operator for `_owner`, false otherwise.
   * @param _owner The address that owns the NFTs.
   * @param _operator The address that acts on behalf of the owner.
   * @return True if approved for all, false otherwise.
   */
  function isApprovedForAll(
    address _owner,
    address _operator
  )
    external
    view
    returns (bool);

}

/**
 * @dev Optional metadata extension for ERC-721 non-fungible token standard.
 * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
 */
interface ERC721Metadata
{

  /**
   * @dev Returns a descriptive name for a collection of NFTs in this contract.
   * @return Representing name. 
   */
  function name()
    external
    view
    returns (string memory _name);

  /**
   * @dev Returns a abbreviated name for a collection of NFTs in this contract.
   * @return Representing symbol. 
   */
  function symbol()
    external
    view
    returns (string memory _symbol);

  /**
   * @dev Returns a distinct Uniform Resource Identifier (URI) for a given asset. It Throws if
   * `_tokenId` is not a valid NFT. URIs are defined in RFC3986. The URI may point to a JSON file
   * that conforms to the "ERC721 Metadata JSON Schema".
   * @return URI of _tokenId.
   */
  function tokenURI(uint256 _tokenId)
    external
    view
    returns (string memory);

}

/**
 * @dev Optional enumeration extension for ERC-721 non-fungible token standard.
 * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
 */
interface ERC721Enumerable
{

  /**
   * @dev Returns a count of valid NFTs tracked by this contract, where each one of them has an
   * assigned and queryable owner not equal to the zero address.
   * @return Total supply of NFTs.
   */
  function totalSupply()
    external
    view
    returns (uint256);

  /**
   * @dev Returns the token identifier for the `_index`th NFT. Sort order is not specified.
   * @param _index A counter less than `totalSupply()`.
   * @return Token id.
   */
  function tokenByIndex(
    uint256 _index
  )
    external
    view
    returns (uint256);

  /**
   * @dev Returns the token identifier for the `_index`th NFT assigned to `_owner`. Sort order is
   * not specified. It throws if `_index` >= `balanceOf(_owner)` or if `_owner` is the zero address,
   * representing invalid NFTs.
   * @param _owner An address where we are interested in NFTs owned by them.
   * @param _index A counter less than `balanceOf(_owner)`.
   * @return Token id.
   */
  function tokenOfOwnerByIndex(
    address _owner,
    uint256 _index
  )
    external
    view
    returns (uint256);

}

/**
 * @dev ERC-721 interface for accepting safe transfers. 
 * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
 */
interface ERC721TokenReceiver
{

  /**
   * @dev Handle the receipt of a NFT. 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.
   * Returns `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` unless throwing.
   * @notice The contract address is always the message sender. A wallet/broker/auction application
   * MUST implement the wallet interface if it will accept safe transfers.
   * @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 Returns `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
   */
  function onERC721Received(
    address _operator,
    address _from,
    uint256 _tokenId,
    bytes calldata _data
  )
    external
    returns(bytes4);
    
}

/**
 * @dev A standard for detecting smart contract interfaces.
 * See: https://eips.ethereum.org/EIPS/eip-165.
 */
interface ERC165
{

  /**
   * @dev Checks if the smart contract implements a specific interface.
   * @notice This function uses less than 30,000 gas.
   * @param _interfaceID The interface identifier, as specified in ERC-165.
   */
  function supportsInterface(
    bytes4 _interfaceID
  )
    external
    view
    returns (bool);

}

/**
 * @dev Implementation of standard to publish supported interfaces.
 */
contract SupportsInterface is
  ERC165
{

  /**
   * @dev Mapping of supported intefraces.
   * @notice You must not set element 0xffffffff to true.
   */
  mapping(bytes4 => bool) internal supportedInterfaces;

  /**
   * @dev Contract constructor.
   */
  constructor()
    public
  {
    supportedInterfaces[0x01ffc9a7] = true; // ERC165
  }

  /**
   * @dev Function to check which interfaces are suported by this contract.
   * @param _interfaceID Id of the interface.
   */
  function supportsInterface(
    bytes4 _interfaceID
  )
    external
    view
    returns (bool)
  {
    return supportedInterfaces[_interfaceID];
  }

}

/**
 * @dev Utility library of inline functions on addresses.
 */
library AddressUtils
{

  /**
   * @dev Returns whether the target address is a contract.
   * @param _addr Address to check.
   * @return True if _addr is a contract, false if not.
   */
  function isContract(
    address _addr
  )
    internal
    view
    returns (bool addressCheck)
  {
    uint256 size;

    /**
     * XXX Currently there is no better way to check if there is a contract in an address than to
     * check the size of the code at that address.
     * See https://ethereum.stackexchange.com/a/14016/36603 for more details about how this works.
     * TODO: Check this again before the Serenity release, because all addresses will be
     * contracts then.
     */
    assembly { size := extcodesize(_addr) } // solhint-disable-line
    addressCheck = size > 0;
  }

}

/**
 * @dev Optional metadata enumerable implementation for ERC-721 non-fungible token standard.
 */
contract NFTokenMetadataEnumerable is
  ERC721,
  ERC721Metadata,
  ERC721Enumerable,
  SupportsInterface
{
  using SafeMath for uint256;
  using AddressUtils for address;

  /**
   * @dev Error constants.
   */
  string constant ZERO_ADDRESS = "006001";
  string constant NOT_VALID_NFT = "006002";
  string constant NOT_OWNER_OR_OPERATOR = "006003";
  string constant NOT_OWNER_APPROWED_OR_OPERATOR = "006004";
  string constant NOT_ABLE_TO_RECEIVE_NFT = "006005";
  string constant NFT_ALREADY_EXISTS = "006006";
  string constant INVALID_INDEX = "006007";

  /**
   * @dev Magic value of a smart contract that can recieve NFT.
   * Equal to: bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")).
   */
  bytes4 constant MAGIC_ON_ERC721_RECEIVED = 0x150b7a02;

  /**
   * @dev A descriptive name for a collection of NFTs.
   */
  string internal nftName;

  /**
   * @dev An abbreviated name for NFTs.
   */
  string internal nftSymbol;

  /**
   * @dev URI base for NFT metadata. NFT URI is made from base + NFT id.
   */
  string public uriBase;

  /**
   * @dev Array of all NFT IDs.
   */
  uint256[] internal tokens;

  /**
   * @dev Mapping from token ID its index in global tokens array.
   */
  mapping(uint256 => uint256) internal idToIndex;

  /**
   * @dev Mapping from owner to list of owned NFT IDs.
   */
  mapping(address => uint256[]) internal ownerToIds;

  /**
   * @dev Mapping from NFT ID to its index in the owner tokens list.
   */
  mapping(uint256 => uint256) internal idToOwnerIndex;

  /**
   * @dev A mapping from NFT ID to the address that owns it.
   */
  mapping (uint256 => address) internal idToOwner;

  /**
   * @dev Mapping from NFT ID to approved address.
   */
  mapping (uint256 => address) internal idToApproval;

  /**
   * @dev Mapping from owner address to mapping of operator addresses.
   */
  mapping (address => mapping (address => bool)) internal ownerToOperators;

  /**
   * @dev Emits when ownership of any NFT changes by any mechanism. This event emits when NFTs are
   * created (`from` == 0) and destroyed (`to` == 0). Exception: during contract creation, any
   * number of NFTs may be created and assigned without emitting Transfer. At the time of any
   * transfer, the approved address for that NFT (if any) is reset to none.
   * @param _from Sender of NFT (if address is zero address it indicates token creation).
   * @param _to Receiver of NFT (if address is zero address it indicates token destruction).
   * @param _tokenId The NFT that got transfered.
   */
  event Transfer(
    address indexed _from,
    address indexed _to,
    uint256 indexed _tokenId
  );

  /**
   * @dev This emits when the approved address for an NFT is changed or reaffirmed. The zero
   * address indicates there is no approved address. When a Transfer event emits, this also
   * indicates that the approved address for that NFT (if any) is reset to none.
   * @param _owner Owner of NFT.
   * @param _approved Address that we are approving.
   * @param _tokenId NFT which we are approving.
   */
  event Approval(
    address indexed _owner,
    address indexed _approved,
    uint256 indexed _tokenId
  );

  /**
   * @dev This emits when an operator is enabled or disabled for an owner. The operator can manage
   * all NFTs of the owner.
   * @param _owner Owner of NFT.
   * @param _operator Address to which we are setting operator rights.
   * @param _approved Status of operator rights(true if operator rights are given and false if
   * revoked).
   */
  event ApprovalForAll(
    address indexed _owner,
    address indexed _operator,
    bool _approved
  );

  /**
   * @dev Contract constructor.
   * @notice When implementing this contract don't forget to set nftName, nftSymbol and uriBase.
   */
  constructor()
    public
  {
    supportedInterfaces[0x80ac58cd] = true; // ERC721
    supportedInterfaces[0x5b5e139f] = true; // ERC721Metadata
    supportedInterfaces[0x780e9d63] = true; // ERC721Enumerable
  }

  /**
   * @dev Transfers the ownership of an NFT from one address to another address.
   * @notice Throws unless `msg.sender` is the current owner, an authorized operator, or the
   * approved address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is
   * the zero address. Throws if `_tokenId` is not a valid NFT. When transfer is complete, this
   * function checks if `_to` is a smart contract (code size > 0). If so, it calls 
   * `onERC721Received` on `_to` and throws if the return value is not 
   * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   * @param _data Additional data with no specified format, sent in call to `_to`.
   */
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId,
    bytes calldata _data
  )
    external
  {
    _safeTransferFrom(_from, _to, _tokenId, _data);
  }

  /**
   * @dev Transfers the ownership of an NFT from one address to another address.
   * @notice This works identically to the other function with an extra data parameter, except this
   * function just sets data to "".
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   */
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    external
  {
    _safeTransferFrom(_from, _to, _tokenId, "");
  }

  /**
   * @dev Throws unless `msg.sender` is the current owner, an authorized operator, or the approved
   * address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is the zero
   * address. Throws if `_tokenId` is not a valid NFT.
   * @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else
   * they maybe be permanently lost.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   */
  function transferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    external
  {
    _transferFrom(_from, _to, _tokenId);
  }

  /**
   * @dev Set or reaffirm the approved address for an NFT.
   * @notice The zero address indicates there is no approved address. Throws unless `msg.sender` is
   * the current NFT owner, or an authorized operator of the current owner.
   * @param _approved Address to be approved for the given NFT ID.
   * @param _tokenId ID of the token to be approved.
   */
  function approve(
    address _approved,
    uint256 _tokenId
  )
    external
  {
    // can operate
    address tokenOwner = idToOwner[_tokenId];
    require(
      tokenOwner == msg.sender || ownerToOperators[tokenOwner][msg.sender],
      NOT_OWNER_OR_OPERATOR
    );

    idToApproval[_tokenId] = _approved;
    emit Approval(tokenOwner, _approved, _tokenId);
  }

  /**
   * @dev Enables or disables approval for a third party ("operator") to manage all of
   * `msg.sender`'s assets. It also emits the ApprovalForAll event.
   * @notice This works even if sender doesn't own any tokens at the time.
   * @param _operator Address to add to the set of authorized operators.
   * @param _approved True if the operators is approved, false to revoke approval.
   */
  function setApprovalForAll(
    address _operator,
    bool _approved
  )
    external
  {
    ownerToOperators[msg.sender][_operator] = _approved;
    emit ApprovalForAll(msg.sender, _operator, _approved);
  }

  /**
   * @dev Returns the number of NFTs owned by `_owner`. NFTs assigned to the zero address are
   * considered invalid, and this function throws for queries about the zero address.
   * @param _owner Address for whom to query the balance.
   * @return Balance of _owner.
   */
  function balanceOf(
    address _owner
  )
    external
    view
    returns (uint256)
  {
    require(_owner != address(0), ZERO_ADDRESS);
    return ownerToIds[_owner].length;
  }

  /**
   * @dev Returns the address of the owner of the NFT. NFTs assigned to zero address are considered
   * invalid, and queries about them do throw.
   * @param _tokenId The identifier for an NFT.
   * @return Address of _tokenId owner.
   */
  function ownerOf(
    uint256 _tokenId
  )
    external
    view
    returns (address _owner)
  {
    _owner = idToOwner[_tokenId];
    require(_owner != address(0), NOT_VALID_NFT);
  }

  /**
   * @dev Get the approved address for a single NFT.
   * @notice Throws if `_tokenId` is not a valid NFT.
   * @param _tokenId ID of the NFT to query the approval of.
   * @return Address that _tokenId is approved for. 
   */
  function getApproved(
    uint256 _tokenId
  )
    external
    view
    returns (address)
  {
    require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT);
    return idToApproval[_tokenId];
  }

  /**
   * @dev Checks if `_operator` is an approved operator for `_owner`.
   * @param _owner The address that owns the NFTs.
   * @param _operator The address that acts on behalf of the owner.
   * @return True if approved for all, false otherwise.
   */
  function isApprovedForAll(
    address _owner,
    address _operator
  )
    external
    view
    returns (bool)
  {
    return ownerToOperators[_owner][_operator];
  }

  /**
   * @dev Returns the count of all existing NFTs.
   * @return Total supply of NFTs.
   */
  function totalSupply()
    external
    view
    returns (uint256)
  {
    return tokens.length;
  }

  /**
   * @dev Returns NFT ID by its index.
   * @param _index A counter less than `totalSupply()`.
   * @return Token id.
   */
  function tokenByIndex(
    uint256 _index
  )
    external
    view
    returns (uint256)
  {
    require(_index < tokens.length, INVALID_INDEX);
    return tokens[_index];
  }

  /**
   * @dev returns the n-th NFT ID from a list of owner's tokens.
   * @param _owner Token owner's address.
   * @param _index Index number representing n-th token in owner's list of tokens.
   * @return Token id.
   */
  function tokenOfOwnerByIndex(
    address _owner,
    uint256 _index
  )
    external
    view
    returns (uint256)
  {
    require(_index < ownerToIds[_owner].length, INVALID_INDEX);
    return ownerToIds[_owner][_index];
  }

  /**
   * @dev Returns a descriptive name for a collection of NFTs.
   * @return Representing name. 
   */
  function name()
    external
    view
    returns (string memory _name)
  {
    _name = nftName;
  }

  /**
   * @dev Returns an abbreviated name for NFTs.
   * @return Representing symbol. 
   */
  function symbol()
    external
    view
    returns (string memory _symbol)
  {
    _symbol = nftSymbol;
  }
  
  /**
   * @notice A distinct Uniform Resource Identifier (URI) for a given asset.
   * @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC 3986. The URI may point
   * to a JSON file that conforms to the "ERC721 Metadata JSON Schema".
   * @param _tokenId Id for which we want URI.
   * @return URI of _tokenId.
   */
  function tokenURI(
    uint256 _tokenId
  )
    external
    view
    returns (string memory)
  {
    require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT);
    if (bytes(uriBase).length > 0)
    {
      return string(abi.encodePacked(uriBase, _uint2str(_tokenId)));
    }
    return "";
  }

  /**
   * @dev Set a distinct URI (RFC 3986) base for all nfts.
   * @notice this is a internal function which should be called from user-implemented external
   * function. Its purpose is to show and properly initialize data structures when using this
   * implementation.
   * @param _uriBase String representing RFC 3986 URI base.
   */
  function _setUriBase(
    string memory _uriBase
  )
    internal
  {
    uriBase = _uriBase;
  }

  /**
   * @dev Creates a new NFT.
   * @notice This is a private function which should be called from user-implemented external
   * function. Its purpose is to show and properly initialize data structures when using this
   * implementation.
   * @param _to The address that will own the created NFT.
   * @param _tokenId of the NFT to be created by the msg.sender.
   */
  function _create(
    address _to,
    uint256 _tokenId
  )
    internal
  {
    require(_to != address(0), ZERO_ADDRESS);
    require(idToOwner[_tokenId] == address(0), NFT_ALREADY_EXISTS);

    // add NFT
    idToOwner[_tokenId] = _to;

    uint256 length = ownerToIds[_to].push(_tokenId);
    idToOwnerIndex[_tokenId] = length - 1;

    // add to tokens array
    length = tokens.push(_tokenId);
    idToIndex[_tokenId] = length - 1;

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

  /**
   * @dev Destroys a NFT.
   * @notice This is a private function which should be called from user-implemented external
   * destroy function. Its purpose is to show and properly initialize data structures when using this
   * implementation.
   * @param _tokenId ID of the NFT to be destroyed.
   */
  function _destroy(
    uint256 _tokenId
  )
    internal
  {
    // valid NFT
    address owner = idToOwner[_tokenId];
    require(owner != address(0), NOT_VALID_NFT);

    // clear approval
    if (idToApproval[_tokenId] != address(0))
    {
      delete idToApproval[_tokenId];
    }

    // remove NFT
    assert(ownerToIds[owner].length > 0);

    uint256 tokenToRemoveIndex = idToOwnerIndex[_tokenId];
    uint256 lastTokenIndex = ownerToIds[owner].length - 1;
    uint256 lastToken;
    if (lastTokenIndex != tokenToRemoveIndex)
    {
      lastToken = ownerToIds[owner][lastTokenIndex];
      ownerToIds[owner][tokenToRemoveIndex] = lastToken;
      idToOwnerIndex[lastToken] = tokenToRemoveIndex;
    }

    delete idToOwner[_tokenId];
    delete idToOwnerIndex[_tokenId];
    ownerToIds[owner].length--;

    // remove from tokens array
    assert(tokens.length > 0);

    uint256 tokenIndex = idToIndex[_tokenId];
    lastTokenIndex = tokens.length - 1;
    lastToken = tokens[lastTokenIndex];

    tokens[tokenIndex] = lastToken;

    tokens.length--;
    // Consider adding a conditional check for the last token in order to save GAS.
    idToIndex[lastToken] = tokenIndex;
    idToIndex[_tokenId] = 0;

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

  /**
   * @dev Helper methods that actually does the transfer.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   */
  function _transferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    internal
  {
    // valid NFT
    require(_from != address(0), ZERO_ADDRESS);
    require(idToOwner[_tokenId] == _from, NOT_VALID_NFT);
    require(_to != address(0), ZERO_ADDRESS);

    // can transfer
    require(
      _from == msg.sender
      || idToApproval[_tokenId] == msg.sender
      || ownerToOperators[_from][msg.sender],
      NOT_OWNER_APPROWED_OR_OPERATOR
    );

    // clear approval
    if (idToApproval[_tokenId] != address(0))
    {
      delete idToApproval[_tokenId];
    }

    // remove NFT
    assert(ownerToIds[_from].length > 0);

    uint256 tokenToRemoveIndex = idToOwnerIndex[_tokenId];
    uint256 lastTokenIndex = ownerToIds[_from].length - 1;

    if (lastTokenIndex != tokenToRemoveIndex)
    {
      uint256 lastToken = ownerToIds[_from][lastTokenIndex];
      ownerToIds[_from][tokenToRemoveIndex] = lastToken;
      idToOwnerIndex[lastToken] = tokenToRemoveIndex;
    }

    ownerToIds[_from].length--;

    // add NFT
    idToOwner[_tokenId] = _to;
    uint256 length = ownerToIds[_to].push(_tokenId);
    idToOwnerIndex[_tokenId] = length - 1;

    emit Transfer(_from, _to, _tokenId);
  }

  /**
   * @dev Helper function that actually does the safeTransfer.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   * @param _data Additional data with no specified format, sent in call to `_to`.
   */
  function _safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId,
    bytes memory _data
  )
    internal
  {
    if (_to.isContract())
    {
      require(
        ERC721TokenReceiver(_to)
          .onERC721Received(msg.sender, _from, _tokenId, _data) == MAGIC_ON_ERC721_RECEIVED,
        NOT_ABLE_TO_RECEIVE_NFT
      );
    }

    _transferFrom(_from, _to, _tokenId);
  }

  /**
   * @dev Helper function that changes uint to string representation.
   * @return String representation.
   */
  function _uint2str(
    uint256 _i
  ) 
    internal
    pure
    returns (string memory str)
  {
    if (_i == 0)
    {
      return "0";
    }
    uint256 j = _i;
    uint256 length;
    while (j != 0)
    {
      length++;
      j /= 10;
    }
    bytes memory bstr = new bytes(length);
    uint256 k = length - 1;
    j = _i;
    while (j != 0)
    {
      bstr[k--] = byte(uint8(48 + j % 10));
      j /= 10;
    }
    str = string(bstr);
  }
  
}

/**
 * @dev Xcert implementation.
 */
contract XcertToken is 
  Xcert,
  XcertBurnable,
  XcertMutable,
  XcertPausable,
  XcertRevokable,
  NFTokenMetadataEnumerable,
  Abilitable
{

  /**
   * @dev List of abilities (gathered from all extensions):
   */
  uint8 constant ABILITY_CREATE_ASSET = 2;
  uint8 constant ABILITY_REVOKE_ASSET = 4;
  uint8 constant ABILITY_TOGGLE_TRANSFERS = 8;
  uint8 constant ABILITY_UPDATE_ASSET_IMPRINT = 16;
  /// ABILITY_ALLOW_CREATE_ASSET = 32 - A specific ability that is bounded to atomic orders.
  /// When creating a new Xcert trough `OrderGateway`, the order maker has to have this ability.
  uint8 constant ABILITY_UPDATE_URI_BASE = 64;

  /**
   * @dev List of capabilities (supportInterface bytes4 representations).
   */
  bytes4 constant MUTABLE = 0xbda0e852;
  bytes4 constant BURNABLE = 0x9d118770;
  bytes4 constant PAUSABLE = 0xbedb86fb;
  bytes4 constant REVOKABLE = 0x20c5429b;

  /**
   * @dev Error constants.
   */
  string constant CAPABILITY_NOT_SUPPORTED = "007001";
  string constant TRANSFERS_DISABLED = "007002";
  string constant NOT_VALID_XCERT = "007003";
  string constant NOT_OWNER_OR_OPERATOR = "007004";

  /**
   * @dev This emits when ability of beeing able to transfer Xcerts changes (paused/unpaused).
   */
  event IsPaused(bool isPaused);

  /**
   * @dev Emits when imprint of a token is changed.
   * @param _tokenId Id of the Xcert.
   * @param _imprint Cryptographic asset imprint.
   */
  event TokenImprintUpdate(
    uint256 indexed _tokenId,
    bytes32 _imprint
  );

  /**
   * @dev Unique ID which determines each Xcert smart contract type by its JSON convention.
   * @notice Calculated as keccak256(jsonSchema).
   */
  bytes32 internal nftSchemaId;

  /**
   * @dev Maps NFT ID to imprint.
   */
  mapping (uint256 => bytes32) internal idToImprint;

  /**
   * @dev Maps address to authorization of contract.
   */
  mapping (address => bool) internal addressToAuthorized;

  /**
   * @dev Are Xcerts transfers paused (can be performed) or not.
   */
  bool public isPaused;

  /**
   * @dev Contract constructor.
   * @notice When implementing this contract don't forget to set nftSchemaId, nftName, nftSymbol
   * and uriBase.
   */
  constructor()
    public
  {
    supportedInterfaces[0xe08725ee] = true; // Xcert
  }

  /**
   * @dev Creates a new Xcert.
   * @param _to The address that will own the created Xcert.
   * @param _id The Xcert to be created by the msg.sender.
   * @param _imprint Cryptographic asset imprint.
   */
  function create(
    address _to,
    uint256 _id,
    bytes32 _imprint
  )
    external
    hasAbilities(ABILITY_CREATE_ASSET)
  {
    super._create(_to, _id);
    idToImprint[_id] = _imprint;
  }

  /**
   * @dev Change URI base.
   * @param _uriBase New uriBase.
   */
  function setUriBase(
    string calldata _uriBase
  )
    external
    hasAbilities(ABILITY_UPDATE_URI_BASE)
  {
    super._setUriBase(_uriBase);
  }

  /**
   * @dev Revokes(destroys) a specified Xcert. Reverts if not called from contract owner or 
   * authorized address.
   * @param _tokenId Id of the Xcert we want to destroy.
   */
  function revoke(
    uint256 _tokenId
  )
    external
    hasAbilities(ABILITY_REVOKE_ASSET)
  {
    require(supportedInterfaces[REVOKABLE], CAPABILITY_NOT_SUPPORTED);
    super._destroy(_tokenId);
    delete idToImprint[_tokenId];
  }

  /**
   * @dev Sets if Xcerts transfers are paused (can be performed) or not.
   * @param _isPaused Pause status.
   */
  function setPause(
    bool _isPaused
  )
    external
    hasAbilities(ABILITY_TOGGLE_TRANSFERS)
  {
    require(supportedInterfaces[PAUSABLE], CAPABILITY_NOT_SUPPORTED);
    isPaused = _isPaused;
    emit IsPaused(_isPaused);
  }

  /**
   * @dev Updates Xcert imprint.
   * @param _tokenId Id of the Xcert.
   * @param _imprint New imprint.
   */
  function updateTokenImprint(
    uint256 _tokenId,
    bytes32 _imprint
  )
    external
    hasAbilities(ABILITY_UPDATE_ASSET_IMPRINT)
  {
    require(supportedInterfaces[MUTABLE], CAPABILITY_NOT_SUPPORTED);
    require(idToOwner[_tokenId] != address(0), NOT_VALID_XCERT);
    idToImprint[_tokenId] = _imprint;
    emit TokenImprintUpdate(_tokenId, _imprint);
  }

  /**
   * @dev Destroys a specified Xcert. Reverts if not called from Xcert owner or operator.
   * @param _tokenId Id of the Xcert we want to destroy.
   */
  function destroy(
    uint256 _tokenId
  )
    external
  {
    require(supportedInterfaces[BURNABLE], CAPABILITY_NOT_SUPPORTED);
    address tokenOwner = idToOwner[_tokenId];
    super._destroy(_tokenId);
    require(
      tokenOwner == msg.sender || ownerToOperators[tokenOwner][msg.sender],
      NOT_OWNER_OR_OPERATOR
    );
    delete idToImprint[_tokenId];
  }

  /**
   * @dev Returns a bytes32 of sha256 of json schema representing 0xcert Protocol convention.
   * @return Schema id.
   */
  function schemaId()
    external
    view
    returns (bytes32 _schemaId)
  {
    _schemaId = nftSchemaId;
  }

  /**
   * @dev Returns imprint for Xcert.
   * @param _tokenId Id of the Xcert.
   * @return Token imprint.
   */
  function tokenImprint(
    uint256 _tokenId
  )
    external
    view
    returns(bytes32 imprint)
  {
    imprint = idToImprint[_tokenId];
  }

  /**
   * @dev Helper methods that actually does the transfer.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   */
  function _transferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    internal
  {
    /**
     * if (supportedInterfaces[0xbedb86fb])
     * {
     *   require(!isPaused, TRANSFERS_DISABLED);
     * }
     * There is no need to check for pausable capability here since by using logical deduction we 
     * can say based on code above that:
     * !supportedInterfaces[0xbedb86fb] => !isPaused
     * isPaused => supportedInterfaces[0xbedb86fb]
     * (supportedInterfaces[0xbedb86fb] ∧ isPaused) <=> isPaused. 
     * This saves 200 gas.
     */
    require(!isPaused, TRANSFERS_DISABLED); 
    super._transferFrom(_from, _to, _tokenId);
  }
}

/**
 * @title XcertCreateProxy - creates a token on behalf of contracts that have been approved via
 * decentralized governance.
 */
contract XcertCreateProxy is 
  Abilitable 
{

  /**
   * @dev List of abilities:
   * 2 - Ability to execute create. 
   */
  uint8 constant ABILITY_TO_EXECUTE = 2;

  /**
   * @dev Creates a new NFT.
   * @param _xcert Address of the Xcert contract on which the creation will be perfomed.
   * @param _to The address that will own the created NFT.
   * @param _id The NFT to be created by the msg.sender.
   * @param _imprint Cryptographic asset imprint.
   */
  function create(
    address _xcert,
    address _to,
    uint256 _id,
    bytes32 _imprint
  )
    external
    hasAbilities(ABILITY_TO_EXECUTE)
  {
    Xcert(_xcert).create(_to, _id, _imprint);
  }
  
}

pragma experimental ABIEncoderV2;




/**
 * @dev Decentralize exchange, creating, updating and other actions for fundgible and non-fundgible 
 * tokens powered by atomic swaps. 
 */
contract OrderGateway is
  Abilitable
{

  /**
   * @dev List of abilities:
   * 2 - Ability to set proxies.
   */
  uint8 constant ABILITY_TO_SET_PROXIES = 2;

  /**
   * @dev Xcert abilities.
   */
  uint8 constant ABILITY_ALLOW_CREATE_ASSET = 32;

  /**
   * @dev Error constants.
   */
  string constant INVALID_SIGNATURE_KIND = "015001";
  string constant INVALID_PROXY = "015002";
  string constant TAKER_NOT_EQUAL_TO_SENDER = "015003";
  string constant SENDER_NOT_TAKER_OR_MAKER = "015004";
  string constant CLAIM_EXPIRED = "015005";
  string constant INVALID_SIGNATURE = "015006";
  string constant ORDER_CANCELED = "015007";
  string constant ORDER_ALREADY_PERFORMED = "015008";
  string constant MAKER_NOT_EQUAL_TO_SENDER = "015009";
  string constant SIGNER_NOT_AUTHORIZED = "015010";

  /**
   * @dev Enum of available signature kinds.
   * @param eth_sign Signature using eth sign.
   * @param trezor Signature from Trezor hardware wallet.
   * It differs from web3.eth_sign in the encoding of message length
   * (Bitcoin varint encoding vs ascii-decimal, the latter is not
   * self-terminating which leads to ambiguities).
   * See also:
   * https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer
   * https://github.com/trezor/trezor-mcu/blob/master/firmware/ethereum.c#L602
   * https://github.com/trezor/trezor-mcu/blob/master/firmware/crypto.c#L36 
   * @param eip721 Signature using eip721.
   */
  enum SignatureKind
  {
    eth_sign,
    trezor,
    eip712
  }

  /**
   * Enum of available action kinds.
   */
  enum ActionKind
  {
    create,
    transfer
  }

  /**
   * @dev Structure representing what to send and where.
   * @param kind Enum representing action kind. 
   * @param proxy Id representing approved proxy address.
   * @param token Address of the token we are sending.
   * @param param1 Address of the sender or imprint.
   * @param to Address of the receiver.
   * @param value Amount of ERC20 or ID of ERC721.
   */
  struct ActionData 
  {
    ActionKind kind;
    uint32 proxy;
    address token;
    bytes32 param1;
    address to;
    uint256 value;
  }

  /**
   * @dev Structure representing the signature parts.
   * @param r ECDSA signature parameter r.
   * @param s ECDSA signature parameter s.
   * @param v ECDSA signature parameter v.
   * @param kind Type of signature. 
   */
  struct SignatureData
  {
    bytes32 r;
    bytes32 s;
    uint8 v;
    SignatureKind kind;
  }

  /**
   * @dev Structure representing the data needed to do the order.
   * @param maker Address of the one that made the claim.
   * @param taker Address of the one that is executing the claim.
   * @param actions Data of all the actions that should accure it this order.
   * @param signature Data from the signed claim.
   * @param seed Arbitrary number to facilitate uniqueness of the order's hash. Usually timestamp.
   * @param expiration Timestamp of when the claim expires. 0 if indefinet. 
   */
  struct OrderData 
  {
    address maker;
    address taker;
    ActionData[] actions;
    uint256 seed;
    uint256 expiration;
  }

  /** 
   * @dev Valid proxy contract addresses.
   */
  address[] public proxies;

  /**
   * @dev Mapping of all cancelled orders.
   */
  mapping(bytes32 => bool) public orderCancelled;

  /**
   * @dev Mapping of all performed orders.
   */
  mapping(bytes32 => bool) public orderPerformed;

  /**
   * @dev This event emmits when tokens change ownership.
   */
  event Perform(
    address indexed _maker,
    address indexed _taker,
    bytes32 _claim
  );

  /**
   * @dev This event emmits when transfer order is cancelled.
   */
  event Cancel(
    address indexed _maker,
    address indexed _taker,
    bytes32 _claim
  );

  /**
   * @dev This event emmits when proxy address is changed..
   */
  event ProxyChange(
    uint256 indexed _index,
    address _proxy
  );

  /**
   * @dev Adds a verified proxy address. 
   * @notice Can be done through a multisig wallet in the future.
   * @param _proxy Proxy address.
   */
  function addProxy(
    address _proxy
  )
    external
    hasAbilities(ABILITY_TO_SET_PROXIES)
  {
    uint256 length = proxies.push(_proxy);
    emit ProxyChange(length - 1, _proxy);
  }

  /**
   * @dev Removes a proxy address. 
   * @notice Can be done through a multisig wallet in the future.
   * @param _index Index of proxy we are removing.
   */
  function removeProxy(
    uint256 _index
  )
    external
    hasAbilities(ABILITY_TO_SET_PROXIES)
  {
    proxies[_index] = address(0);
    emit ProxyChange(_index, address(0));
  }

  /**
   * @dev Performs the atomic swap that can exchange, create, update and do other actions for
   * fungible and non-fungible tokens.
   * @param _data Data required to make the order.
   * @param _signature Data from the signature. 
   */
  function perform(
    OrderData memory _data,
    SignatureData memory _signature
  )
    public 
  {
    require(_data.taker == msg.sender, TAKER_NOT_EQUAL_TO_SENDER);
    require(_data.expiration >= now, CLAIM_EXPIRED);

    bytes32 claim = getOrderDataClaim(_data);
    require(
      isValidSignature(
        _data.maker,
        claim,
        _signature
      ), 
      INVALID_SIGNATURE
    );

    require(!orderCancelled[claim], ORDER_CANCELED);
    require(!orderPerformed[claim], ORDER_ALREADY_PERFORMED);

    orderPerformed[claim] = true;

    _doActions(_data);

    emit Perform(
      _data.maker,
      _data.taker,
      claim
    );
  }

  /** 
   * @dev Cancels order.
   * @notice You can cancel the same order multiple times. There is no check for whether the order
   * was already canceled due to gas optimization. You should either check orderCancelled variable
   * or listen to Cancel event if you want to check if an order is already canceled.
   * @param _data Data of order to cancel.
   */
  function cancel(
    OrderData memory _data
  )
    public
  {
    require(_data.maker == msg.sender, MAKER_NOT_EQUAL_TO_SENDER);

    bytes32 claim = getOrderDataClaim(_data);
    require(!orderPerformed[claim], ORDER_ALREADY_PERFORMED);

    orderCancelled[claim] = true;
    emit Cancel(
      _data.maker,
      _data.taker,
      claim
    );
  }

  /**
   * @dev Calculates keccak-256 hash of OrderData from parameters.
   * @param _orderData Data needed for atomic swap.
   * @return keccak-hash of order data.
   */
  function getOrderDataClaim(
    OrderData memory _orderData
  )
    public
    view
    returns (bytes32)
  {
    bytes32 temp = 0x0;

    for(uint256 i = 0; i < _orderData.actions.length; i++)
    {
      temp = keccak256(
        abi.encodePacked(
          temp,
          _orderData.actions[i].kind,
          _orderData.actions[i].proxy,
          _orderData.actions[i].token,
          _orderData.actions[i].param1,
          _orderData.actions[i].to,
          _orderData.actions[i].value
        )
      );
    }

    return keccak256(
      abi.encodePacked(
        address(this),
        _orderData.maker,
        _orderData.taker,
        temp,
        _orderData.seed,
        _orderData.expiration
      )
    );
  }
  
  /**
   * @dev Verifies if claim signature is valid.
   * @param _signer address of signer.
   * @param _claim Signed Keccak-256 hash.
   * @param _signature Signature data.
   */
  function isValidSignature(
    address _signer,
    bytes32 _claim,
    SignatureData memory _signature
  )
    public
    pure
    returns (bool)
  {
    if (_signature.kind == SignatureKind.eth_sign)
    {
      return _signer == ecrecover(
        keccak256(
          abi.encodePacked(
            "\x19Ethereum Signed Message:\n32",
            _claim
          )
        ),
        _signature.v,
        _signature.r,
        _signature.s
      );
    } else if (_signature.kind == SignatureKind.trezor)
    {
      return _signer == ecrecover(
        keccak256(
          abi.encodePacked(
            "\x19Ethereum Signed Message:\n\x20",
            _claim
          )
        ),
        _signature.v,
        _signature.r,
        _signature.s
      );
    } else if (_signature.kind == SignatureKind.eip712)
    {
      return _signer == ecrecover(
        _claim,
        _signature.v,
        _signature.r,
        _signature.s
      );
    }

    revert(INVALID_SIGNATURE_KIND);
  }

  /**
   * @dev Helper function that makes transfes.
   * @param _order Data needed for order.
   */
  function _doActions(
    OrderData memory _order
  )
    private
  {
    for(uint256 i = 0; i < _order.actions.length; i++)
    {
      require(
        proxies[_order.actions[i].proxy] != address(0),
        INVALID_PROXY
      );

      if (_order.actions[i].kind == ActionKind.create)
      {
        require(
          Abilitable(_order.actions[i].token).isAble(_order.maker, ABILITY_ALLOW_CREATE_ASSET),
          SIGNER_NOT_AUTHORIZED
        );
        
        XcertCreateProxy(proxies[_order.actions[i].proxy]).create(
          _order.actions[i].token,
          _order.actions[i].to,
          _order.actions[i].value,
          _order.actions[i].param1
        );
      } 
      else if (_order.actions[i].kind == ActionKind.transfer)
      {
        address from = address(uint160(bytes20(_order.actions[i].param1)));
        require(
          from == _order.maker
          || from == _order.taker,
          SENDER_NOT_TAKER_OR_MAKER
        );
        
        Proxy(proxies[_order.actions[i].proxy]).execute(
          _order.actions[i].token,
          from,
          _order.actions[i].to,
          _order.actions[i].value
        );
      }
    }
  }
  
}

Contract ABI

[{"constant":false,"inputs":[{"name":"_target","type":"address"},{"name":"_abilities","type":"uint256"}],"name":"grantAbilities","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_proxy","type":"address"}],"name":"addProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"components":[{"name":"maker","type":"address"},{"name":"taker","type":"address"},{"components":[{"name":"kind","type":"uint8"},{"name":"proxy","type":"uint32"},{"name":"token","type":"address"},{"name":"param1","type":"bytes32"},{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"actions","type":"tuple[]"},{"name":"seed","type":"uint256"},{"name":"expiration","type":"uint256"}],"name":"_data","type":"tuple"}],"name":"cancel","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_index","type":"uint256"}],"name":"removeProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"addressToAbility","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"orderCancelled","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"components":[{"name":"maker","type":"address"},{"name":"taker","type":"address"},{"components":[{"name":"kind","type":"uint8"},{"name":"proxy","type":"uint32"},{"name":"token","type":"address"},{"name":"param1","type":"bytes32"},{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"actions","type":"tuple[]"},{"name":"seed","type":"uint256"},{"name":"expiration","type":"uint256"}],"name":"_data","type":"tuple"},{"components":[{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"v","type":"uint8"},{"name":"kind","type":"uint8"}],"name":"_signature","type":"tuple"}],"name":"perform","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_signer","type":"address"},{"name":"_claim","type":"bytes32"},{"components":[{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"v","type":"uint8"},{"name":"kind","type":"uint8"}],"name":"_signature","type":"tuple"}],"name":"isValidSignature","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"proxies","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_target","type":"address"},{"name":"_abilities","type":"uint256"},{"name":"_allowSuperRevoke","type":"bool"}],"name":"revokeAbilities","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_target","type":"address"},{"name":"_abilities","type":"uint256"}],"name":"isAble","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"components":[{"name":"maker","type":"address"},{"name":"taker","type":"address"},{"components":[{"name":"kind","type":"uint8"},{"name":"proxy","type":"uint32"},{"name":"token","type":"address"},{"name":"param1","type":"bytes32"},{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"actions","type":"tuple[]"},{"name":"seed","type":"uint256"},{"name":"expiration","type":"uint256"}],"name":"_orderData","type":"tuple"}],"name":"getOrderDataClaim","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"orderPerformed","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_maker","type":"address"},{"indexed":true,"name":"_taker","type":"address"},{"indexed":false,"name":"_claim","type":"bytes32"}],"name":"Perform","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_maker","type":"address"},{"indexed":true,"name":"_taker","type":"address"},{"indexed":false,"name":"_claim","type":"bytes32"}],"name":"Cancel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_index","type":"uint256"},{"indexed":false,"name":"_proxy","type":"address"}],"name":"ProxyChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_target","type":"address"},{"indexed":true,"name":"_abilities","type":"uint256"}],"name":"GrantAbilities","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_target","type":"address"},{"indexed":true,"name":"_abilities","type":"uint256"}],"name":"RevokeAbilities","type":"event"}]

Contract Creation Code

6080604081815233600081815260208190529182206001908190559290917fc4adfc5f00262a1ab9b2241c7e98408a91e58dc5777d786164bba34a7652f62f91a3611a608061004f6000396000f3fe608060405234801561001057600080fd5b50600436106100cf5760003560e01c80638b1d83351161008c578063aca910e711610066578063aca910e7146101b1578063ba00a330146101c4578063d1c87f30146101d7578063d981e736146101ea576100cf565b80638b1d83351461016b5780638fa76d8d1461017e578063abd90f8514610191576100cf565b80630ab319e8146100d457806323b11d8d146100e957806336d63aca146100fc5780633ab7d8411461010f57806345a32c86146101225780635889bf5e1461014b575b600080fd5b6100e76100e236600461147d565b6101fd565b005b6100e76100f736600461140a565b6102d1565b6100e761010a366004611536565b6103d0565b6100e761011d366004611518565b6104f3565b61013561013036600461140a565b6105e5565b6040516101429190611897565b60405180910390f35b61015e610159366004611518565b6105f7565b6040516101429190611889565b6100e761017936600461156b565b61060c565b61015e61018c366004611430565b610836565b6101a461019f366004611518565b61099e565b60405161014291906117ec565b6100e76101bf3660046114b7565b6109c6565b61015e6101d236600461147d565b610aeb565b6101356101e5366004611536565b610b57565b61015e6101f8366004611518565b610ca8565b6040805180820190915260068152600160d01b6530313730303302602082015260019061022e565b60405180910390fd5b50336000908152602081815260409182902054825180840190935260068352600160d01b6530313730303102918301919091528216821461028557604051600160e51b62461bcd02815260040161022591906118c0565b506001600160a01b038316600081815260208190526040808220805486179055518492917fc4adfc5f00262a1ab9b2241c7e98408a91e58dc5777d786164bba34a7652f62f91a3505050565b6040805180820182526006808252600160d01b6530313730303302602092830152336000908152808352839020548351808501909452908352600160d01b653031373030310291830191909152600291908216821461034657604051600160e51b62461bcd02815260040161022591906118c0565b50600180548082018083556000929092527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6810180546001600160a01b0319166001600160a01b0386161790556040517f8edda873a8ad561ecebeb71ceb3ae6bcb70c2b76a3fcb869859895c4d4fc7416906103c39086906117ec565b60405180910390a2505050565b80516040805180820190915260068152600160d01b65303135303039026020820152906001600160a01b0316331461041e57604051600160e51b62461bcd02815260040161022591906118c0565b50600061042a82610b57565b60008181526003602090815260409182902054825180840190935260068352600160d31b65060626a6060702918301919091529192509060ff161561048557604051600160e51b62461bcd02815260040161022591906118c0565b50600081815260026020908152604091829020805460ff19166001179055830151835191516001600160a01b0391821692909116907f421b43caf093b5e58d1ea89ca0d80151eda923342cf3cfddf5eb6b30d4947ba0906104e7908590611897565b60405180910390a35050565b6040805180820182526006808252600160d01b6530313730303302602092830152336000908152808352839020548351808501909452908352600160d01b653031373030310291830191909152600291908216821461056857604051600160e51b62461bcd02815260040161022591906118c0565b50600060018381548110151561057a57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550817f8edda873a8ad561ecebeb71ceb3ae6bcb70c2b76a3fcb869859895c4d4fc741660006040516105d991906117fa565b60405180910390a25050565b60006020819052908152604090205481565b60026020526000908152604090205460ff1681565b6020808301516040805180820190915260068152600160d01b6530313530303302928101929092526001600160a01b0316331461065f57604051600160e51b62461bcd02815260040161022591906118c0565b5060808201516040805180820190915260068152600160d01b65303135303035026020820152904211156106a957604051600160e51b62461bcd02815260040161022591906118c0565b5060006106b583610b57565b90506106c683600001518284610836565b604051806040016040528060068152602001600160d11b6518189a98181b0281525090151561070b57604051600160e51b62461bcd02815260040161022591906118c0565b5060008181526002602090815260409182902054825180840190935260068352600160d01b65303135303037029183019190915260ff161561076357604051600160e51b62461bcd02815260040161022591906118c0565b5060008181526003602090815260409182902054825180840190935260068352600160d31b65060626a60607029183019190915260ff16156107bb57604051600160e51b62461bcd02815260040161022591906118c0565b506000818152600360205260409020805460ff191660011790556107de83610cbd565b82602001516001600160a01b031683600001516001600160a01b03167fdd97b854c02f699ea0d8984479d0012fbbbd0f4f80fc2e099315f6c47a3da178836040516108299190611897565b60405180910390a3505050565b6000808260600151600281111561084957fe5b14156108eb5760018360405160200161086291906117c1565b60405160208183030381529060405280519060200120836040015184600001518560200151604051600081526020016040526040516108a494939291906118a5565b6020604051602081039080840390855afa1580156108c6573d6000803e3d6000fd5b505050602060405103516001600160a01b0316846001600160a01b0316149050610997565b6001826060015160028111156108fd57fe5b14156109165760018360405160200161086291906117e1565b60028260600151600281111561092857fe5b141561095d57600183836040015184600001518560200151604051600081526020016040526040516108a494939291906118a5565b60408051808201825260068152600160d01b653031353030310260208201529051600160e51b62461bcd02815261022591906004016118c0565b9392505050565b60018054829081106109ac57fe5b6000918252602090912001546001600160a01b0316905081565b6040805180820182526006808252600160d01b6530313730303302602092830152336000908152808352839020548351808501909452908352600160d01b6530313730303102918301919091526001919082168214610a3b57604051600160e51b62461bcd02815260040161022591906118c0565b5081158015610a525750336001600160a01b038516145b15610a9e576040805180820190915260068152600160d11b6518189b9818190260208201526001841615610a9c57604051600160e51b62461bcd02815260040161022591906118c0565b505b6001600160a01b03841660008181526020819052604080822080548719169055518592917fbb71944f65b9a48cc7d835179fb5e874f29b60aa0195785fb54968d8dddef08a91a350505050565b6040805180820190915260068152600160d01b65303137303033026020820152600090821515610b3157604051600160e51b62461bcd02815260040161022591906118c0565b50506001600160a01b038216600090815260208190526040902054811681145b92915050565b600080805b836040015151811015610c5e5781846040015182815181101515610b7c57fe5b60209081029091010151516040860151805184908110610b9857fe5b9060200190602002015160200151866040015184815181101515610bb857fe5b9060200190602002015160400151876040015185815181101515610bd857fe5b9060200190602002015160600151886040015186815181101515610bf857fe5b9060200190602002015160800151896040015187815181101515610c1857fe5b9060200190602002015160a00151604051602001610c3c9796959493929190611746565b60408051601f1981840301815291905280516020909101209150600101610b5c565b5030836000015184602001518386606001518760800151604051602001610c8a969594939291906116dc565b60405160208183030381529060405280519060200120915050919050565b60036020526000908152604090205460ff1681565b60005b816040015151811015611184576040820151805160009160019184908110610ce457fe5b906020019060200201516020015163ffffffff16815481101515610d0457fe5b600091825260209182902001546040805180820190915260068152600160d11b6518189a981819029281019290925290916001600160a01b039091161415610d6257604051600160e51b62461bcd02815260040161022591906118c0565b5060006040830151805183908110610d7657fe5b60209081029091010151516001811115610d8c57fe5b1415610fa1576040820151805182908110610da357fe5b90602001906020020151604001516001600160a01b031663ba00a330836000015160206040518363ffffffff1660e01b8152600401610de392919061186e565b60206040518083038186803b158015610dfb57600080fd5b505afa158015610e0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e3391908101906114fa565b604051806040016040528060068152602001600160d41b6503031353031302815250901515610e7857604051600160e51b62461bcd02815260040161022591906118c0565b506001826040015182815181101515610e8d57fe5b906020019060200201516020015163ffffffff16815481101515610ead57fe5b600091825260209091200154604083015180516001600160a01b03909216916346009b0e919084908110610edd57fe5b9060200190602002015160400151846040015184815181101515610efd57fe5b9060200190602002015160800151856040015185815181101515610f1d57fe5b9060200190602002015160a00151866040015186815181101515610f3d57fe5b90602001906020020151606001516040518563ffffffff1660e01b8152600401610f6a9493929190611846565b600060405180830381600087803b158015610f8457600080fd5b505af1158015610f98573d6000803e3d6000fd5b5050505061117c565b60016040830151805183908110610fb457fe5b60209081029091010151516001811115610fca57fe5b141561117c576000826040015182815181101515610fe457fe5b906020019060200201516060015160601c905082600001516001600160a01b0316816001600160a01b03161480611030575082602001516001600160a01b0316816001600160a01b0316145b604051806040016040528060068152602001600160d21b650c0c4d4c0c0d0281525090151561107557604051600160e51b62461bcd02815260040161022591906118c0565b50600183604001518381518110151561108a57fe5b906020019060200201516020015163ffffffff168154811015156110aa57fe5b600091825260209091200154604084015180516001600160a01b039092169163239aee069190859081106110da57fe5b9060200190602002015160400151838660400151868151811015156110fb57fe5b906020019060200201516080015187604001518781518110151561111b57fe5b9060200190602002015160a001516040518563ffffffff1660e01b81526004016111489493929190611808565b600060405180830381600087803b15801561116257600080fd5b505af1158015611176573d6000803e3d6000fd5b50505050505b600101610cc0565b5050565b6000610997823561192b565b6000601f820183136111a557600080fd5b81356111b86111b3826118f8565b6118d1565b915081818352602084019350602081019050838560c08402820111156111dd57600080fd5b60005b8381101561120b57816111f38882611251565b84525060209092019160c091909101906001016111e0565b5050505092915050565b60006109978235611936565b60006109978251611936565b6000610997823561193b565b60006109978235611969565b60006109978235611978565b600060c0828403121561126357600080fd5b61126d60c06118d1565b9050600061127b8484611239565b825250602061128c848483016113f2565b60208301525060406112a084828501611188565b60408301525060606112b48482850161122d565b60608301525060806112c884828501611188565b60808301525060a06112dc8482850161122d565b60a08301525092915050565b600060a082840312156112fa57600080fd5b61130460a06118d1565b905060006113128484611188565b825250602061132384848301611188565b602083015250604082013567ffffffffffffffff81111561134357600080fd5b61134f84828501611194565b60408301525060606113638482850161122d565b60608301525060806113778482850161122d565b60808301525092915050565b60006080828403121561139557600080fd5b61139f60806118d1565b905060006113ad848461122d565b82525060206113be8484830161122d565b60208301525060406113d2848285016113fe565b60408301525060606113e684828501611245565b60608301525092915050565b6000610997823561195a565b60006109978235611963565b60006020828403121561141c57600080fd5b60006114288484611188565b949350505050565b600080600060c0848603121561144557600080fd5b60006114518686611188565b93505060206114628682870161122d565b925050604061147386828701611383565b9150509250925092565b6000806040838503121561149057600080fd5b600061149c8585611188565b92505060206114ad8582860161122d565b9150509250929050565b6000806000606084860312156114cc57600080fd5b60006114d88686611188565b93505060206114e98682870161122d565b925050604061147386828701611215565b60006020828403121561150c57600080fd5b60006114288484611221565b60006020828403121561152a57600080fd5b6000611428848461122d565b60006020828403121561154857600080fd5b813567ffffffffffffffff81111561155f57600080fd5b611428848285016112e8565b60008060a0838503121561157e57600080fd5b823567ffffffffffffffff81111561159557600080fd5b6115a1858286016112e8565b92505060206114ad85828601611383565b6115bb81611987565b82525050565b6115bb8161192b565b6115bb6115d68261192b565b6119e3565b6115bb81611936565b6115bb8161193b565b6115bb6115f98261193b565b61193b565b6115bb61160a82611992565b6119ff565b600061161a82611919565b611624818561191d565b93506116348185602086016119b3565b61163d81611a0a565b9093019392505050565b6000611654601c83611926565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c0192915050565b600061168d601b83611926565b7f19457468657265756d205369676e6564204d6573736167653a0a2000000000008152601b0192915050565b6115bb6116c58261195a565b6119f4565b6115bb816119a8565b6115bb81611963565b60006116e882896115ca565b6014820191506116f882886115ca565b60148201915061170882876115ca565b60148201915061171882866115ed565b60208201915061172882856115ed565b60208201915061173882846115ed565b506020019695505050505050565b6000611752828a6115ed565b60208201915061176282896115fe565b60018201915061177282886116b9565b60048201915061178282876115ca565b60148201915061179282866115ed565b6020820191506117a282856115ca565b6014820191506117b282846115ed565b50602001979650505050505050565b60006117cc82611647565b91506117d882846115ed565b50602001919050565b60006117cc82611680565b60208101610b5182846115c1565b60208101610b5182846115b2565b6080810161181682876115c1565b61182360208301866115c1565b61183060408301856115c1565b61183d60608301846115e4565b95945050505050565b6080810161185482876115c1565b61186160208301866115c1565b61183060408301856115e4565b6040810161187c82856115c1565b61099760208301846116ca565b60208101610b5182846115db565b60208101610b5182846115e4565b608081016118b382876115e4565b61186160208301866116d3565b60208082528101610997818461160f565b60405181810167ffffffffffffffff811182821017156118f057600080fd5b604052919050565b600067ffffffffffffffff82111561190f57600080fd5b5060209081020190565b5190565b90815260200190565b919050565b6000610b518261194e565b151590565b90565b60006002821061194a57fe5b5090565b6001600160a01b031690565b63ffffffff1690565b60ff1690565b60006002821061194a57600080fd5b60006003821061194a57600080fd5b6000610b518261199d565b6000610b518261193e565b6000610b518261192b565b6000610b5182611963565b60005b838110156119ce5781810151838201526020016119b6565b838111156119dd576000848401525b50505050565b6000610b51826000610b5182611a20565b6000610b5182611a14565b6000610b5182611a1a565b601f01601f191690565b60e01b90565b60f81b90565b60601b9056fea265627a7a7230582035d95e84b77938745f31baeaa0bed8c296c14afd93751ba5b8d062c559fa9d196c6578706572696d656e74616cf50037

Swarm Source

bzzr://35d95e84b77938745f31baeaa0bed8c296c14afd93751ba5b8d062c559fa9d19
Block Age Transaction Difficulty GasUsed Reward
Block Age Uncle Number Difficulty GasUsed Reward