/

SMART CONTRACT on

c
0x6460777cda22ad67bbb97536ffc446d65761197e
Chainbridge Core

Chainbridge Core

Last Transaction

Chainbridge transfer 0xea9a99...8f883d1e
From
0xb7f9f538aa1b41ae2853eb63f1939187ffe70eb4
To
Chainbridge Core
16 minutes
Sat, 06 Mar 2021 00:46:24 GMT
13.00AVAX

AVAX balance

1,286.999 999 999

Contract Properties

Language
Solidity
Compiler Version
v0.6.4+commit.1dca32f3
Source Code
Available and Matching

Compiler settings

{
  "compilationTarget": {
    "ChainBridge.sol": "ChainBridge"
  },
  "evmVersion": "istanbul",
  "optimizer": {
    "enabled": false,
    "runs": 0
  }
}

ABI

[
  {
    "type": "constructor",
    "stateMutability": "nonpayable",
    "inputs": [
      {
        "type": "uint8",
        "name": "chainID",
        "internalType": "uint8"
      },
      {
        "type": "address[]",
        "name": "initialRelayers",
        "internalType": "address[]"
      },
      {
        "type": "uint256",
        "name": "initialRelayerThreshold",
        "internalType": "uint256"
      },
      {
        "type": "uint256",
        "name": "fee",
        "internalType": "uint256"
      },
      {
        "type": "uint256",
        "name": "expiry",
        "internalType": "uint256"
      }
    ]
  },
  {
    "type": "event",
    "name": "Deposit",
    "inputs": [
      {
        "type": "uint8",
        "name": "destinationChainID",
        "internalType": "uint8",
        "indexed": true
      },
      {
        "type": "bytes32",
        "name": "resourceID",
        "internalType": "bytes32",
        "indexed": true
      },
      {
        "type": "uint64",
        "name": "depositNonce",
        "internalType": "uint64",
        "indexed": true
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "Paused",
    "inputs": [
      {
        "type": "address",
        "name": "account",
        "internalType": "address",
        "indexed": false
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "ProposalEvent",
    "inputs": [
      {
        "type": "uint8",
        "name": "originChainID",
        "internalType": "uint8",
        "indexed": true
      },
      {
        "type": "uint64",
        "name": "depositNonce",
        "internalType": "uint64",
        "indexed": true
      },
      {
        "type": "uint8",
        "name": "status",
        "internalType": "enum Bridge.ProposalStatus",
        "indexed": true
      },
      {
        "type": "bytes32",
        "name": "resourceID",
        "internalType": "bytes32",
        "indexed": false
      },
      {
        "type": "bytes32",
        "name": "dataHash",
        "internalType": "bytes32",
        "indexed": false
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "ProposalVote",
    "inputs": [
      {
        "type": "uint8",
        "name": "originChainID",
        "internalType": "uint8",
        "indexed": true
      },
      {
        "type": "uint64",
        "name": "depositNonce",
        "internalType": "uint64",
        "indexed": true
      },
      {
        "type": "uint8",
        "name": "status",
        "internalType": "enum Bridge.ProposalStatus",
        "indexed": true
      },
      {
        "type": "bytes32",
        "name": "resourceID",
        "internalType": "bytes32",
        "indexed": false
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "RelayerAdded",
    "inputs": [
      {
        "type": "address",
        "name": "relayer",
        "internalType": "address",
        "indexed": true
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "RelayerRemoved",
    "inputs": [
      {
        "type": "address",
        "name": "relayer",
        "internalType": "address",
        "indexed": true
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "RelayerThresholdChanged",
    "inputs": [
      {
        "type": "uint256",
        "name": "newThreshold",
        "internalType": "uint256",
        "indexed": true
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "RoleGranted",
    "inputs": [
      {
        "type": "bytes32",
        "name": "role",
        "internalType": "bytes32",
        "indexed": true
      },
      {
        "type": "address",
        "name": "account",
        "internalType": "address",
        "indexed": true
      },
      {
        "type": "address",
        "name": "sender",
        "internalType": "address",
        "indexed": true
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "RoleRevoked",
    "inputs": [
      {
        "type": "bytes32",
        "name": "role",
        "internalType": "bytes32",
        "indexed": true
      },
      {
        "type": "address",
        "name": "account",
        "internalType": "address",
        "indexed": true
      },
      {
        "type": "address",
        "name": "sender",
        "internalType": "address",
        "indexed": true
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "Unpaused",
    "inputs": [
      {
        "type": "address",
        "name": "account",
        "internalType": "address",
        "indexed": false
      }
    ],
    "anonymous": false
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "bytes32",
        "name": "",
        "internalType": "bytes32"
      }
    ],
    "name": "DEFAULT_ADMIN_ROLE",
    "inputs": []
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "bytes32",
        "name": "",
        "internalType": "bytes32"
      }
    ],
    "name": "RELAYER_ROLE",
    "inputs": []
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "uint8",
        "name": "",
        "internalType": "uint8"
      }
    ],
    "name": "_chainID",
    "inputs": []
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "uint64",
        "name": "",
        "internalType": "uint64"
      }
    ],
    "name": "_depositCounts",
    "inputs": [
      {
        "type": "uint8",
        "name": "",
        "internalType": "uint8"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "bytes",
        "name": "",
        "internalType": "bytes"
      }
    ],
    "name": "_depositRecords",
    "inputs": [
      {
        "type": "uint64",
        "name": "",
        "internalType": "uint64"
      },
      {
        "type": "uint8",
        "name": "",
        "internalType": "uint8"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "uint256",
        "name": "",
        "internalType": "uint256"
      }
    ],
    "name": "_expiry",
    "inputs": []
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "uint256",
        "name": "",
        "internalType": "uint256"
      }
    ],
    "name": "_fee",
    "inputs": []
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "bool",
        "name": "",
        "internalType": "bool"
      }
    ],
    "name": "_hasVotedOnProposal",
    "inputs": [
      {
        "type": "uint72",
        "name": "",
        "internalType": "uint72"
      },
      {
        "type": "bytes32",
        "name": "",
        "internalType": "bytes32"
      },
      {
        "type": "address",
        "name": "",
        "internalType": "address"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "bytes32",
        "name": "_resourceID",
        "internalType": "bytes32"
      },
      {
        "type": "bytes32",
        "name": "_dataHash",
        "internalType": "bytes32"
      },
      {
        "type": "uint8",
        "name": "_status",
        "internalType": "enum Bridge.ProposalStatus"
      },
      {
        "type": "uint256",
        "name": "_proposedBlock",
        "internalType": "uint256"
      }
    ],
    "name": "_proposals",
    "inputs": [
      {
        "type": "uint72",
        "name": "",
        "internalType": "uint72"
      },
      {
        "type": "bytes32",
        "name": "",
        "internalType": "bytes32"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "uint256",
        "name": "",
        "internalType": "uint256"
      }
    ],
    "name": "_relayerThreshold",
    "inputs": []
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "address",
        "name": "",
        "internalType": "address"
      }
    ],
    "name": "_resourceIDToHandlerAddress",
    "inputs": [
      {
        "type": "bytes32",
        "name": "",
        "internalType": "bytes32"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "uint256",
        "name": "",
        "internalType": "uint256"
      }
    ],
    "name": "_totalProposals",
    "inputs": []
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "uint256",
        "name": "",
        "internalType": "uint256"
      }
    ],
    "name": "_totalRelayers",
    "inputs": []
  },
  {
    "type": "function",
    "stateMutability": "nonpayable",
    "outputs": [],
    "name": "adminAddRelayer",
    "inputs": [
      {
        "type": "address",
        "name": "relayerAddress",
        "internalType": "address"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "nonpayable",
    "outputs": [],
    "name": "adminChangeFee",
    "inputs": [
      {
        "type": "uint256",
        "name": "newFee",
        "internalType": "uint256"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "nonpayable",
    "outputs": [],
    "name": "adminChangeRelayerThreshold",
    "inputs": [
      {
        "type": "uint256",
        "name": "newThreshold",
        "internalType": "uint256"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "nonpayable",
    "outputs": [],
    "name": "adminPauseTransfers",
    "inputs": []
  },
  {
    "type": "function",
    "stateMutability": "nonpayable",
    "outputs": [],
    "name": "adminRemoveRelayer",
    "inputs": [
      {
        "type": "address",
        "name": "relayerAddress",
        "internalType": "address"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "nonpayable",
    "outputs": [],
    "name": "adminSetBurnable",
    "inputs": [
      {
        "type": "address",
        "name": "handlerAddress",
        "internalType": "address"
      },
      {
        "type": "address",
        "name": "tokenAddress",
        "internalType": "address"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "nonpayable",
    "outputs": [],
    "name": "adminSetGenericResource",
    "inputs": [
      {
        "type": "address",
        "name": "handlerAddress",
        "internalType": "address"
      },
      {
        "type": "bytes32",
        "name": "resourceID",
        "internalType": "bytes32"
      },
      {
        "type": "address",
        "name": "contractAddress",
        "internalType": "address"
      },
      {
        "type": "bytes4",
        "name": "depositFunctionSig",
        "internalType": "bytes4"
      },
      {
        "type": "bytes4",
        "name": "executeFunctionSig",
        "internalType": "bytes4"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "nonpayable",
    "outputs": [],
    "name": "adminSetResource",
    "inputs": [
      {
        "type": "address",
        "name": "handlerAddress",
        "internalType": "address"
      },
      {
        "type": "bytes32",
        "name": "resourceID",
        "internalType": "bytes32"
      },
      {
        "type": "address",
        "name": "tokenAddress",
        "internalType": "address"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "nonpayable",
    "outputs": [],
    "name": "adminUnpauseTransfers",
    "inputs": []
  },
  {
    "type": "function",
    "stateMutability": "nonpayable",
    "outputs": [],
    "name": "adminWithdraw",
    "inputs": [
      {
        "type": "address",
        "name": "handlerAddress",
        "internalType": "address"
      },
      {
        "type": "address",
        "name": "tokenAddress",
        "internalType": "address"
      },
      {
        "type": "address",
        "name": "recipient",
        "internalType": "address"
      },
      {
        "type": "uint256",
        "name": "amountOrTokenID",
        "internalType": "uint256"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "nonpayable",
    "outputs": [],
    "name": "cancelProposal",
    "inputs": [
      {
        "type": "uint8",
        "name": "chainID",
        "internalType": "uint8"
      },
      {
        "type": "uint64",
        "name": "depositNonce",
        "internalType": "uint64"
      },
      {
        "type": "bytes32",
        "name": "dataHash",
        "internalType": "bytes32"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "payable",
    "outputs": [],
    "name": "deposit",
    "inputs": [
      {
        "type": "uint8",
        "name": "destinationChainID",
        "internalType": "uint8"
      },
      {
        "type": "bytes32",
        "name": "resourceID",
        "internalType": "bytes32"
      },
      {
        "type": "bytes",
        "name": "data",
        "internalType": "bytes"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "nonpayable",
    "outputs": [],
    "name": "executeProposal",
    "inputs": [
      {
        "type": "uint8",
        "name": "chainID",
        "internalType": "uint8"
      },
      {
        "type": "uint64",
        "name": "depositNonce",
        "internalType": "uint64"
      },
      {
        "type": "bytes",
        "name": "data",
        "internalType": "bytes"
      },
      {
        "type": "bytes32",
        "name": "resourceID",
        "internalType": "bytes32"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "tuple",
        "name": "",
        "internalType": "struct Bridge.Proposal",
        "components": [
          {
            "type": "bytes32",
            "name": "_resourceID",
            "internalType": "bytes32"
          },
          {
            "type": "bytes32",
            "name": "_dataHash",
            "internalType": "bytes32"
          },
          {
            "type": "address[]",
            "name": "_yesVotes",
            "internalType": "address[]"
          },
          {
            "type": "address[]",
            "name": "_noVotes",
            "internalType": "address[]"
          },
          {
            "type": "uint8",
            "name": "_status",
            "internalType": "enum Bridge.ProposalStatus"
          },
          {
            "type": "uint256",
            "name": "_proposedBlock",
            "internalType": "uint256"
          }
        ]
      }
    ],
    "name": "getProposal",
    "inputs": [
      {
        "type": "uint8",
        "name": "originChainID",
        "internalType": "uint8"
      },
      {
        "type": "uint64",
        "name": "depositNonce",
        "internalType": "uint64"
      },
      {
        "type": "bytes32",
        "name": "dataHash",
        "internalType": "bytes32"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "bytes32",
        "name": "",
        "internalType": "bytes32"
      }
    ],
    "name": "getRoleAdmin",
    "inputs": [
      {
        "type": "bytes32",
        "name": "role",
        "internalType": "bytes32"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "address",
        "name": "",
        "internalType": "address"
      }
    ],
    "name": "getRoleMember",
    "inputs": [
      {
        "type": "bytes32",
        "name": "role",
        "internalType": "bytes32"
      },
      {
        "type": "uint256",
        "name": "index",
        "internalType": "uint256"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "uint256",
        "name": "",
        "internalType": "uint256"
      }
    ],
    "name": "getRoleMemberCount",
    "inputs": [
      {
        "type": "bytes32",
        "name": "role",
        "internalType": "bytes32"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "nonpayable",
    "outputs": [],
    "name": "grantRole",
    "inputs": [
      {
        "type": "bytes32",
        "name": "role",
        "internalType": "bytes32"
      },
      {
        "type": "address",
        "name": "account",
        "internalType": "address"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "bool",
        "name": "",
        "internalType": "bool"
      }
    ],
    "name": "hasRole",
    "inputs": [
      {
        "type": "bytes32",
        "name": "role",
        "internalType": "bytes32"
      },
      {
        "type": "address",
        "name": "account",
        "internalType": "address"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "bool",
        "name": "",
        "internalType": "bool"
      }
    ],
    "name": "isRelayer",
    "inputs": [
      {
        "type": "address",
        "name": "relayer",
        "internalType": "address"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "view",
    "outputs": [
      {
        "type": "bool",
        "name": "",
        "internalType": "bool"
      }
    ],
    "name": "paused",
    "inputs": []
  },
  {
    "type": "function",
    "stateMutability": "nonpayable",
    "outputs": [],
    "name": "renounceAdmin",
    "inputs": [
      {
        "type": "address",
        "name": "newAdmin",
        "internalType": "address"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "nonpayable",
    "outputs": [],
    "name": "renounceRole",
    "inputs": [
      {
        "type": "bytes32",
        "name": "role",
        "internalType": "bytes32"
      },
      {
        "type": "address",
        "name": "account",
        "internalType": "address"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "nonpayable",
    "outputs": [],
    "name": "revokeRole",
    "inputs": [
      {
        "type": "bytes32",
        "name": "role",
        "internalType": "bytes32"
      },
      {
        "type": "address",
        "name": "account",
        "internalType": "address"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "nonpayable",
    "outputs": [],
    "name": "transferFunds",
    "inputs": [
      {
        "type": "address[]",
        "name": "addrs",
        "internalType": "address payable[]"
      },
      {
        "type": "uint256[]",
        "name": "amounts",
        "internalType": "uint256[]"
      }
    ]
  },
  {
    "type": "function",
    "stateMutability": "nonpayable",
    "outputs": [],
    "name": "voteProposal",
    "inputs": [
      {
        "type": "uint8",
        "name": "chainID",
        "internalType": "uint8"
      },
      {
        "type": "uint64",
        "name": "depositNonce",
        "internalType": "uint64"
      },
      {
        "type": "bytes32",
        "name": "resourceID",
        "internalType": "bytes32"
      },
      {
        "type": "bytes32",
        "name": "dataHash",
        "internalType": "bytes32"
      }
    ]
  }
]

Contract Source Code

Chainbridge.sol

Chainbridge.sol

// File: @openzeppelin/contracts/utils/EnumerableSet.sol

pragma solidity ^0.6.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256`
 * (`UintSet`) are supported.
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;

        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping (bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) { // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            bytes32 lastvalue = set._values[lastIndex];

            // Move the last value to the index where the value to delete is
            set._values[toDeleteIndex] = lastvalue;
            // Update the index for the moved value
            set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        require(set._values.length > index, "EnumerableSet: index out of bounds");
        return set._values[index];
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(value)));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(value)));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(value)));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint256(_at(set._inner, index)));
    }


    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }
}

// File: @openzeppelin/contracts/utils/Address.sol

pragma solidity ^0.6.2;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }
}

// File: @openzeppelin/contracts/GSN/Context.sol

pragma solidity ^0.6.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
contract Context {
    // Empty internal constructor, to prevent people from mistakenly deploying
    // an instance of this contract, which should be used via inheritance.
    constructor () internal { }

    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

// File: @openzeppelin/contracts/access/AccessControl.sol

pragma solidity ^0.6.0;




/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControl is Context {
    using EnumerableSet for EnumerableSet.AddressSet;
    using Address for address;

    struct RoleData {
        EnumerableSet.AddressSet members;
        bytes32 adminRole;
    }

    mapping (bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view returns (bool) {
        return _roles[role].members.contains(account);
    }

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) public view returns (uint256) {
        return _roles[role].members.length();
    }

    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) public view returns (address) {
        return _roles[role].members.at(index);
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) public virtual {
        require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant");

        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) public virtual {
        require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke");

        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) public virtual {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        _roles[role].adminRole = adminRole;
    }

    function _grantRole(bytes32 role, address account) private {
        if (_roles[role].members.add(account)) {
            emit RoleGranted(role, account, _msgSender());
        }
    }

    function _revokeRole(bytes32 role, address account) private {
        if (_roles[role].members.remove(account)) {
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

// File: contracts/utils/Pausable.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;


/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This is a stripped down version of Open zeppelin's Pausable contract.
 * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/EnumerableSet.sol
 *
 */
contract Pausable {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor () internal {
        _paused = false;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view returns (bool) {
        return _paused;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _whenNotPaused();
        _;
    }

    function _whenNotPaused() private view {
        require(!_paused, "Pausable: paused");
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenPaused() {
        _whenPaused();
        _;
    }

    function _whenPaused() private view {
        require(_paused, "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(msg.sender);
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(msg.sender);
    }
}

// File: contracts/utils/SafeMath.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * note that this is a stripped down version of open zeppelin's safemath
 * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol
 */

contract SafeMath {

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return _sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function _sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

}

// File: contracts/interfaces/IDepositExecute.sol

pragma solidity 0.6.4;

/**
    @title Interface for handler contracts that support deposits and deposit executions.
    @author ChainSafe Systems.
 */
interface IDepositExecute {
    /**
        @notice It is intended that deposit are made using the Bridge contract.
        @param destinationChainID Chain ID deposit is expected to be bridged to.
        @param depositNonce This value is generated as an ID by the Bridge contract.
        @param depositer Address of account making the deposit in the Bridge contract.
        @param data Consists of additional data needed for a specific deposit.
     */
    function deposit(bytes32 resourceID, uint8 destinationChainID, uint64 depositNonce, address depositer, bytes calldata data) external;

    /**
        @notice It is intended that proposals are executed by the Bridge contract.
        @param data Consists of additional data needed for a specific deposit execution.
     */
    function executeProposal(bytes32 resourceID, bytes calldata data) external;
}

// File: contracts/interfaces/IBridge.sol

pragma solidity 0.6.4;

/**
    @title Interface for Bridge contract.
    @author ChainSafe Systems.
 */
interface IBridge {
    /**
        @notice Exposing getter for {_chainID} instead of forcing the use of call.
        @return uint8 The {_chainID} that is currently set for the Bridge contract.
     */
    function _chainID() external returns (uint8);
}

// File: contracts/interfaces/IERCHandler.sol

pragma solidity 0.6.4;

/**
    @title Interface to be used with handlers that support ERC20s and ERC721s.
    @author ChainSafe Systems.
 */
interface IERCHandler {
    /**
        @notice Correlates {resourceID} with {contractAddress}.
        @param resourceID ResourceID to be used when making deposits.
        @param contractAddress Address of contract to be called when a deposit is made and a deposited is executed.
     */
    function setResource(bytes32 resourceID, address contractAddress) external;
    /**
        @notice Marks {contractAddress} as mintable/burnable.
        @param contractAddress Address of contract to be used when making or executing deposits.
     */
    function setBurnable(address contractAddress) external;
    /**
        @notice Used to manually release funds from ERC safes.
        @param tokenAddress Address of token contract to release.
        @param recipient Address to release tokens to.
        @param amountOrTokenID Either the amount of ERC20 tokens or the ERC721 token ID to release.
     */
    function withdraw(address tokenAddress, address recipient, uint256 amountOrTokenID) external;
}

// File: contracts/interfaces/IGenericHandler.sol

pragma solidity 0.6.4;

/**
    @title Interface for handler that handles generic deposits and deposit executions.
    @author ChainSafe Systems.
 */
interface IGenericHandler {
    /**
        @notice Correlates {resourceID} with {contractAddress}, {depositFunctionSig}, and {executeFunctionSig}.
        @param resourceID ResourceID to be used when making deposits.
        @param contractAddress Address of contract to be called when a deposit is made and a deposited is executed.
        @param depositFunctionSig Function signature of method to be called in {contractAddress} when a deposit is made.
        @param executeFunctionSig Function signature of method to be called in {contractAddress} when a deposit is executed.
     */
    function setResource(bytes32 resourceID, address contractAddress, bytes4 depositFunctionSig, bytes4 executeFunctionSig) external;
}

// File: contracts/Bridge.sol

pragma solidity 0.6.4;
pragma experimental ABIEncoderV2;








/**
    @title Facilitates deposits, creation and votiing of deposit proposals, and deposit executions.
    @author ChainSafe Systems.
 */
contract Bridge is Pausable, AccessControl, SafeMath {

    uint8   public _chainID;
    uint256 public _relayerThreshold;
    uint256 public _totalRelayers;
    uint256 public _totalProposals;
    uint256 public _fee;
    uint256 public _expiry;

    enum Vote {No, Yes}

    enum ProposalStatus {Inactive, Active, Passed, Executed, Cancelled}

    struct Proposal {
        bytes32 _resourceID;
        bytes32 _dataHash;
        address[] _yesVotes;
        address[] _noVotes;
        ProposalStatus _status;
        uint256 _proposedBlock;
    }

    // destinationChainID => number of deposits
    mapping(uint8 => uint64) public _depositCounts;
    // resourceID => handler address
    mapping(bytes32 => address) public _resourceIDToHandlerAddress;
    // depositNonce => destinationChainID => bytes
    mapping(uint64 => mapping(uint8 => bytes)) public _depositRecords;
    // destinationChainID + depositNonce => dataHash => Proposal
    mapping(uint72 => mapping(bytes32 => Proposal)) public _proposals;
    // destinationChainID + depositNonce => dataHash => relayerAddress => bool
    mapping(uint72 => mapping(bytes32 => mapping(address => bool))) public _hasVotedOnProposal;

    event RelayerThresholdChanged(uint indexed newThreshold);
    event RelayerAdded(address indexed relayer);
    event RelayerRemoved(address indexed relayer);
    event Deposit(
        uint8   indexed destinationChainID,
        bytes32 indexed resourceID,
        uint64  indexed depositNonce
    );
    event ProposalEvent(
        uint8           indexed originChainID,
        uint64          indexed depositNonce,
        ProposalStatus  indexed status,
        bytes32 resourceID,
        bytes32 dataHash
    );

    event ProposalVote(
        uint8   indexed originChainID,
        uint64  indexed depositNonce,
        ProposalStatus indexed status,
        bytes32 resourceID
    );

    bytes32 public constant RELAYER_ROLE = keccak256("RELAYER_ROLE");

    modifier onlyAdmin() {
        _onlyAdmin();
        _;
    }

    modifier onlyAdminOrRelayer() {
        _onlyAdminOrRelayer();
        _;
    }

    modifier onlyRelayers() {
        _onlyRelayers();
        _;
    }

    function _onlyAdminOrRelayer() private {
        require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender) || hasRole(RELAYER_ROLE, msg.sender),
            "sender is not relayer or admin");
    }

    function _onlyAdmin() private {
        require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "sender doesn't have admin role");
    }

    function _onlyRelayers() private {
        require(hasRole(RELAYER_ROLE, msg.sender), "sender doesn't have relayer role");
    }

    /**
        @notice Initializes Bridge, creates and grants {msg.sender} the admin role,
        creates and grants {initialRelayers} the relayer role.
        @param chainID ID of chain the Bridge contract exists on.
        @param initialRelayers Addresses that should be initially granted the relayer role.
        @param initialRelayerThreshold Number of votes needed for a deposit proposal to be considered passed.
     */
    constructor (uint8 chainID, address[] memory initialRelayers, uint initialRelayerThreshold, uint256 fee, uint256 expiry) public {
        _chainID = chainID;
        _relayerThreshold = initialRelayerThreshold;
        _fee = fee;
        _expiry = expiry;

        _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
        _setRoleAdmin(RELAYER_ROLE, DEFAULT_ADMIN_ROLE);

        for (uint i; i < initialRelayers.length; i++) {
            grantRole(RELAYER_ROLE, initialRelayers[i]);
            _totalRelayers++;
        }

    }

    /**
        @notice Returns true if {relayer} has the relayer role.
        @param relayer Address to check.
     */
    function isRelayer(address relayer) external view returns (bool) {
        return hasRole(RELAYER_ROLE, relayer);
    }

    /**
        @notice Removes admin role from {msg.sender} and grants it to {newAdmin}.
        @notice Only callable by an address that currently has the admin role.
        @param newAdmin Address that admin role will be granted to.
     */
    function renounceAdmin(address newAdmin) external onlyAdmin {
        grantRole(DEFAULT_ADMIN_ROLE, newAdmin);
        renounceRole(DEFAULT_ADMIN_ROLE, msg.sender);
    }

    /**
        @notice Pauses deposits, proposal creation and voting, and deposit executions.
        @notice Only callable by an address that currently has the admin role.
     */
    function adminPauseTransfers() external onlyAdmin {
        _pause();
    }

    /**
        @notice Unpauses deposits, proposal creation and voting, and deposit executions.
        @notice Only callable by an address that currently has the admin role.
     */
    function adminUnpauseTransfers() external onlyAdmin {
        _unpause();
    }

    /**
        @notice Modifies the number of votes required for a proposal to be considered passed.
        @notice Only callable by an address that currently has the admin role.
        @param newThreshold Value {_relayerThreshold} will be changed to.
        @notice Emits {RelayerThresholdChanged} event.
     */
    function adminChangeRelayerThreshold(uint newThreshold) external onlyAdmin {
        _relayerThreshold = newThreshold;
        emit RelayerThresholdChanged(newThreshold);
    }

    /**
        @notice Grants {relayerAddress} the relayer role and increases {_totalRelayer} count.
        @notice Only callable by an address that currently has the admin role.
        @param relayerAddress Address of relayer to be added.
        @notice Emits {RelayerAdded} event.
     */
    function adminAddRelayer(address relayerAddress) external onlyAdmin {
        require(!hasRole(RELAYER_ROLE, relayerAddress), "addr already has relayer role!");
        grantRole(RELAYER_ROLE, relayerAddress);
        emit RelayerAdded(relayerAddress);
        _totalRelayers++;
    }

    /**
        @notice Removes relayer role for {relayerAddress} and decreases {_totalRelayer} count.
        @notice Only callable by an address that currently has the admin role.
        @param relayerAddress Address of relayer to be removed.
        @notice Emits {RelayerRemoved} event.
     */
    function adminRemoveRelayer(address relayerAddress) external onlyAdmin {
        require(hasRole(RELAYER_ROLE, relayerAddress), "addr doesn't have relayer role!");
        revokeRole(RELAYER_ROLE, relayerAddress);
        emit RelayerRemoved(relayerAddress);
        _totalRelayers--;
    }

    /**
        @notice Sets a new resource for handler contracts that use the IERCHandler interface,
        and maps the {handlerAddress} to {resourceID} in {_resourceIDToHandlerAddress}.
        @notice Only callable by an address that currently has the admin role.
        @param handlerAddress Address of handler resource will be set for.
        @param resourceID ResourceID to be used when making deposits.
        @param tokenAddress Address of contract to be called when a deposit is made and a deposited is executed.
     */
    function adminSetResource(address handlerAddress, bytes32 resourceID, address tokenAddress) external onlyAdmin {
        _resourceIDToHandlerAddress[resourceID] = handlerAddress;
        IERCHandler handler = IERCHandler(handlerAddress);
        handler.setResource(resourceID, tokenAddress);
    }

    /**
        @notice Sets a new resource for handler contracts that use the IGenericHandler interface,
        and maps the {handlerAddress} to {resourceID} in {_resourceIDToHandlerAddress}.
        @notice Only callable by an address that currently has the admin role.
        @param handlerAddress Address of handler resource will be set for.
        @param resourceID ResourceID to be used when making deposits.
        @param contractAddress Address of contract to be called when a deposit is made and a deposited is executed.
     */
    function adminSetGenericResource(
        address handlerAddress,
        bytes32 resourceID,
        address contractAddress,
        bytes4 depositFunctionSig,
        bytes4 executeFunctionSig
    ) external onlyAdmin {
        _resourceIDToHandlerAddress[resourceID] = handlerAddress;
        IGenericHandler handler = IGenericHandler(handlerAddress);
        handler.setResource(resourceID, contractAddress, depositFunctionSig, executeFunctionSig);
    }

    /**
        @notice Sets a resource as burnable for handler contracts that use the IERCHandler interface.
        @notice Only callable by an address that currently has the admin role.
        @param handlerAddress Address of handler resource will be set for.
        @param tokenAddress Address of contract to be called when a deposit is made and a deposited is executed.
     */
    function adminSetBurnable(address handlerAddress, address tokenAddress) external onlyAdmin {
        IERCHandler handler = IERCHandler(handlerAddress);
        handler.setBurnable(tokenAddress);
    }

    /**
        @notice Returns a proposal.
        @param originChainID Chain ID deposit originated from.
        @param depositNonce ID of proposal generated by proposal's origin Bridge contract.
        @param dataHash Hash of data to be provided when deposit proposal is executed.
        @return Proposal which consists of:
        - _dataHash Hash of data to be provided when deposit proposal is executed.
        - _yesVotes Number of votes in favor of proposal.
        - _noVotes Number of votes against proposal.
        - _status Current status of proposal.
     */
    function getProposal(uint8 originChainID, uint64 depositNonce, bytes32 dataHash) external view returns (Proposal memory) {
        uint72 nonceAndID = (uint72(depositNonce) << 8) | uint72(originChainID);
        return _proposals[nonceAndID][dataHash];
    }

    /**
        @notice Changes deposit fee.
        @notice Only callable by admin.
        @param newFee Value {_fee} will be updated to.
     */
    function adminChangeFee(uint newFee) external onlyAdmin {
        require(_fee != newFee, "Current fee is equal to new fee");
        _fee = newFee;
    }

    /**
        @notice Used to manually withdraw funds from ERC safes.
        @param handlerAddress Address of handler to withdraw from.
        @param tokenAddress Address of token to withdraw.
        @param recipient Address to withdraw tokens to.
        @param amountOrTokenID Either the amount of ERC20 tokens or the ERC721 token ID to withdraw.
     */
    function adminWithdraw(
        address handlerAddress,
        address tokenAddress,
        address recipient,
        uint256 amountOrTokenID
    ) external onlyAdmin {
        IERCHandler handler = IERCHandler(handlerAddress);
        handler.withdraw(tokenAddress, recipient, amountOrTokenID);
    }

    /**
        @notice Initiates a transfer using a specified handler contract.
        @notice Only callable when Bridge is not paused.
        @param destinationChainID ID of chain deposit will be bridged to.
        @param resourceID ResourceID used to find address of handler to be used for deposit.
        @param data Additional data to be passed to specified handler.
        @notice Emits {Deposit} event.
     */
    function deposit(uint8 destinationChainID, bytes32 resourceID, bytes calldata data) external payable whenNotPaused {
        require(msg.value == _fee, "Incorrect fee supplied");

        address handler = _resourceIDToHandlerAddress[resourceID];
        require(handler != address(0), "resourceID not mapped to handler");

        uint64 depositNonce = ++_depositCounts[destinationChainID];
        _depositRecords[depositNonce][destinationChainID] = data;

        IDepositExecute depositHandler = IDepositExecute(handler);
        depositHandler.deposit(resourceID, destinationChainID, depositNonce, msg.sender, data);

        emit Deposit(destinationChainID, resourceID, depositNonce);
    }

    /**
        @notice When called, {msg.sender} will be marked as voting in favor of proposal.
        @notice Only callable by relayers when Bridge is not paused.
        @param chainID ID of chain deposit originated from.
        @param depositNonce ID of deposited generated by origin Bridge contract.
        @param dataHash Hash of data provided when deposit was made.
        @notice Proposal must not have already been passed or executed.
        @notice {msg.sender} must not have already voted on proposal.
        @notice Emits {ProposalEvent} event with status indicating the proposal status.
        @notice Emits {ProposalVote} event.
     */
    function voteProposal(uint8 chainID, uint64 depositNonce, bytes32 resourceID, bytes32 dataHash) external onlyRelayers whenNotPaused {

        uint72 nonceAndID = (uint72(depositNonce) << 8) | uint72(chainID);
        Proposal storage proposal = _proposals[nonceAndID][dataHash];

        require(_resourceIDToHandlerAddress[resourceID] != address(0), "no handler for resourceID");
        require(uint(proposal._status) <= 1, "proposal already passed/executed/cancelled");
        require(!_hasVotedOnProposal[nonceAndID][dataHash][msg.sender], "relayer already voted");

        if (uint(proposal._status) == 0) {
            ++_totalProposals;
            _proposals[nonceAndID][dataHash] = Proposal({
                _resourceID : resourceID,
                _dataHash : dataHash,
                _yesVotes : new address[](1),
                _noVotes : new address[](0),
                _status : ProposalStatus.Active,
                _proposedBlock : block.number
                });

            proposal._yesVotes[0] = msg.sender;
            emit ProposalEvent(chainID, depositNonce, ProposalStatus.Active, resourceID, dataHash);
        } else {
            if (sub(block.number, proposal._proposedBlock) > _expiry) {
                // if the number of blocks that has passed since this proposal was
                // submitted exceeds the expiry threshold set, cancel the proposal
                proposal._status = ProposalStatus.Cancelled;
                emit ProposalEvent(chainID, depositNonce, ProposalStatus.Cancelled, resourceID, dataHash);
            } else {
                require(dataHash == proposal._dataHash, "datahash mismatch");
                proposal._yesVotes.push(msg.sender);


            }

        }
        if (proposal._status != ProposalStatus.Cancelled) {
            _hasVotedOnProposal[nonceAndID][dataHash][msg.sender] = true;
            emit ProposalVote(chainID, depositNonce, proposal._status, resourceID);

            // If _depositThreshold is set to 1, then auto finalize
            // or if _relayerThreshold has been exceeded
            if (_relayerThreshold <= 1 || proposal._yesVotes.length >= _relayerThreshold) {
                proposal._status = ProposalStatus.Passed;

                emit ProposalEvent(chainID, depositNonce, ProposalStatus.Passed, resourceID, dataHash);
            }
        }

    }

    /**
        @notice Executes a deposit proposal that is considered passed using a specified handler contract.
        @notice Only callable by relayers when Bridge is not paused.
        @param chainID ID of chain deposit originated from.
        @param depositNonce ID of deposited generated by origin Bridge contract.
        @param dataHash Hash of data originally provided when deposit was made.
        @notice Proposal must be past expiry threshold.
        @notice Emits {ProposalEvent} event with status {Cancelled}.
     */
    function cancelProposal(uint8 chainID, uint64 depositNonce, bytes32 dataHash) public onlyAdminOrRelayer {
        uint72 nonceAndID = (uint72(depositNonce) << 8) | uint72(chainID);
        Proposal storage proposal = _proposals[nonceAndID][dataHash];

        require(proposal._status != ProposalStatus.Cancelled, "Proposal already cancelled");
        require(sub(block.number, proposal._proposedBlock) > _expiry, "Proposal not at expiry threshold");

        proposal._status = ProposalStatus.Cancelled;
        emit ProposalEvent(chainID, depositNonce, ProposalStatus.Cancelled, proposal._resourceID, proposal._dataHash);

    }

    /**
        @notice Executes a deposit proposal that is considered passed using a specified handler contract.
        @notice Only callable by relayers when Bridge is not paused.
        @param chainID ID of chain deposit originated from.
        @param resourceID ResourceID to be used when making deposits.
        @param depositNonce ID of deposited generated by origin Bridge contract.
        @param data Data originally provided when deposit was made.
        @notice Proposal must have Passed status.
        @notice Hash of {data} must equal proposal's {dataHash}.
        @notice Emits {ProposalEvent} event with status {Executed}.
     */
    function executeProposal(uint8 chainID, uint64 depositNonce, bytes calldata data, bytes32 resourceID) external onlyRelayers whenNotPaused {
        address handler = _resourceIDToHandlerAddress[resourceID];
        uint72 nonceAndID = (uint72(depositNonce) << 8) | uint72(chainID);
        bytes32 dataHash = keccak256(abi.encodePacked(handler, data));
        Proposal storage proposal = _proposals[nonceAndID][dataHash];

        require(proposal._status != ProposalStatus.Inactive, "proposal is not active");
        require(proposal._status == ProposalStatus.Passed, "proposal already transferred");
        require(dataHash == proposal._dataHash, "data doesn't match datahash");

        proposal._status = ProposalStatus.Executed;

        IDepositExecute depositHandler = IDepositExecute(_resourceIDToHandlerAddress[proposal._resourceID]);
        depositHandler.executeProposal(proposal._resourceID, data);

        emit ProposalEvent(chainID, depositNonce, proposal._status, proposal._resourceID, proposal._dataHash);
    }

    /**
        @notice Transfers eth in the contract to the specified addresses. The parameters addrs and amounts are mapped 1-1.
        This means that the address at index 0 for addrs will receive the amount (in WEI) from amounts at index 0.
        @param addrs Array of addresses to transfer {amounts} to.
        @param amounts Array of amonuts to transfer to {addrs}.
     */
    function transferFunds(address payable[] calldata addrs, uint[] calldata amounts) external onlyAdmin {
        for (uint i = 0; i < addrs.length; i++) {
            addrs[i].transfer(amounts[i]);
        }
    }

}

Contract Bytecode

Bytecode

0x60806040523480156200001157600080fd5b5060405162004d8938038062004d898339818101604052810190620000379190620004bc565b60008060006101000a81548160ff02191690831515021790555084600260006101000a81548160ff021916908360ff160217905550826003819055508160068190555080600781905550620000966000801b336200013460201b60201c565b620000c0604051620000a89062000601565b60405180910390206000801b6200014a60201b60201c565b60005b8451811015620001285762000108604051620000df9062000601565b6040518091039020868381518110620000f457fe5b60200260200101516200016960201b60201c565b6004600081548092919060010191905055508080600101915050620000c3565b50505050505062000746565b620001468282620001f860201b60201c565b5050565b8060016000848152602001908152602001600020600201819055505050565b620001a06001600084815260200190815260200160002060020154620001946200029c60201b60201c565b620002a460201b60201c565b620001e2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620001d99062000618565b60405180910390fd5b620001f48282620001f860201b60201c565b5050565b620002278160016000858152602001908152602001600020600001620002dd60201b6200285b1790919060201c565b1562000298576200023d6200029c60201b60201c565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b600033905090565b6000620002d582600160008681526020019081526020016000206000016200031560201b620027601790919060201c565b905092915050565b60006200030d836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6200034d60201b60201c565b905092915050565b600062000345836000018373ffffffffffffffffffffffffffffffffffffffff1660001b620003c760201b60201c565b905092915050565b6000620003618383620003c760201b60201c565b620003bc578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050620003c1565b600090505b92915050565b600080836001016000848152602001908152602001600020541415905092915050565b600081519050620003fb81620006f8565b92915050565b600082601f8301126200041357600080fd5b81516200042a620004248262000668565b6200063a565b915081818352602084019350602081019050838560208402820111156200045057600080fd5b60005b83811015620004845781620004698882620003ea565b84526020840193506020830192505060018101905062000453565b5050505092915050565b6000815190506200049f8162000712565b92915050565b600081519050620004b6816200072c565b92915050565b600080600080600060a08688031215620004d557600080fd5b6000620004e588828901620004a5565b955050602086015167ffffffffffffffff8111156200050357600080fd5b620005118882890162000401565b945050604062000524888289016200048e565b935050606062000537888289016200048e565b92505060806200054a888289016200048e565b9150509295509295909350565b600062000566602f8362000691565b91507f416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e60008301527f2061646d696e20746f206772616e7400000000000000000000000000000000006020830152604082019050919050565b6000620005ce600c83620006a2565b91507f52454c415945525f524f4c4500000000000000000000000000000000000000006000830152600c82019050919050565b60006200060e82620005bf565b9150819050919050565b60006020820190508181036000830152620006338162000557565b9050919050565b6000604051905081810181811067ffffffffffffffff821117156200065e57600080fd5b8060405250919050565b600067ffffffffffffffff8211156200068057600080fd5b602082029050602081019050919050565b600082825260208201905092915050565b600081905092915050565b6000620006ba82620006c1565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b6200070381620006ad565b81146200070f57600080fd5b50565b6200071d81620006e1565b81146200072957600080fd5b50565b6200073781620006eb565b81146200074357600080fd5b50565b61463380620007566000396000f3fe6080604052600436106102305760003560e01c806384db809f1161012e578063beab7131116100ab578063cdb0f73a1161006f578063cdb0f73a14610877578063d547741f146108a0578063d7a9cd79146108c9578063e8437ee7146108f4578063ffaac0eb1461091d57610230565b8063beab713114610790578063c5b37c22146107bb578063c5ec8970146107e6578063ca15c87314610811578063cb10f2151461084e57610230565b8063926d7d7f116100f2578063926d7d7f146106a95780639d5773e0146106d45780639d82dd63146106ff578063a217fddf14610728578063a9cf69fa1461075357610230565b806384db809f146105a05780638c0c2631146105dd5780639010d07c1461060657806391c404ac1461064357806391d148541461066c57610230565b80634b0b919d116101bc5780635e1fab0f116101805780635e1fab0f146104cf578063780cf004146104f85780637febe63f14610521578063802aabe81461055e57806380ae1c281461058957610230565b80634b0b919d146103c15780634e056005146103fe5780635059871914610427578063541d5548146104675780635c975abb146104a457610230565b80632f2ff15d116102035780632f2ff15d146102e057806336568abe146103095780633ee7094a146103325780634454b20d1461036f5780634603ae381461039857610230565b806305e2ca171461023557806317f03ce5146102515780631ff013f11461027a578063248a9ca3146102a3575b600080fd5b61024f600480360381019061024a9190613229565b610934565b005b34801561025d57600080fd5b5061027860048036038101906102739190613295565b610b91565b005b34801561028657600080fd5b506102a1600480360381019061029c91906132e4565b610d3e565b005b3480156102af57600080fd5b506102ca60048036038101906102c5919061306f565b6114bf565b6040516102d79190613df0565b60405180910390f35b3480156102ec57600080fd5b5061030760048036038101906103029190613098565b6114df565b005b34801561031557600080fd5b50610330600480360381019061032b9190613098565b611553565b005b34801561033e57600080fd5b5061035960048036038101906103549190613139565b6115d6565b6040516103669190613f75565b60405180910390f35b34801561037b57600080fd5b5061039660048036038101906103919190613347565b611693565b005b3480156103a457600080fd5b506103bf60048036038101906103ba9190612ffa565b6119d4565b005b3480156103cd57600080fd5b506103e860048036038101906103e39190613200565b611a7a565b6040516103f591906142d6565b60405180910390f35b34801561040a57600080fd5b5061042560048036038101906104209190613110565b611aa1565b005b34801561043357600080fd5b5061044e60048036038101906104499190613175565b611ae0565b60405161045e9493929190613ea2565b60405180910390f35b34801561047357600080fd5b5061048e60048036038101906104899190612e43565b611b2a565b60405161049b9190613dd5565b60405180910390f35b3480156104b057600080fd5b506104b9611b50565b6040516104c69190613dd5565b60405180910390f35b3480156104db57600080fd5b506104f660048036038101906104f19190612e43565b611b66565b005b34801561050457600080fd5b5061051f600480360381019061051a9190612ed1565b611b8b565b005b34801561052d57600080fd5b50610548600480360381019061054391906131b1565b611c0e565b6040516105559190613dd5565b60405180910390f35b34801561056a57600080fd5b50610573611c4a565b60405161058091906142bb565b60405180910390f35b34801561059557600080fd5b5061059e611c50565b005b3480156105ac57600080fd5b506105c760048036038101906105c2919061306f565b611c62565b6040516105d49190613d68565b60405180910390f35b3480156105e957600080fd5b5061060460048036038101906105ff9190612e95565b611c95565b005b34801561061257600080fd5b5061062d600480360381019061062891906130d4565b611d12565b60405161063a9190613d68565b60405180910390f35b34801561064f57600080fd5b5061066a60048036038101906106659190613110565b611d44565b005b34801561067857600080fd5b50610693600480360381019061068e9190613098565b611d9b565b6040516106a09190613dd5565b60405180910390f35b3480156106b557600080fd5b506106be611dcd565b6040516106cb9190613df0565b60405180910390f35b3480156106e057600080fd5b506106e9611de4565b6040516106f691906142bb565b60405180910390f35b34801561070b57600080fd5b5061072660048036038101906107219190612e43565b611dea565b005b34801561073457600080fd5b5061073d611ec4565b60405161074a9190613df0565b60405180910390f35b34801561075f57600080fd5b5061077a60048036038101906107759190613295565b611ecb565b6040516107879190614299565b60405180910390f35b34801561079c57600080fd5b506107a56120ac565b6040516107b291906142f1565b60405180910390f35b3480156107c757600080fd5b506107d06120bf565b6040516107dd91906142bb565b60405180910390f35b3480156107f257600080fd5b506107fb6120c5565b60405161080891906142bb565b60405180910390f35b34801561081d57600080fd5b506108386004803603810190610833919061306f565b6120cb565b60405161084591906142bb565b60405180910390f35b34801561085a57600080fd5b5061087560048036038101906108709190612f34565b6120f2565b005b34801561088357600080fd5b5061089e60048036038101906108999190612e43565b6121c4565b005b3480156108ac57600080fd5b506108c760048036038101906108c29190613098565b61229e565b005b3480156108d557600080fd5b506108de612312565b6040516108eb91906142bb565b60405180910390f35b34801561090057600080fd5b5061091b60048036038101906109169190612f83565b612318565b005b34801561092957600080fd5b506109326123f0565b005b61093c612402565b6006543414610980576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610977906140b9565b60405180910390fd5b60006009600085815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610a28576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a1f90614119565b60405180910390fd5b6000600860008760ff1660ff168152602001908152602001600020600081819054906101000a900467ffffffffffffffff1660010191906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905590508383600a60008467ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060008960ff1660ff1681526020019081526020016000209190610ad1929190612b04565b5060008290508073ffffffffffffffffffffffffffffffffffffffff166338995da9878985338a8a6040518763ffffffff1660e01b8152600401610b1a96959493929190613f19565b600060405180830381600087803b158015610b3457600080fd5b505af1158015610b48573d6000803e3d6000fd5b505050508167ffffffffffffffff16868860ff167fdbb69440df8433824a026ef190652f29929eb64b4d1d5d2a69be8afe3e6eaed860405160405180910390a450505050505050565b610b99612453565b60008360ff1660088467ffffffffffffffff1668ffffffffffffffffff16901b1790506000600b60008368ffffffffffffffffff1668ffffffffffffffffff16815260200190815260200160002060008481526020019081526020016000209050600480811115610c0657fe5b8160040160009054906101000a900460ff166004811115610c2357fe5b1415610c64576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c5b906140f9565b60405180910390fd5b600754610c754383600501546124c5565b11610cb5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cac90614159565b60405180910390fd5b60048160040160006101000a81548160ff02191690836004811115610cd657fe5b0217905550600480811115610ce757fe5b8467ffffffffffffffff168660ff167f803c5a12f6bde629cea32e63d4b92d1b560816a6fb72e939d3c89e1cab65041784600001548560010154604051610d2f929190613e79565b60405180910390a45050505050565b610d4661250f565b610d4e612402565b60008460ff1660088567ffffffffffffffff1668ffffffffffffffffff16901b1790506000600b60008368ffffffffffffffffff1668ffffffffffffffffff16815260200190815260200160002060008481526020019081526020016000209050600073ffffffffffffffffffffffffffffffffffffffff166009600086815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610e52576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e4990614259565b60405180910390fd5b60018160040160009054906101000a900460ff166004811115610e7157fe5b1115610eb2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ea9906141b9565b60405180910390fd5b600c60008368ffffffffffffffffff1668ffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615610f77576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f6e90614059565b60405180910390fd5b60008160040160009054906101000a900460ff166004811115610f9657fe5b14156111b657600560008154600101919050819055506040518060c001604052808581526020018481526020016001604051908082528060200260200182016040528015610ff35781602001602082028036833780820191505090505b50815260200160006040519080825280602002602001820160405280156110295781602001602082028036833780820191505090505b5081526020016001600481111561103c57fe5b815260200143815250600b60008468ffffffffffffffffff1668ffffffffffffffffff1681526020019081526020016000206000858152602001908152602001600020600082015181600001556020820151816001015560408201518160020190805190602001906110af929190612b84565b5060608201518160030190805190602001906110cc929190612b84565b5060808201518160040160006101000a81548160ff021916908360048111156110f157fe5b021790555060a08201518160050155905050338160020160008154811061111457fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600481111561116957fe5b8567ffffffffffffffff168760ff167f803c5a12f6bde629cea32e63d4b92d1b560816a6fb72e939d3c89e1cab65041787876040516111a9929190613e79565b60405180910390a46112f9565b6007546111c74383600501546124c5565b111561124c5760048160040160006101000a81548160ff021916908360048111156111ee57fe5b02179055506004808111156111ff57fe5b8567ffffffffffffffff168760ff167f803c5a12f6bde629cea32e63d4b92d1b560816a6fb72e939d3c89e1cab650417878760405161123f929190613e79565b60405180910390a46112f8565b80600101548314611292576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161128990614239565b60405180910390fd5b80600201339080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b5b60048081111561130557fe5b8160040160009054906101000a900460ff16600481111561132257fe5b146114b7576001600c60008468ffffffffffffffffff1668ffffffffffffffffff168152602001908152602001600020600085815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508060040160009054906101000a900460ff1660048111156113d457fe5b8567ffffffffffffffff168760ff167f25f8daaa4635a7729927ba3f5b3d59cc3320aca7c32c9db4e7ca7b9574343640876040516114129190613df0565b60405180910390a460016003541115806114355750600354816002018054905010155b156114b65760028160040160006101000a81548160ff0219169083600481111561145b57fe5b02179055506002600481111561146d57fe5b8567ffffffffffffffff168760ff167f803c5a12f6bde629cea32e63d4b92d1b560816a6fb72e939d3c89e1cab65041787876040516114ad929190613e79565b60405180910390a45b5b505050505050565b600060016000838152602001908152602001600020600201549050919050565b611506600160008481526020019081526020016000206002015461150161256d565b611d9b565b611545576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161153c90614039565b60405180910390fd5b61154f8282612575565b5050565b61155b61256d565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146115c8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115bf90614279565b60405180910390fd5b6115d28282612609565b5050565b600a602052816000526040600020602052806000526040600020600091509150508054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561168b5780601f106116605761010080835404028352916020019161168b565b820191906000526020600020905b81548152906001019060200180831161166e57829003601f168201915b505050505081565b61169b61250f565b6116a3612402565b60006009600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008660ff1660088767ffffffffffffffff1668ffffffffffffffffff16901b179050600082868660405160200161171593929190613d29565b6040516020818303038152906040528051906020012090506000600b60008468ffffffffffffffffff1668ffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002090506000600481111561177857fe5b8160040160009054906101000a900460ff16600481111561179557fe5b14156117d6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117cd90613fd9565b60405180910390fd5b600260048111156117e357fe5b8160040160009054906101000a900460ff16600481111561180057fe5b14611840576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161183790613fb9565b60405180910390fd5b80600101548214611886576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161187d906140d9565b60405180910390fd5b60038160040160006101000a81548160ff021916908360048111156118a757fe5b02179055506000600960008360000154815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff1663e248cff283600001548a8a6040518463ffffffff1660e01b815260040161192993929190613ee7565b600060405180830381600087803b15801561194357600080fd5b505af1158015611957573d6000803e3d6000fd5b505050508160040160009054906101000a900460ff16600481111561197857fe5b8967ffffffffffffffff168b60ff167f803c5a12f6bde629cea32e63d4b92d1b560816a6fb72e939d3c89e1cab650417856000015486600101546040516119c0929190613e79565b60405180910390a450505050505050505050565b6119dc61269d565b60008090505b84849050811015611a73578484828181106119f957fe5b9050602002016020810190611a0e9190612e6c565b73ffffffffffffffffffffffffffffffffffffffff166108fc848484818110611a3357fe5b905060200201359081150290604051600060405180830381858888f19350505050158015611a65573d6000803e3d6000fd5b5080806001019150506119e2565b5050505050565b60086020528060005260406000206000915054906101000a900467ffffffffffffffff1681565b611aa961269d565b80600381905550807fa20d6b84cd798a24038be305eff8a45ca82ef54a2aa2082005d8e14c0a4746c860405160405180910390a250565b600b602052816000526040600020602052806000526040600020600091509150508060000154908060010154908060040160009054906101000a900460ff16908060050154905084565b6000611b49604051611b3b90613d53565b604051809103902083611d9b565b9050919050565b60008060009054906101000a900460ff16905090565b611b6e61269d565b611b7b6000801b826114df565b611b886000801b33611553565b50565b611b9361269d565b60008490508073ffffffffffffffffffffffffffffffffffffffff1663d9caed128585856040518463ffffffff1660e01b8152600401611bd593929190613d9e565b600060405180830381600087803b158015611bef57600080fd5b505af1158015611c03573d6000803e3d6000fd5b505050505050505050565b600c602052826000526040600020602052816000526040600020602052806000526040600020600092509250509054906101000a900460ff1681565b60045481565b611c5861269d565b611c606126eb565b565b60096020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b611c9d61269d565b60008290508073ffffffffffffffffffffffffffffffffffffffff166307b7ed99836040518263ffffffff1660e01b8152600401611cdb9190613d68565b600060405180830381600087803b158015611cf557600080fd5b505af1158015611d09573d6000803e3d6000fd5b50505050505050565b6000611d3c826001600086815260200190815260200160002060000161274690919063ffffffff16565b905092915050565b611d4c61269d565b806006541415611d91576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d8890614219565b60405180910390fd5b8060068190555050565b6000611dc5826001600086815260200190815260200160002060000161276090919063ffffffff16565b905092915050565b604051611dd990613d53565b604051809103902081565b60055481565b611df261269d565b611e0f604051611e0190613d53565b604051809103902082611d9b565b611e4e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e4590614099565b60405180910390fd5b611e6b604051611e5d90613d53565b60405180910390208261229e565b8073ffffffffffffffffffffffffffffffffffffffff167f10e1f7ce9fd7d1b90a66d13a2ab3cb8dd7f29f3f8d520b143b063ccfbab6906b60405160405180910390a26004600081548092919060019003919050555050565b6000801b81565b611ed3612c0e565b60008460ff1660088567ffffffffffffffff1668ffffffffffffffffff16901b179050600b60008268ffffffffffffffffff1668ffffffffffffffffff16815260200190815260200160002060008481526020019081526020016000206040518060c0016040529081600082015481526020016001820154815260200160028201805480602002602001604051908101604052809291908181526020018280548015611fd457602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611f8a575b505050505081526020016003820180548060200260200160405190810160405280929190818152602001828054801561206257602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612018575b505050505081526020016004820160009054906101000a900460ff16600481111561208957fe5b600481111561209457fe5b81526020016005820154815250509150509392505050565b600260009054906101000a900460ff1681565b60065481565b60075481565b60006120eb60016000848152602001908152602001600020600001612790565b9050919050565b6120fa61269d565b826009600084815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008390508073ffffffffffffffffffffffffffffffffffffffff1663b8fa373684846040518363ffffffff1660e01b815260040161218c929190613e0b565b600060405180830381600087803b1580156121a657600080fd5b505af11580156121ba573d6000803e3d6000fd5b5050505050505050565b6121cc61269d565b6121e96040516121db90613d53565b604051809103902082611d9b565b15612229576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161222090614199565b60405180910390fd5b61224660405161223890613d53565b6040518091039020826114df565b8073ffffffffffffffffffffffffffffffffffffffff167f03580ee9f53a62b7cb409a2cb56f9be87747dd15017afc5cef6eef321e4fb2c560405160405180910390a260046000815480929190600101919050555050565b6122c560016000848152602001908152602001600020600201546122c061256d565b611d9b565b612304576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122fb90614139565b60405180910390fd5b61230e8282612609565b5050565b60035481565b61232061269d565b846009600086815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008590508073ffffffffffffffffffffffffffffffffffffffff1663bba8185a868686866040518563ffffffff1660e01b81526004016123b69493929190613e34565b600060405180830381600087803b1580156123d057600080fd5b505af11580156123e4573d6000803e3d6000fd5b50505050505050505050565b6123f861269d565b6124006127a5565b565b6000809054906101000a900460ff1615612451576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161244890614179565b60405180910390fd5b565b6124606000801b33611d9b565b80612484575061248360405161247590613d53565b604051809103902033611d9b565b5b6124c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124ba90614019565b60405180910390fd5b565b600061250783836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612800565b905092915050565b61252c60405161251e90613d53565b604051809103902033611d9b565b61256b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612562906141d9565b60405180910390fd5b565b600033905090565b61259d816001600085815260200190815260200160002060000161285b90919063ffffffff16565b15612605576125aa61256d565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b612631816001600085815260200190815260200160002060000161288b90919063ffffffff16565b156126995761263e61256d565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45b5050565b6126aa6000801b33611d9b565b6126e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126e0906141f9565b60405180910390fd5b565b6126f3612402565b60016000806101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2583360405161273c9190613d83565b60405180910390a1565b600061275583600001836128bb565b60001c905092915050565b6000612788836000018373ffffffffffffffffffffffffffffffffffffffff1660001b612928565b905092915050565b600061279e8260000161294b565b9050919050565b6127ad61295c565b60008060006101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336040516127f69190613d83565b60405180910390a1565b6000838311158290612848576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161283f9190613f97565b60405180910390fd5b5060008385039050809150509392505050565b6000612883836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6129ac565b905092915050565b60006128b3836000018373ffffffffffffffffffffffffffffffffffffffff1660001b612a1c565b905092915050565b600081836000018054905011612906576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128fd90613ff9565b60405180910390fd5b82600001828154811061291557fe5b9060005260206000200154905092915050565b600080836001016000848152602001908152602001600020541415905092915050565b600081600001805490509050919050565b6000809054906101000a900460ff166129aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129a190614079565b60405180910390fd5b565b60006129b88383612928565b612a11578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050612a16565b600090505b92915050565b60008083600101600084815260200190815260200160002054905060008114612af85760006001820390506000600186600001805490500390506000866000018281548110612a6757fe5b9060005260206000200154905080876000018481548110612a8457fe5b9060005260206000200181905550600183018760010160008381526020019081526020016000208190555086600001805480612abc57fe5b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050612afe565b60009150505b92915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10612b4557803560ff1916838001178555612b73565b82800160010185558215612b73579182015b82811115612b72578235825591602001919060010190612b57565b5b509050612b809190612c55565b5090565b828054828255906000526020600020908101928215612bfd579160200282015b82811115612bfc5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555091602001919060010190612ba4565b5b509050612c0a9190612c7a565b5090565b6040518060c001604052806000801916815260200160008019168152602001606081526020016060815260200160006004811115612c4857fe5b8152602001600081525090565b612c7791905b80821115612c73576000816000905550600101612c5b565b5090565b90565b612cba91905b80821115612cb657600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600101612c80565b5090565b90565b600081359050612ccc81614545565b92915050565b600081359050612ce18161455c565b92915050565b60008083601f840112612cf957600080fd5b8235905067ffffffffffffffff811115612d1257600080fd5b602083019150836020820283011115612d2a57600080fd5b9250929050565b60008083601f840112612d4357600080fd5b8235905067ffffffffffffffff811115612d5c57600080fd5b602083019150836020820283011115612d7457600080fd5b9250929050565b600081359050612d8a81614573565b92915050565b600081359050612d9f8161458a565b92915050565b60008083601f840112612db757600080fd5b8235905067ffffffffffffffff811115612dd057600080fd5b602083019150836001820283011115612de857600080fd5b9250929050565b600081359050612dfe816145a1565b92915050565b600081359050612e13816145b8565b92915050565b600081359050612e28816145cf565b92915050565b600081359050612e3d816145e6565b92915050565b600060208284031215612e5557600080fd5b6000612e6384828501612cbd565b91505092915050565b600060208284031215612e7e57600080fd5b6000612e8c84828501612cd2565b91505092915050565b60008060408385031215612ea857600080fd5b6000612eb685828601612cbd565b9250506020612ec785828601612cbd565b9150509250929050565b60008060008060808587031215612ee757600080fd5b6000612ef587828801612cbd565b9450506020612f0687828801612cbd565b9350506040612f1787828801612cbd565b9250506060612f2887828801612def565b91505092959194509250565b600080600060608486031215612f4957600080fd5b6000612f5786828701612cbd565b9350506020612f6886828701612d7b565b9250506040612f7986828701612cbd565b9150509250925092565b600080600080600060a08688031215612f9b57600080fd5b6000612fa988828901612cbd565b9550506020612fba88828901612d7b565b9450506040612fcb88828901612cbd565b9350506060612fdc88828901612d90565b9250506080612fed88828901612d90565b9150509295509295909350565b6000806000806040858703121561301057600080fd5b600085013567ffffffffffffffff81111561302a57600080fd5b61303687828801612ce7565b9450945050602085013567ffffffffffffffff81111561305557600080fd5b61306187828801612d31565b925092505092959194509250565b60006020828403121561308157600080fd5b600061308f84828501612d7b565b91505092915050565b600080604083850312156130ab57600080fd5b60006130b985828601612d7b565b92505060206130ca85828601612cbd565b9150509250929050565b600080604083850312156130e757600080fd5b60006130f585828601612d7b565b925050602061310685828601612def565b9150509250929050565b60006020828403121561312257600080fd5b600061313084828501612def565b91505092915050565b6000806040838503121561314c57600080fd5b600061315a85828601612e04565b925050602061316b85828601612e2e565b9150509250929050565b6000806040838503121561318857600080fd5b600061319685828601612e19565b92505060206131a785828601612d7b565b9150509250929050565b6000806000606084860312156131c657600080fd5b60006131d486828701612e19565b93505060206131e586828701612d7b565b92505060406131f686828701612cbd565b9150509250925092565b60006020828403121561321257600080fd5b600061322084828501612e2e565b91505092915050565b6000806000806060858703121561323f57600080fd5b600061324d87828801612e2e565b945050602061325e87828801612d7b565b935050604085013567ffffffffffffffff81111561327b57600080fd5b61328787828801612da5565b925092505092959194509250565b6000806000606084860312156132aa57600080fd5b60006132b886828701612e2e565b93505060206132c986828701612e04565b92505060406132da86828701612d7b565b9150509250925092565b600080600080608085870312156132fa57600080fd5b600061330887828801612e2e565b945050602061331987828801612e04565b935050604061332a87828801612d7b565b925050606061333b87828801612d7b565b91505092959194509250565b60008060008060006080868803121561335f57600080fd5b600061336d88828901612e2e565b955050602061337e88828901612e04565b945050604086013567ffffffffffffffff81111561339b57600080fd5b6133a788828901612da5565b935093505060606133ba88828901612d7b565b9150509295509295909350565b60006133d383836133ee565b60208301905092915050565b6133e88161446c565b82525050565b6133f781614393565b82525050565b61340681614393565b82525050565b61341d61341882614393565b6144f6565b82525050565b600061342e8261431c565b613438818561434a565b93506134438361430c565b8060005b8381101561347457815161345b88826133c7565b97506134668361433d565b925050600181019050613447565b5085935050505092915050565b61348a816143b7565b82525050565b613499816143c3565b82525050565b6134a8816143c3565b82525050565b6134b7816143cd565b82525050565b60006134c9838561435b565b93506134d68385846144b4565b6134df8361451a565b840190509392505050565b60006134f6838561436c565b93506135038385846144b4565b82840190509392505050565b600061351a82614327565b613524818561435b565b93506135348185602086016144c3565b61353d8161451a565b840191505092915050565b6135518161447e565b82525050565b6135608161447e565b82525050565b600061357182614332565b61357b8185614377565b935061358b8185602086016144c3565b6135948161451a565b840191505092915050565b60006135ac601c83614377565b91507f70726f706f73616c20616c7265616479207472616e73666572726564000000006000830152602082019050919050565b60006135ec601683614377565b91507f70726f706f73616c206973206e6f7420616374697665000000000000000000006000830152602082019050919050565b600061362c602283614377565b91507f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e60008301527f64730000000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000613692601e83614377565b91507f73656e646572206973206e6f742072656c61796572206f722061646d696e00006000830152602082019050919050565b60006136d2602f83614377565b91507f416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e60008301527f2061646d696e20746f206772616e7400000000000000000000000000000000006020830152604082019050919050565b6000613738601583614377565b91507f72656c6179657220616c726561647920766f74656400000000000000000000006000830152602082019050919050565b6000613778601483614377565b91507f5061757361626c653a206e6f74207061757365640000000000000000000000006000830152602082019050919050565b60006137b8601f83614377565b91507f6164647220646f65736e277420686176652072656c6179657220726f6c6521006000830152602082019050919050565b60006137f8601683614377565b91507f496e636f72726563742066656520737570706c696564000000000000000000006000830152602082019050919050565b6000613838601b83614377565b91507f6461746120646f65736e2774206d6174636820646174616861736800000000006000830152602082019050919050565b6000613878601a83614377565b91507f50726f706f73616c20616c72656164792063616e63656c6c65640000000000006000830152602082019050919050565b60006138b8602083614377565b91507f7265736f757263654944206e6f74206d617070656420746f2068616e646c65726000830152602082019050919050565b60006138f8603083614377565b91507f416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e60008301527f2061646d696e20746f207265766f6b65000000000000000000000000000000006020830152604082019050919050565b600061395e602083614377565b91507f50726f706f73616c206e6f7420617420657870697279207468726573686f6c646000830152602082019050919050565b600061399e601083614377565b91507f5061757361626c653a20706175736564000000000000000000000000000000006000830152602082019050919050565b60006139de601e83614377565b91507f6164647220616c7265616479206861732072656c6179657220726f6c652100006000830152602082019050919050565b6000613a1e602a83614377565b91507f70726f706f73616c20616c7265616479207061737365642f657865637574656460008301527f2f63616e63656c6c6564000000000000000000000000000000000000000000006020830152604082019050919050565b6000613a84602083614377565b91507f73656e64657220646f65736e277420686176652072656c6179657220726f6c656000830152602082019050919050565b6000613ac4601e83614377565b91507f73656e64657220646f65736e277420686176652061646d696e20726f6c6500006000830152602082019050919050565b6000613b04601f83614377565b91507f43757272656e742066656520697320657175616c20746f206e657720666565006000830152602082019050919050565b6000613b44600c83614388565b91507f52454c415945525f524f4c4500000000000000000000000000000000000000006000830152600c82019050919050565b6000613b84601183614377565b91507f6461746168617368206d69736d617463680000000000000000000000000000006000830152602082019050919050565b6000613bc4601983614377565b91507f6e6f2068616e646c657220666f72207265736f757263654944000000000000006000830152602082019050919050565b6000613c04602f83614377565b91507f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560008301527f20726f6c657320666f722073656c6600000000000000000000000000000000006020830152604082019050919050565b600060c083016000830151613c756000860182613490565b506020830151613c886020860182613490565b5060408301518482036040860152613ca08282613423565b91505060608301518482036060860152613cba8282613423565b9150506080830151613ccf6080860182613548565b5060a0830151613ce260a0860182613ced565b508091505092915050565b613cf68161442c565b82525050565b613d058161442c565b82525050565b613d1481614436565b82525050565b613d238161445f565b82525050565b6000613d35828661340c565b601482019150613d468284866134ea565b9150819050949350505050565b6000613d5e82613b37565b9150819050919050565b6000602082019050613d7d60008301846133fd565b92915050565b6000602082019050613d9860008301846133df565b92915050565b6000606082019050613db360008301866133fd565b613dc060208301856133fd565b613dcd6040830184613cfc565b949350505050565b6000602082019050613dea6000830184613481565b92915050565b6000602082019050613e05600083018461349f565b92915050565b6000604082019050613e20600083018561349f565b613e2d60208301846133fd565b9392505050565b6000608082019050613e49600083018761349f565b613e5660208301866133fd565b613e6360408301856134ae565b613e7060608301846134ae565b95945050505050565b6000604082019050613e8e600083018561349f565b613e9b602083018461349f565b9392505050565b6000608082019050613eb7600083018761349f565b613ec4602083018661349f565b613ed16040830185613557565b613ede6060830184613cfc565b95945050505050565b6000604082019050613efc600083018661349f565b8181036020830152613f0f8184866134bd565b9050949350505050565b600060a082019050613f2e600083018961349f565b613f3b6020830188613d1a565b613f486040830187613d0b565b613f5560608301866133df565b8181036080830152613f688184866134bd565b9050979650505050505050565b60006020820190508181036000830152613f8f818461350f565b905092915050565b60006020820190508181036000830152613fb18184613566565b905092915050565b60006020820190508181036000830152613fd28161359f565b9050919050565b60006020820190508181036000830152613ff2816135df565b9050919050565b600060208201905081810360008301526140128161361f565b9050919050565b6000602082019050818103600083015261403281613685565b9050919050565b60006020820190508181036000830152614052816136c5565b9050919050565b600060208201905081810360008301526140728161372b565b9050919050565b600060208201905081810360008301526140928161376b565b9050919050565b600060208201905081810360008301526140b2816137ab565b9050919050565b600060208201905081810360008301526140d2816137eb565b9050919050565b600060208201905081810360008301526140f28161382b565b9050919050565b600060208201905081810360008301526141128161386b565b9050919050565b60006020820190508181036000830152614132816138ab565b9050919050565b60006020820190508181036000830152614152816138eb565b9050919050565b6000602082019050818103600083015261417281613951565b9050919050565b6000602082019050818103600083015261419281613991565b9050919050565b600060208201905081810360008301526141b2816139d1565b9050919050565b600060208201905081810360008301526141d281613a11565b9050919050565b600060208201905081810360008301526141f281613a77565b9050919050565b6000602082019050818103600083015261421281613ab7565b9050919050565b6000602082019050818103600083015261423281613af7565b9050919050565b6000602082019050818103600083015261425281613b77565b9050919050565b6000602082019050818103600083015261427281613bb7565b9050919050565b6000602082019050818103600083015261429281613bf7565b9050919050565b600060208201905081810360008301526142b38184613c5d565b905092915050565b60006020820190506142d06000830184613cfc565b92915050565b60006020820190506142eb6000830184613d0b565b92915050565b60006020820190506143066000830184613d1a565b92915050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b600061439e8261440c565b9050919050565b60006143b08261440c565b9050919050565b60008115159050919050565b6000819050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b600081905061440782614538565b919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600067ffffffffffffffff82169050919050565b600068ffffffffffffffffff82169050919050565b600060ff82169050919050565b600061447782614490565b9050919050565b6000614489826143f9565b9050919050565b600061449b826144a2565b9050919050565b60006144ad8261440c565b9050919050565b82818337600083830152505050565b60005b838110156144e15780820151818401526020810190506144c6565b838111156144f0576000848401525b50505050565b600061450182614508565b9050919050565b60006145138261452b565b9050919050565b6000601f19601f8301169050919050565b60008160601b9050919050565b6005811061454257fe5b50565b61454e81614393565b811461455957600080fd5b50565b614565816143a5565b811461457057600080fd5b50565b61457c816143c3565b811461458757600080fd5b50565b614593816143cd565b811461459e57600080fd5b50565b6145aa8161442c565b81146145b557600080fd5b50565b6145c181614436565b81146145cc57600080fd5b50565b6145d88161444a565b81146145e357600080fd5b50565b6145ef8161445f565b81146145fa57600080fd5b5056fea2646970667358221220b27b3c33d92631bd006c1342adfd7f89f45a528dbb1ea4dc7ed3c444c8199e9f64736f6c63430006040033000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ddd0000000000000000000000000000000000000000000000000000000000000000050000000000000000000000007a27f96736f335a6b1a2582ba325bdbc09394a90000000000000000000000000e167efd9611eafa2512a023e3289effb3d72877b000000000000000000000000d0f2898e49d941d6d479b381d3c8f0bd8d983b4c000000000000000000000000b64b7b92e37d11c098ad4bf21d37fa49c0c0ef450000000000000000000000003394b1f0f2614b87a6a44697236c10eccea51b03