Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
ForeignOmnibridge
Compiler Version
v0.7.5+commit.eb77ed08
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2023-06-02 */ // File: @openzeppelin/contracts/math/SafeMath.sol pragma solidity ^0.7.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @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; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File: contracts/upgradeability/EternalStorage.sol pragma solidity 0.7.5; /** * @title EternalStorage * @dev This contract holds all the necessary state variables to carry out the storage of any contract. */ contract EternalStorage { mapping(bytes32 => uint256) internal uintStorage; mapping(bytes32 => string) internal stringStorage; mapping(bytes32 => address) internal addressStorage; mapping(bytes32 => bytes) internal bytesStorage; mapping(bytes32 => bool) internal boolStorage; mapping(bytes32 => int256) internal intStorage; } // File: contracts/upgradeable_contracts/Initializable.sol pragma solidity 0.7.5; contract Initializable is EternalStorage { bytes32 internal constant INITIALIZED = 0x0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba; // keccak256(abi.encodePacked("isInitialized")) function setInitialize() internal { boolStorage[INITIALIZED] = true; } function isInitialized() public view returns (bool) { return boolStorage[INITIALIZED]; } } // File: contracts/interfaces/IUpgradeabilityOwnerStorage.sol pragma solidity 0.7.5; interface IUpgradeabilityOwnerStorage { function upgradeabilityOwner() external view returns (address); } // File: contracts/upgradeable_contracts/Upgradeable.sol pragma solidity 0.7.5; contract Upgradeable { /** * @dev Throws if called by any account other than the upgradeability owner. */ modifier onlyIfUpgradeabilityOwner() { _onlyIfUpgradeabilityOwner(); _; } /** * @dev Internal function for reducing onlyIfUpgradeabilityOwner modifier bytecode overhead. */ function _onlyIfUpgradeabilityOwner() internal view { require(msg.sender == IUpgradeabilityOwnerStorage(address(this)).upgradeabilityOwner()); } } // File: @openzeppelin/contracts/token/ERC20/IERC20.sol pragma solidity ^0.7.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File: @openzeppelin/contracts/utils/Address.sol pragma solidity ^0.7.0; /** * @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"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); return _functionCallWithValue(target, data, value, errorMessage); } function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) { require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: weiValue }(data); if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol pragma solidity ^0.7.0; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } // File: contracts/upgradeable_contracts/Sacrifice.sol pragma solidity 0.7.5; contract Sacrifice { constructor(address payable _recipient) payable { selfdestruct(_recipient); } } // File: contracts/libraries/AddressHelper.sol pragma solidity 0.7.5; /** * @title AddressHelper * @dev Helper methods for Address type. */ library AddressHelper { /** * @dev Try to send native tokens to the address. If it fails, it will force the transfer by creating a selfdestruct contract * @param _receiver address that will receive the native tokens * @param _value the amount of native tokens to send */ function safeSendValue(address payable _receiver, uint256 _value) internal { if (!(_receiver).send(_value)) { new Sacrifice{ value: _value }(_receiver); } } } // File: contracts/upgradeable_contracts/Claimable.sol pragma solidity 0.7.5; /** * @title Claimable * @dev Implementation of the claiming utils that can be useful for withdrawing accidentally sent tokens that are not used in bridge operations. */ contract Claimable { using SafeERC20 for IERC20; /** * Throws if a given address is equal to address(0) */ modifier validAddress(address _to) { require(_to != address(0)); _; } /** * @dev Withdraws the erc20 tokens or native coins from this contract. * Caller should additionally check that the claimed token is not a part of bridge operations (i.e. that token != erc20token()). * @param _token address of the claimed token or address(0) for native coins. * @param _to address of the tokens/coins receiver. */ function claimValues(address _token, address _to) internal validAddress(_to) { if (_token == address(0)) { claimNativeCoins(_to); } else { claimErc20Tokens(_token, _to); } } /** * @dev Internal function for withdrawing all native coins from the contract. * @param _to address of the coins receiver. */ function claimNativeCoins(address _to) internal { uint256 value = address(this).balance; AddressHelper.safeSendValue(payable(_to), value); } /** * @dev Internal function for withdrawing all tokens of some particular ERC20 contract from this contract. * @param _token address of the claimed ERC20 token. * @param _to address of the tokens receiver. */ function claimErc20Tokens(address _token, address _to) internal { IERC20 token = IERC20(_token); uint256 balance = token.balanceOf(address(this)); token.safeTransfer(_to, balance); } } // File: contracts/upgradeable_contracts/components/bridged/BridgedTokensRegistry.sol pragma solidity 0.7.5; /** * @title BridgedTokensRegistry * @dev Functionality for keeping track of registered bridged token pairs. */ contract BridgedTokensRegistry is EternalStorage { event NewTokenRegistered(address indexed nativeToken, address indexed bridgedToken); /** * @dev Retrieves address of the bridged token contract associated with a specific native token contract on the other side. * @param _nativeToken address of the native token contract on the other side. * @return address of the deployed bridged token contract. */ function bridgedTokenAddress(address _nativeToken) public view returns (address) { return addressStorage[keccak256(abi.encodePacked("homeTokenAddress", _nativeToken))]; } /** * @dev Retrieves address of the native token contract associated with a specific bridged token contract. * @param _bridgedToken address of the created bridged token contract on this side. * @return address of the native token contract on the other side of the bridge. */ function nativeTokenAddress(address _bridgedToken) public view returns (address) { return addressStorage[keccak256(abi.encodePacked("foreignTokenAddress", _bridgedToken))]; } /** * @dev Internal function for updating a pair of addresses for the bridged token. * @param _nativeToken address of the native token contract on the other side. * @param _bridgedToken address of the created bridged token contract on this side. */ function _setTokenAddressPair(address _nativeToken, address _bridgedToken) internal { addressStorage[keccak256(abi.encodePacked("homeTokenAddress", _nativeToken))] = _bridgedToken; addressStorage[keccak256(abi.encodePacked("foreignTokenAddress", _bridgedToken))] = _nativeToken; emit NewTokenRegistered(_nativeToken, _bridgedToken); } } // File: contracts/upgradeable_contracts/components/native/NativeTokensRegistry.sol pragma solidity 0.7.5; /** * @title NativeTokensRegistry * @dev Functionality for keeping track of registered native tokens. */ contract NativeTokensRegistry is EternalStorage { /** * @dev Checks if for a given native token, the deployment of its bridged alternative was already acknowledged. * @param _token address of native token contract. * @return true, if bridged token was already deployed. */ function isBridgedTokenDeployAcknowledged(address _token) public view returns (bool) { return boolStorage[keccak256(abi.encodePacked("ackDeploy", _token))]; } /** * @dev Acknowledges the deployment of bridged token contract on the other side. * @param _token address of native token contract. */ function _ackBridgedTokenDeploy(address _token) internal { if (!boolStorage[keccak256(abi.encodePacked("ackDeploy", _token))]) { boolStorage[keccak256(abi.encodePacked("ackDeploy", _token))] = true; } } } // File: contracts/upgradeable_contracts/components/native/MediatorBalanceStorage.sol pragma solidity 0.7.5; /** * @title MediatorBalanceStorage * @dev Functionality for storing expected mediator balance for native tokens. */ contract MediatorBalanceStorage is EternalStorage { /** * @dev Tells the expected token balance of the contract. * @param _token address of token contract. * @return the current tracked token balance of the contract. */ function mediatorBalance(address _token) public view returns (uint256) { return uintStorage[keccak256(abi.encodePacked("mediatorBalance", _token))]; } /** * @dev Updates expected token balance of the contract. * @param _token address of token contract. * @param _balance the new token balance of the contract. */ function _setMediatorBalance(address _token, uint256 _balance) internal { uintStorage[keccak256(abi.encodePacked("mediatorBalance", _token))] = _balance; } } // File: contracts/upgradeable_contracts/VersionableBridge.sol pragma solidity 0.7.5; interface VersionableBridge { function getBridgeInterfacesVersion() external pure returns ( uint64 major, uint64 minor, uint64 patch ); function getBridgeMode() external pure returns (bytes4); } // File: contracts/upgradeable_contracts/components/common/OmnibridgeInfo.sol pragma solidity 0.7.5; /** * @title OmnibridgeInfo * @dev Functionality for versioning Omnibridge mediator. */ contract OmnibridgeInfo is VersionableBridge { event TokensBridgingInitiated( address indexed token, address indexed sender, uint256 value, bytes32 indexed messageId ); event TokensBridged(address indexed token, address indexed recipient, uint256 value, bytes32 indexed messageId); /** * @dev Tells the bridge interface version that this contract supports. * @return major value of the version * @return minor value of the version * @return patch value of the version */ function getBridgeInterfacesVersion() external pure override returns ( uint64 major, uint64 minor, uint64 patch ) { return (3, 3, 0); } /** * @dev Tells the bridge mode that this contract supports. * @return _data 4 bytes representing the bridge mode */ function getBridgeMode() external pure override returns (bytes4 _data) { return 0xb1516c26; // bytes4(keccak256(abi.encodePacked("multi-erc-to-erc-amb"))) } } // File: contracts/upgradeable_contracts/Ownable.sol pragma solidity 0.7.5; /** * @title Ownable * @dev This contract has an owner address providing basic authorization control */ contract Ownable is EternalStorage { bytes4 internal constant UPGRADEABILITY_OWNER = 0x6fde8202; // upgradeabilityOwner() /** * @dev Event to show ownership has been transferred * @param previousOwner representing the address of the previous owner * @param newOwner representing the address of the new owner */ event OwnershipTransferred(address previousOwner, address newOwner); /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _onlyOwner(); _; } /** * @dev Internal function for reducing onlyOwner modifier bytecode overhead. */ function _onlyOwner() internal view { require(msg.sender == owner()); } /** * @dev Throws if called through proxy by any account other than contract itself or an upgradeability owner. */ modifier onlyRelevantSender() { (bool isProxy, bytes memory returnData) = address(this).staticcall(abi.encodeWithSelector(UPGRADEABILITY_OWNER)); require( !isProxy || // covers usage without calling through storage proxy (returnData.length == 32 && msg.sender == abi.decode(returnData, (address))) || // covers usage through regular proxy calls msg.sender == address(this) // covers calls through upgradeAndCall proxy method ); _; } bytes32 internal constant OWNER = 0x02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0; // keccak256(abi.encodePacked("owner")) /** * @dev Tells the address of the owner * @return the address of the owner */ function owner() public view returns (address) { return addressStorage[OWNER]; } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner the address to transfer ownership to. */ function transferOwnership(address newOwner) external onlyOwner { _setOwner(newOwner); } /** * @dev Sets a new owner address */ function _setOwner(address newOwner) internal { require(newOwner != address(0)); emit OwnershipTransferred(owner(), newOwner); addressStorage[OWNER] = newOwner; } } // File: contracts/upgradeable_contracts/components/common/TokensBridgeLimits.sol pragma solidity 0.7.5; /** * @title TokensBridgeLimits * @dev Functionality for keeping track of bridging limits for multiple tokens. */ contract TokensBridgeLimits is EternalStorage, Ownable { using SafeMath for uint256; // token == 0x00..00 represents default limits (assuming decimals == 18) for all newly created tokens event DailyLimitChanged(address indexed token, uint256 newLimit); event ExecutionDailyLimitChanged(address indexed token, uint256 newLimit); /** * @dev Checks if specified token was already bridged at least once. * @param _token address of the token contract. * @return true, if token address is address(0) or token was already bridged. */ function isTokenRegistered(address _token) public view returns (bool) { return minPerTx(_token) > 0; } /** * @dev Retrieves the total spent amount for particular token during specific day. * @param _token address of the token contract. * @param _day day number for which spent amount if requested. * @return amount of tokens sent through the bridge to the other side. */ function totalSpentPerDay(address _token, uint256 _day) public view returns (uint256) { return uintStorage[keccak256(abi.encodePacked("totalSpentPerDay", _token, _day))]; } /** * @dev Retrieves the total executed amount for particular token during specific day. * @param _token address of the token contract. * @param _day day number for which spent amount if requested. * @return amount of tokens received from the bridge from the other side. */ function totalExecutedPerDay(address _token, uint256 _day) public view returns (uint256) { return uintStorage[keccak256(abi.encodePacked("totalExecutedPerDay", _token, _day))]; } /** * @dev Retrieves current daily limit for a particular token contract. * @param _token address of the token contract. * @return daily limit on tokens that can be sent through the bridge per day. */ function dailyLimit(address _token) public view returns (uint256) { return uintStorage[keccak256(abi.encodePacked("dailyLimit", _token))]; } /** * @dev Retrieves current execution daily limit for a particular token contract. * @param _token address of the token contract. * @return daily limit on tokens that can be received from the bridge on the other side per day. */ function executionDailyLimit(address _token) public view returns (uint256) { return uintStorage[keccak256(abi.encodePacked("executionDailyLimit", _token))]; } /** * @dev Retrieves current maximum amount of tokens per one transfer for a particular token contract. * @param _token address of the token contract. * @return maximum amount on tokens that can be sent through the bridge in one transfer. */ function maxPerTx(address _token) public view returns (uint256) { return uintStorage[keccak256(abi.encodePacked("maxPerTx", _token))]; } /** * @dev Retrieves current maximum execution amount of tokens per one transfer for a particular token contract. * @param _token address of the token contract. * @return maximum amount on tokens that can received from the bridge on the other side in one transaction. */ function executionMaxPerTx(address _token) public view returns (uint256) { return uintStorage[keccak256(abi.encodePacked("executionMaxPerTx", _token))]; } /** * @dev Retrieves current minimum amount of tokens per one transfer for a particular token contract. * @param _token address of the token contract. * @return minimum amount on tokens that can be sent through the bridge in one transfer. */ function minPerTx(address _token) public view returns (uint256) { return uintStorage[keccak256(abi.encodePacked("minPerTx", _token))]; } /** * @dev Checks that bridged amount of tokens conforms to the configured limits. * @param _token address of the token contract. * @param _amount amount of bridge tokens. * @return true, if specified amount can be bridged. */ function withinLimit(address _token, uint256 _amount) public view returns (bool) { uint256 nextLimit = totalSpentPerDay(_token, getCurrentDay()).add(_amount); return dailyLimit(address(0)) > 0 && dailyLimit(_token) >= nextLimit && _amount <= maxPerTx(_token) && _amount >= minPerTx(_token); } /** * @dev Checks that bridged amount of tokens conforms to the configured execution limits. * @param _token address of the token contract. * @param _amount amount of bridge tokens. * @return true, if specified amount can be processed and executed. */ function withinExecutionLimit(address _token, uint256 _amount) public view returns (bool) { uint256 nextLimit = totalExecutedPerDay(_token, getCurrentDay()).add(_amount); return executionDailyLimit(address(0)) > 0 && executionDailyLimit(_token) >= nextLimit && _amount <= executionMaxPerTx(_token); } /** * @dev Returns current day number. * @return day number. */ function getCurrentDay() public view returns (uint256) { // solhint-disable-next-line not-rely-on-time return block.timestamp / 1 days; } /** * @dev Updates daily limit for the particular token. Only owner can call this method. * @param _token address of the token contract, or address(0) for configuring the efault limit. * @param _dailyLimit daily allowed amount of bridged tokens, should be greater than maxPerTx. * 0 value is also allowed, will stop the bridge operations in outgoing direction. */ function setDailyLimit(address _token, uint256 _dailyLimit) external onlyOwner { require(isTokenRegistered(_token)); require(_dailyLimit > maxPerTx(_token) || _dailyLimit == 0); uintStorage[keccak256(abi.encodePacked("dailyLimit", _token))] = _dailyLimit; emit DailyLimitChanged(_token, _dailyLimit); } /** * @dev Updates execution daily limit for the particular token. Only owner can call this method. * @param _token address of the token contract, or address(0) for configuring the default limit. * @param _dailyLimit daily allowed amount of executed tokens, should be greater than executionMaxPerTx. * 0 value is also allowed, will stop the bridge operations in incoming direction. */ function setExecutionDailyLimit(address _token, uint256 _dailyLimit) external onlyOwner { require(isTokenRegistered(_token)); require(_dailyLimit > executionMaxPerTx(_token) || _dailyLimit == 0); uintStorage[keccak256(abi.encodePacked("executionDailyLimit", _token))] = _dailyLimit; emit ExecutionDailyLimitChanged(_token, _dailyLimit); } /** * @dev Updates execution maximum per transaction for the particular token. Only owner can call this method. * @param _token address of the token contract, or address(0) for configuring the default limit. * @param _maxPerTx maximum amount of executed tokens per one transaction, should be less than executionDailyLimit. * 0 value is also allowed, will stop the bridge operations in incoming direction. */ function setExecutionMaxPerTx(address _token, uint256 _maxPerTx) external onlyOwner { require(isTokenRegistered(_token)); require(_maxPerTx == 0 || (_maxPerTx > 0 && _maxPerTx < executionDailyLimit(_token))); uintStorage[keccak256(abi.encodePacked("executionMaxPerTx", _token))] = _maxPerTx; } /** * @dev Updates maximum per transaction for the particular token. Only owner can call this method. * @param _token address of the token contract, or address(0) for configuring the default limit. * @param _maxPerTx maximum amount of tokens per one transaction, should be less than dailyLimit, greater than minPerTx. * 0 value is also allowed, will stop the bridge operations in outgoing direction. */ function setMaxPerTx(address _token, uint256 _maxPerTx) external onlyOwner { require(isTokenRegistered(_token)); require(_maxPerTx == 0 || (_maxPerTx > minPerTx(_token) && _maxPerTx < dailyLimit(_token))); uintStorage[keccak256(abi.encodePacked("maxPerTx", _token))] = _maxPerTx; } /** * @dev Updates minimum per transaction for the particular token. Only owner can call this method. * @param _token address of the token contract, or address(0) for configuring the default limit. * @param _minPerTx minimum amount of tokens per one transaction, should be less than maxPerTx and dailyLimit. */ function setMinPerTx(address _token, uint256 _minPerTx) external onlyOwner { require(isTokenRegistered(_token)); require(_minPerTx > 0 && _minPerTx < dailyLimit(_token) && _minPerTx < maxPerTx(_token)); uintStorage[keccak256(abi.encodePacked("minPerTx", _token))] = _minPerTx; } /** * @dev Retrieves maximum available bridge amount per one transaction taking into account maxPerTx() and dailyLimit() parameters. * @param _token address of the token contract, or address(0) for the default limit. * @return minimum of maxPerTx parameter and remaining daily quota. */ function maxAvailablePerTx(address _token) public view returns (uint256) { uint256 _maxPerTx = maxPerTx(_token); uint256 _dailyLimit = dailyLimit(_token); uint256 _spent = totalSpentPerDay(_token, getCurrentDay()); uint256 _remainingOutOfDaily = _dailyLimit > _spent ? _dailyLimit - _spent : 0; return _maxPerTx < _remainingOutOfDaily ? _maxPerTx : _remainingOutOfDaily; } /** * @dev Internal function for adding spent amount for some token. * @param _token address of the token contract. * @param _day day number, when tokens are processed. * @param _value amount of bridge tokens. */ function addTotalSpentPerDay( address _token, uint256 _day, uint256 _value ) internal { uintStorage[keccak256(abi.encodePacked("totalSpentPerDay", _token, _day))] = totalSpentPerDay(_token, _day).add( _value ); } /** * @dev Internal function for adding executed amount for some token. * @param _token address of the token contract. * @param _day day number, when tokens are processed. * @param _value amount of bridge tokens. */ function addTotalExecutedPerDay( address _token, uint256 _day, uint256 _value ) internal { uintStorage[keccak256(abi.encodePacked("totalExecutedPerDay", _token, _day))] = totalExecutedPerDay( _token, _day ) .add(_value); } /** * @dev Internal function for initializing limits for some token. * @param _token address of the token contract. * @param _limits [ 0 = dailyLimit, 1 = maxPerTx, 2 = minPerTx ]. */ function _setLimits(address _token, uint256[3] memory _limits) internal { require( _limits[2] > 0 && // minPerTx > 0 _limits[1] > _limits[2] && // maxPerTx > minPerTx _limits[0] > _limits[1] // dailyLimit > maxPerTx ); uintStorage[keccak256(abi.encodePacked("dailyLimit", _token))] = _limits[0]; uintStorage[keccak256(abi.encodePacked("maxPerTx", _token))] = _limits[1]; uintStorage[keccak256(abi.encodePacked("minPerTx", _token))] = _limits[2]; emit DailyLimitChanged(_token, _limits[0]); } /** * @dev Internal function for initializing execution limits for some token. * @param _token address of the token contract. * @param _limits [ 0 = executionDailyLimit, 1 = executionMaxPerTx ]. */ function _setExecutionLimits(address _token, uint256[2] memory _limits) internal { require(_limits[1] < _limits[0]); // foreignMaxPerTx < foreignDailyLimit uintStorage[keccak256(abi.encodePacked("executionDailyLimit", _token))] = _limits[0]; uintStorage[keccak256(abi.encodePacked("executionMaxPerTx", _token))] = _limits[1]; emit ExecutionDailyLimitChanged(_token, _limits[0]); } /** * @dev Internal function for initializing limits for some token relative to its decimals parameter. * @param _token address of the token contract. * @param _decimals token decimals parameter. */ function _initializeTokenBridgeLimits(address _token, uint256 _decimals) internal { uint256 factor; if (_decimals < 18) { factor = 10**(18 - _decimals); uint256 _minPerTx = minPerTx(address(0)).div(factor); uint256 _maxPerTx = maxPerTx(address(0)).div(factor); uint256 _dailyLimit = dailyLimit(address(0)).div(factor); uint256 _executionMaxPerTx = executionMaxPerTx(address(0)).div(factor); uint256 _executionDailyLimit = executionDailyLimit(address(0)).div(factor); // such situation can happen when calculated limits relative to the token decimals are too low // e.g. minPerTx(address(0)) == 10 ** 14, _decimals == 3. _minPerTx happens to be 0, which is not allowed. // in this case, limits are raised to the default values if (_minPerTx == 0) { // Numbers 1, 100, 10000 are chosen in a semi-random way, // so that any token with small decimals can still be bridged in some amounts. // It is possible to override limits for the particular token later if needed. _minPerTx = 1; if (_maxPerTx <= _minPerTx) { _maxPerTx = 100; _executionMaxPerTx = 100; if (_dailyLimit <= _maxPerTx || _executionDailyLimit <= _executionMaxPerTx) { _dailyLimit = 10000; _executionDailyLimit = 10000; } } } _setLimits(_token, [_dailyLimit, _maxPerTx, _minPerTx]); _setExecutionLimits(_token, [_executionDailyLimit, _executionMaxPerTx]); } else { factor = 10**(_decimals - 18); _setLimits( _token, [dailyLimit(address(0)).mul(factor), maxPerTx(address(0)).mul(factor), minPerTx(address(0)).mul(factor)] ); _setExecutionLimits( _token, [executionDailyLimit(address(0)).mul(factor), executionMaxPerTx(address(0)).mul(factor)] ); } } } // File: contracts/interfaces/IAMB.sol pragma solidity 0.7.5; interface IAMB { event UserRequestForAffirmation(bytes32 indexed messageId, bytes encodedData); event UserRequestForSignature(bytes32 indexed messageId, bytes encodedData); event AffirmationCompleted( address indexed sender, address indexed executor, bytes32 indexed messageId, bool status ); event RelayedMessage(address indexed sender, address indexed executor, bytes32 indexed messageId, bool status); function messageSender() external view returns (address); function maxGasPerTx() external view returns (uint256); function transactionHash() external view returns (bytes32); function messageId() external view returns (bytes32); function messageSourceChainId() external view returns (bytes32); function messageCallStatus(bytes32 _messageId) external view returns (bool); function failedMessageDataHash(bytes32 _messageId) external view returns (bytes32); function failedMessageReceiver(bytes32 _messageId) external view returns (address); function failedMessageSender(bytes32 _messageId) external view returns (address); function requireToPassMessage( address _contract, bytes calldata _data, uint256 _gas ) external returns (bytes32); function requireToConfirmMessage( address _contract, bytes calldata _data, uint256 _gas ) external returns (bytes32); function sourceChainId() external view returns (uint256); function destinationChainId() external view returns (uint256); } // File: contracts/upgradeable_contracts/BasicAMBMediator.sol pragma solidity 0.7.5; /** * @title BasicAMBMediator * @dev Basic storage and methods needed by mediators to interact with AMB bridge. */ abstract contract BasicAMBMediator is Ownable { bytes32 internal constant BRIDGE_CONTRACT = 0x811bbb11e8899da471f0e69a3ed55090fc90215227fc5fb1cb0d6e962ea7b74f; // keccak256(abi.encodePacked("bridgeContract")) bytes32 internal constant MEDIATOR_CONTRACT = 0x98aa806e31e94a687a31c65769cb99670064dd7f5a87526da075c5fb4eab9880; // keccak256(abi.encodePacked("mediatorContract")) bytes32 internal constant WPLS_CONTRACT = 0x59d6267c963dfa6f508daa0db28ce48957e9ccaf6be68a72221b89800942bdc7; // keccak256(abi.encodePacked("wplsContract")) /** * @dev Throws if caller on the other side is not an associated mediator. */ modifier onlyMediator { _onlyMediator(); _; } /** * @dev Internal function for reducing onlyMediator modifier bytecode overhead. */ function _onlyMediator() internal view { IAMB bridge = bridgeContract(); require(msg.sender == address(bridge)); require(bridge.messageSender() == mediatorContractOnOtherSide()); } /** * @dev Sets the AMB bridge contract address. Only the owner can call this method. * @param _bridgeContract the address of the bridge contract. */ function setBridgeContract(address _bridgeContract) external onlyOwner { _setBridgeContract(_bridgeContract); } /** * @dev Sets the mediator contract address from the other network. Only the owner can call this method. * @param _mediatorContract the address of the mediator contract. */ function setMediatorContractOnOtherSide(address _mediatorContract) external onlyOwner { _setMediatorContractOnOtherSide(_mediatorContract); } /** * @dev Sets the WPLS contract address. Only the owner can call this method. * @param _wplsContract address. */ function setWPLSContract(address _wplsContract) external onlyOwner { _setWPLSContract(_wplsContract); } /** * @dev Get the AMB interface for the bridge contract address * @return AMB interface for the bridge contract address */ function bridgeContract() public view returns (IAMB) { return IAMB(addressStorage[BRIDGE_CONTRACT]); } /** * @dev Tells the mediator contract address from the other network. * @return the address of the mediator contract. */ function mediatorContractOnOtherSide() public view virtual returns (address) { return addressStorage[MEDIATOR_CONTRACT]; } /** * @dev Tells the WPLS contract address. * @return the address of the WPLS contract. */ function wplsContract() public view virtual returns (address) { return addressStorage[WPLS_CONTRACT]; } /** * @dev Stores a valid AMB bridge contract address. * @param _bridgeContract the address of the bridge contract. */ function _setBridgeContract(address _bridgeContract) internal { require(Address.isContract(_bridgeContract)); addressStorage[BRIDGE_CONTRACT] = _bridgeContract; } /** * @dev Stores the mediator contract address from the other network. * @param _mediatorContract the address of the mediator contract. */ function _setMediatorContractOnOtherSide(address _mediatorContract) internal { addressStorage[MEDIATOR_CONTRACT] = _mediatorContract; } /** * @dev Stores the WPLS contract address. * @param _wplsContract the address. */ function _setWPLSContract(address _wplsContract) internal { addressStorage[WPLS_CONTRACT] = _wplsContract; } /** * @dev Tells the id of the message originated on the other network. * @return the id of the message originated on the other network. */ function messageId() internal view returns (bytes32) { return bridgeContract().messageId(); } /** * @dev Tells the maximum gas limit that a message can use on its execution by the AMB bridge on the other network. * @return the maximum gas limit value. */ function maxGasPerTx() internal view returns (uint256) { return bridgeContract().maxGasPerTx(); } function _passMessage(bytes memory _data) internal virtual returns (bytes32); } // File: contracts/upgradeable_contracts/components/common/BridgeOperationsStorage.sol pragma solidity 0.7.5; /** * @title BridgeOperationsStorage * @dev Functionality for storing processed bridged operations. */ abstract contract BridgeOperationsStorage is EternalStorage { /** * @dev Stores the bridged token of a message sent to the AMB bridge. * @param _messageId of the message sent to the bridge. * @param _token bridged token address. */ function setMessageToken(bytes32 _messageId, address _token) internal { addressStorage[keccak256(abi.encodePacked("messageToken", _messageId))] = _token; } /** * @dev Tells the bridged token address of a message sent to the AMB bridge. * @return address of a token contract. */ function messageToken(bytes32 _messageId) internal view returns (address) { return addressStorage[keccak256(abi.encodePacked("messageToken", _messageId))]; } /** * @dev Stores the value of a message sent to the AMB bridge. * @param _messageId of the message sent to the bridge. * @param _value amount of tokens bridged. */ function setMessageValue(bytes32 _messageId, uint256 _value) internal { uintStorage[keccak256(abi.encodePacked("messageValue", _messageId))] = _value; } /** * @dev Tells the amount of tokens of a message sent to the AMB bridge. * @return value representing amount of tokens. */ function messageValue(bytes32 _messageId) internal view returns (uint256) { return uintStorage[keccak256(abi.encodePacked("messageValue", _messageId))]; } /** * @dev Stores the receiver of a message sent to the AMB bridge. * @param _messageId of the message sent to the bridge. * @param _recipient receiver of the tokens bridged. */ function setMessageRecipient(bytes32 _messageId, address _recipient) internal { addressStorage[keccak256(abi.encodePacked("messageRecipient", _messageId))] = _recipient; } /** * @dev Tells the receiver of a message sent to the AMB bridge. * @return address of the receiver. */ function messageRecipient(bytes32 _messageId) internal view returns (address) { return addressStorage[keccak256(abi.encodePacked("messageRecipient", _messageId))]; } } // File: contracts/upgradeable_contracts/components/common/FailedMessagesProcessor.sol pragma solidity 0.7.5; /** * @title FailedMessagesProcessor * @dev Functionality for fixing failed bridging operations. */ abstract contract FailedMessagesProcessor is BasicAMBMediator, BridgeOperationsStorage { event FailedMessageFixed(bytes32 indexed messageId, address token, address recipient, uint256 value); /** * @dev Method to be called when a bridged message execution failed. It will generate a new message requesting to * fix/roll back the transferred assets on the other network. * @param _messageId id of the message which execution failed. */ function requestFailedMessageFix(bytes32 _messageId) external { IAMB bridge = bridgeContract(); require(!bridge.messageCallStatus(_messageId)); require(bridge.failedMessageReceiver(_messageId) == address(this)); require(bridge.failedMessageSender(_messageId) == mediatorContractOnOtherSide()); bytes4 methodSelector = this.fixFailedMessage.selector; bytes memory data = abi.encodeWithSelector(methodSelector, _messageId); _passMessage(data); } /** * @dev Handles the request to fix transferred assets which bridged message execution failed on the other network. * It uses the information stored by passMessage method when the assets were initially transferred * @param _messageId id of the message which execution failed on the other network. */ function fixFailedMessage(bytes32 _messageId) public onlyMediator { require(!messageFixed(_messageId)); address token = messageToken(_messageId); address recipient = messageRecipient(_messageId); uint256 value = messageValue(_messageId); setMessageFixed(_messageId); executeActionOnFixedTokens(token, recipient, value); emit FailedMessageFixed(_messageId, token, recipient, value); } /** * @dev Tells if a message sent to the AMB bridge has been fixed. * @return bool indicating the status of the message. */ function messageFixed(bytes32 _messageId) public view returns (bool) { return boolStorage[keccak256(abi.encodePacked("messageFixed", _messageId))]; } /** * @dev Sets that the message sent to the AMB bridge has been fixed. * @param _messageId of the message sent to the bridge. */ function setMessageFixed(bytes32 _messageId) internal { boolStorage[keccak256(abi.encodePacked("messageFixed", _messageId))] = true; } function executeActionOnFixedTokens( address _token, address _recipient, uint256 _value ) internal virtual; } // File: contracts/interfaces/IERC677.sol pragma solidity 0.7.5; interface IERC677 is IERC20 { event Transfer(address indexed from, address indexed to, uint256 value, bytes data); function transferAndCall( address to, uint256 value, bytes calldata data ) external returns (bool); function increaseAllowance(address spender, uint256 addedValue) external returns (bool); function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); } // File: contracts/interfaces/IBurnableMintableERC677Token.sol pragma solidity 0.7.5; interface IBurnableMintableERC677Token is IERC677 { function mint(address _to, uint256 _amount) external returns (bool); function burn(uint256 _value) external; function claimTokens(address _token, address _to) external; } // File: contracts/interfaces/IERC20Metadata.sol pragma solidity 0.7.5; interface IERC20Metadata { function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); } // File: contracts/interfaces/IERC20Receiver.sol pragma solidity 0.7.5; interface IERC20Receiver { function onTokenBridged( address token, uint256 value, bytes calldata data ) external; } // File: contracts/libraries/TokenReader.sol pragma solidity 0.7.5; // solhint-disable interface ITokenDetails { function name() external view; function NAME() external view; function symbol() external view; function SYMBOL() external view; function decimals() external view; function DECIMALS() external view; } // solhint-enable /** * @title TokenReader * @dev Helper methods for reading name/symbol/decimals parameters from ERC20 token contracts. */ library TokenReader { /** * @dev Reads the name property of the provided token. * Either name() or NAME() method is used. * Both, string and bytes32 types are supported. * @param _token address of the token contract. * @return token name as a string or an empty string if none of the methods succeeded. */ function readName(address _token) internal view returns (string memory) { (bool status, bytes memory data) = _token.staticcall(abi.encodeWithSelector(ITokenDetails.name.selector)); if (!status) { (status, data) = _token.staticcall(abi.encodeWithSelector(ITokenDetails.NAME.selector)); if (!status) { return ""; } } return _convertToString(data); } /** * @dev Reads the symbol property of the provided token. * Either symbol() or SYMBOL() method is used. * Both, string and bytes32 types are supported. * @param _token address of the token contract. * @return token symbol as a string or an empty string if none of the methods succeeded. */ function readSymbol(address _token) internal view returns (string memory) { (bool status, bytes memory data) = _token.staticcall(abi.encodeWithSelector(ITokenDetails.symbol.selector)); if (!status) { (status, data) = _token.staticcall(abi.encodeWithSelector(ITokenDetails.SYMBOL.selector)); if (!status) { return ""; } } return _convertToString(data); } /** * @dev Reads the decimals property of the provided token. * Either decimals() or DECIMALS() method is used. * @param _token address of the token contract. * @return token decimals or 0 if none of the methods succeeded. */ function readDecimals(address _token) internal view returns (uint8) { (bool status, bytes memory data) = _token.staticcall(abi.encodeWithSelector(ITokenDetails.decimals.selector)); if (!status) { (status, data) = _token.staticcall(abi.encodeWithSelector(ITokenDetails.DECIMALS.selector)); if (!status) { return 0; } } return abi.decode(data, (uint8)); } /** * @dev Internal function for converting returned value of name()/symbol() from bytes32/string to string. * @param returnData data returned by the token contract. * @return string with value obtained from returnData. */ function _convertToString(bytes memory returnData) private pure returns (string memory) { if (returnData.length > 32) { return abi.decode(returnData, (string)); } else if (returnData.length == 32) { bytes32 data = abi.decode(returnData, (bytes32)); string memory res = new string(32); assembly { let len := 0 mstore(add(res, 32), data) // save value in result string // solhint-disable for { } gt(data, 0) { len := add(len, 1) } { // until string is empty data := shl(8, data) // shift left by one symbol } // solhint-enable mstore(res, len) // save result string length } return res; } else { return ""; } } } // File: contracts/libraries/SafeMint.sol pragma solidity 0.7.5; /** * @title SafeMint * @dev Wrapper around the mint() function in all mintable tokens that verifies the return value. */ library SafeMint { /** * @dev Wrapper around IBurnableMintableERC677Token.mint() that verifies that output value is true. * @param _token token contract. * @param _to address of the tokens receiver. * @param _value amount of tokens to mint. */ function safeMint( IBurnableMintableERC677Token _token, address _to, uint256 _value ) internal { require(_token.mint(_to, _value)); } } // File: contracts/upgradeable_contracts/ReentrancyGuard.sol pragma solidity 0.7.5; contract ReentrancyGuard { function lock() internal view returns (bool res) { assembly { // Even though this is not the same as boolStorage[keccak256(abi.encodePacked("lock"))], // since solidity mapping introduces another level of addressing, such slot change is safe // for temporary variables which are cleared at the end of the call execution. res := sload(0x6168652c307c1e813ca11cfb3a601f1cf3b22452021a5052d8b05f1f1f8a3e92) // keccak256(abi.encodePacked("lock")) } } function setLock(bool _lock) internal { assembly { // Even though this is not the same as boolStorage[keccak256(abi.encodePacked("lock"))], // since solidity mapping introduces another level of addressing, such slot change is safe // for temporary variables which are cleared at the end of the call execution. sstore(0x6168652c307c1e813ca11cfb3a601f1cf3b22452021a5052d8b05f1f1f8a3e92, _lock) // keccak256(abi.encodePacked("lock")) } } } // File: contracts/libraries/Bytes.sol pragma solidity 0.7.5; /** * @title Bytes * @dev Helper methods to transform bytes to other solidity types. */ library Bytes { /** * @dev Truncate bytes array if its size is more than 20 bytes. * NOTE: This function does not perform any checks on the received parameter. * Make sure that the _bytes argument has a correct length, not less than 20 bytes. * A case when _bytes has length less than 20 will lead to the undefined behaviour, * since assembly will read data from memory that is not related to the _bytes argument. * @param _bytes to be converted to address type * @return addr address included in the firsts 20 bytes of the bytes array in parameter. */ function bytesToAddress(bytes memory _bytes) internal pure returns (address addr) { assembly { addr := mload(add(_bytes, 20)) } } } // File: contracts/upgradeable_contracts/BasicOmnibridge.sol pragma solidity 0.7.5; /** * @title BasicOmnibridge * @dev Common functionality for multi-token mediator intended to work on top of AMB bridge. */ abstract contract BasicOmnibridge is Initializable, Upgradeable, Claimable, OmnibridgeInfo, FailedMessagesProcessor, BridgedTokensRegistry, NativeTokensRegistry, MediatorBalanceStorage, TokensBridgeLimits, ReentrancyGuard { using SafeERC20 for IERC677; using SafeMint for IBurnableMintableERC677Token; using SafeMath for uint256; /** * @dev ERC677 transfer callback function. * @param _from address of tokens sender. * @param _value amount of transferred tokens. * @param _data additional transfer data, can be used for passing alternative receiver address. */ function onTokenTransfer( address _from, uint256 _value, bytes memory _data ) external returns (bool) { require(nativeTokenAddress(msg.sender) == addressStorage[WPLS_CONTRACT]); if (!lock()) { bytes memory data = new bytes(0); address receiver = _from; if (_data.length >= 20) { receiver = Bytes.bytesToAddress(_data); if (_data.length > 20) { assembly { let size := sub(mload(_data), 20) data := add(_data, 20) mstore(data, size) } } } bridgeSpecificActionsOnTokenTransfer(msg.sender, _from, receiver, _value, data); } return true; } /** * @dev Initiate the bridge operation for some amount of tokens from msg.sender. * The user should first call Approve method of the ERC677 token. * @param token bridged token contract address. * @param _receiver address that will receive the native tokens on the other network. * @param _value amount of tokens to be transferred to the other network. */ function relayTokens( IERC677 token, address _receiver, uint256 _value ) external { _relayTokens(token, _receiver, _value, new bytes(0)); } /** * @dev Initiate the bridge operation for some amount of tokens from msg.sender to msg.sender on the other side. * The user should first call Approve method of the ERC677 token. * @param token bridged token contract address. * @param _value amount of tokens to be transferred to the other network. */ function relayTokens(IERC677 token, uint256 _value) external { _relayTokens(token, msg.sender, _value, new bytes(0)); } /** * @dev Initiate the bridge operation for some amount of tokens from msg.sender. * The user should first call Approve method of the ERC677 token. * @param token bridged token contract address. * @param _receiver address that will receive the native tokens on the other network. * @param _value amount of tokens to be transferred to the other network. * @param _data additional transfer data to be used on the other side. */ function relayTokensAndCall( IERC677 token, address _receiver, uint256 _value, bytes memory _data ) external { _relayTokens(token, _receiver, _value, _data); } /** * @dev Validates that the token amount is inside the limits, calls transferFrom to transfer the tokens to the contract * and invokes the method to burn/lock the tokens and unlock/mint the tokens on the other network. * The user should first call Approve method of the ERC677 token. * @param token bridge token contract address. * @param _receiver address that will receive the native tokens on the other network. * @param _value amount of tokens to be transferred to the other network. * @param _data additional transfer data to be used on the other side. */ function _relayTokens( IERC677 token, address _receiver, uint256 _value, bytes memory _data ) internal { // This lock is to prevent calling passMessage twice if a ERC677 token is used. // When transferFrom is called, after the transfer, the ERC677 token will call onTokenTransfer from this contract // which will call passMessage. require(address(token) == addressStorage[WPLS_CONTRACT]); require(!lock()); uint256 balanceBefore = token.balanceOf(address(this)); setLock(true); token.safeTransferFrom(msg.sender, address(this), _value); setLock(false); uint256 balanceDiff = token.balanceOf(address(this)).sub(balanceBefore); require(balanceDiff <= _value); bridgeSpecificActionsOnTokenTransfer(address(token), msg.sender, _receiver, balanceDiff, _data); } /** * @dev Handles the bridged tokens for the already registered token pair. * Checks that the value is inside the execution limits and invokes the Mint accordingly. * @param _token address of the native ERC20/ERC677 token on the other side. * @param _recipient address that will receive the tokens. * @param _value amount of tokens to be received. */ function handleBridgedTokens( address _token, address _recipient, uint256 _value ) external onlyMediator { address token = bridgedTokenAddress(_token); require(isTokenRegistered(token)); _handleTokens(token, false, _recipient, _value); } /** * @dev Handles the bridged tokens for the already registered token pair. * Checks that the value is inside the execution limits and invokes the Unlock accordingly. * Executes a callback on the receiver. * @param _token address of the native ERC20/ERC677 token on the other side. * @param _recipient address that will receive the tokens. * @param _value amount of tokens to be received. * @param _data additional transfer data passed from the other side. */ function handleBridgedTokensAndCall( address _token, address _recipient, uint256 _value, bytes memory _data ) external onlyMediator { address token = bridgedTokenAddress(_token); require(isTokenRegistered(token)); uint256 valueAfterFee = _handleTokens(token, false, _recipient, _value); _receiverCallback(_recipient, token, valueAfterFee, _data); } /** * @dev Handles the bridged tokens that are native to this chain. * Checks that the value is inside the execution limits and invokes the Unlock accordingly. * @param _token native ERC20 token. * @param _recipient address that will receive the tokens. * @param _value amount of tokens to be received. */ function handleNativeTokens( address _token, address _recipient, uint256 _value ) external onlyMediator { _ackBridgedTokenDeploy(_token); _handleTokens(_token, true, _recipient, _value); } /** * @dev Handles the bridged tokens that are native to this chain. * Checks that the value is inside the execution limits and invokes the Unlock accordingly. * Executes a callback on the receiver. * @param _token native ERC20 token. * @param _recipient address that will receive the tokens. * @param _value amount of tokens to be received. * @param _data additional transfer data passed from the other side. */ function handleNativeTokensAndCall( address _token, address _recipient, uint256 _value, bytes memory _data ) external onlyMediator { _ackBridgedTokenDeploy(_token); uint256 valueAfterFee = _handleTokens(_token, true, _recipient, _value); _receiverCallback(_recipient, _token, valueAfterFee, _data); } /** * @dev Checks if a given token is a bridged token that is native to this side of the bridge. * @param _token address of token contract. * @return message id of the send message. */ function isRegisteredAsNativeToken(address _token) public view returns (bool) { return isTokenRegistered(_token) && nativeTokenAddress(_token) == address(0); } /** * @dev Unlock back the amount of tokens that were bridged to the other network but failed. * @param _token address that bridged token contract. * @param _recipient address that will receive the tokens. * @param _value amount of tokens to be received. */ function executeActionOnFixedTokens( address _token, address _recipient, uint256 _value ) internal override { _releaseTokens(nativeTokenAddress(_token) == address(0), _token, _recipient, _value, _value); } /** * @dev Allows to send to the other network the amount of locked tokens that can be forced into the contract * without the invocation of the required methods. (e. g. regular transfer without a call to onTokenTransfer) * @param _token address of the token contract. * Before calling this method, it must be carefully investigated how imbalance happened * in order to avoid an attempt to steal the funds from a token with double addresses * (e.g. TUSD is accessible at both 0x8dd5fbCe2F6a956C3022bA3663759011Dd51e73E and 0x0000000000085d4780B73119b644AE5ecd22b376) * @param _receiver the address that will receive the tokens on the other network. */ function fixMediatorBalance(address _token, address _receiver) external onlyIfUpgradeabilityOwner validAddress(_receiver) { require(isRegisteredAsNativeToken(_token)); uint256 diff = _unaccountedBalance(_token); require(diff > 0); uint256 available = maxAvailablePerTx(_token); require(available > 0); if (diff > available) { diff = available; } addTotalSpentPerDay(_token, getCurrentDay(), diff); bytes memory data = _prepareMessage(address(0), _token, _receiver, diff, new bytes(0)); bytes32 _messageId = _passMessage(data); _recordBridgeOperation(_messageId, _token, _receiver, diff); } /** * @dev Claims stuck tokens. Only unsupported tokens can be claimed. * When dealing with already supported tokens, fixMediatorBalance can be used instead. * @param _token address of claimed token, address(0) for native * @param _to address of tokens receiver */ function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner { // Only unregistered tokens and native coins are allowed to be claimed with the use of this function require(_token == address(0) || !isTokenRegistered(_token)); claimValues(_token, _to); } /** * @dev Withdraws erc20 tokens or native coins from the bridged token contract. * Only the proxy owner is allowed to call this method. * @param _bridgedToken address of the bridged token contract. * @param _token address of the claimed token or address(0) for native coins. * @param _to address of the tokens/coins receiver. */ function claimTokensFromTokenContract( address _bridgedToken, address _token, address _to ) external onlyIfUpgradeabilityOwner { IBurnableMintableERC677Token(_bridgedToken).claimTokens(_token, _to); } /** * @dev Internal function for recording bridge operation for further usage. * Recorded information is used for fixing failed requests on the other side. * @param _messageId id of the sent message. * @param _token bridged token address. * @param _sender address of the tokens sender. * @param _value bridged value. */ function _recordBridgeOperation( bytes32 _messageId, address _token, address _sender, uint256 _value ) internal { setMessageToken(_messageId, _token); setMessageRecipient(_messageId, _sender); setMessageValue(_messageId, _value); emit TokensBridgingInitiated(_token, _sender, _value, _messageId); } /** * @dev Constructs the message to be sent to the other side. Burns/locks bridged amount of tokens. * @param _nativeToken address of the native token contract. * @param _token bridged token address. * @param _receiver address of the tokens receiver on the other side. * @param _value bridged value. * @param _data additional transfer data passed from the other side. */ function _prepareMessage( address _nativeToken, address _token, address _receiver, uint256 _value, bytes memory _data ) internal returns (bytes memory) { bool withData = _data.length > 0 || msg.sig == this.relayTokensAndCall.selector; // process token is native with respect to this side of the bridge if (_nativeToken == address(0)) { _setMediatorBalance(_token, mediatorBalance(_token).add(_value)); return withData ? abi.encodeWithSelector(this.handleBridgedTokensAndCall.selector, _token, _receiver, _value, _data) : abi.encodeWithSelector(this.handleBridgedTokens.selector, _token, _receiver, _value); } // process already known token that is bridged from other chain IBurnableMintableERC677Token(_token).burn(_value); return withData ? abi.encodeWithSelector( this.handleNativeTokensAndCall.selector, _nativeToken, _receiver, _value, _data ) : abi.encodeWithSelector(this.handleNativeTokens.selector, _nativeToken, _receiver, _value); } /** * @dev Internal function for getting minter proxy address. * @param _token address of the token to mint. * @return address of the minter contract that should be used for calling mint(address,uint256) */ function _getMinterFor(address _token) internal pure virtual returns (IBurnableMintableERC677Token) { return IBurnableMintableERC677Token(_token); } /** * Internal function for unlocking some amount of tokens. * @param _isNative true, if token is native w.r.t. to this side of the bridge. * @param _token address of the token contract. * @param _recipient address of the tokens receiver. * @param _value amount of tokens to unlock. * @param _balanceChange amount of balance to subtract from the mediator balance. */ function _releaseTokens( bool _isNative, address _token, address _recipient, uint256 _value, uint256 _balanceChange ) internal virtual { if (_isNative) { IERC677(_token).safeTransfer(_recipient, _value); _setMediatorBalance(_token, mediatorBalance(_token).sub(_balanceChange)); } else { _getMinterFor(_token).safeMint(_recipient, _value); } } /** * Notifies receiving contract about the completed bridging operation. * @param _recipient address of the tokens receiver. * @param _token address of the bridged token. * @param _value amount of tokens transferred. * @param _data additional data passed to the callback. */ function _receiverCallback( address _recipient, address _token, uint256 _value, bytes memory _data ) internal { if (Address.isContract(_recipient)) { _recipient.call(abi.encodeWithSelector(IERC20Receiver.onTokenBridged.selector, _token, _value, _data)); } } /** * @dev Internal function for counting excess balance which is not tracked within the bridge. * Represents the amount of forced tokens on this contract. * @param _token address of the token contract. * @return amount of excess tokens. */ function _unaccountedBalance(address _token) internal view virtual returns (uint256) { return IERC677(_token).balanceOf(address(this)).sub(mediatorBalance(_token)); } function _handleTokens( address _token, bool _isNative, address _recipient, uint256 _value ) internal virtual returns (uint256); function bridgeSpecificActionsOnTokenTransfer( address _token, address _from, address _receiver, uint256 _value, bytes memory _data ) internal virtual; } // File: contracts/upgradeable_contracts/components/common/GasLimitManager.sol pragma solidity 0.7.5; /** * @title GasLimitManager * @dev Functionality for determining the request gas limit for AMB execution. */ abstract contract GasLimitManager is BasicAMBMediator { bytes32 internal constant REQUEST_GAS_LIMIT = 0x2dfd6c9f781bb6bbb5369c114e949b69ebb440ef3d4dd6b2836225eb1dc3a2be; // keccak256(abi.encodePacked("requestGasLimit")) /** * @dev Sets the default gas limit to be used in the message execution by the AMB bridge on the other network. * This value can't exceed the parameter maxGasPerTx defined on the AMB bridge. * Only the owner can call this method. * @param _gasLimit the gas limit for the message execution. */ function setRequestGasLimit(uint256 _gasLimit) external onlyOwner { _setRequestGasLimit(_gasLimit); } /** * @dev Tells the default gas limit to be used in the message execution by the AMB bridge on the other network. * @return the gas limit for the message execution. */ function requestGasLimit() public view returns (uint256) { return uintStorage[REQUEST_GAS_LIMIT]; } /** * @dev Stores the gas limit to be used in the message execution by the AMB bridge on the other network. * @param _gasLimit the gas limit for the message execution. */ function _setRequestGasLimit(uint256 _gasLimit) internal { require(_gasLimit <= maxGasPerTx()); uintStorage[REQUEST_GAS_LIMIT] = _gasLimit; } } // File: contracts/upgradeable_contracts/ForeignOmnibridge.sol pragma solidity 0.7.5; /** * @title ForeignOmnibridge * @dev Foreign side implementation for multi-token mediator intended to work on top of AMB bridge. * It is designed to be used as an implementation contract of EternalStorageProxy contract. */ contract ForeignOmnibridge is BasicOmnibridge, GasLimitManager { using SafeERC20 for IERC677; using SafeMint for IBurnableMintableERC677Token; using SafeMath for uint256; /** * @dev Stores the initial parameters of the mediator. * @param _bridgeContract the address of the AMB bridge contract. * @param _mediatorContract the address of the mediator contract on the other network. * @param _dailyLimitMaxPerTxMinPerTxArray array with limit values for the assets to be bridged to the other network. * [ 0 = dailyLimit, 1 = maxPerTx, 2 = minPerTx ] * @param _executionDailyLimitExecutionMaxPerTxArray array with limit values for the assets bridged from the other network. * [ 0 = executionDailyLimit, 1 = executionMaxPerTx ] * @param _requestGasLimit the gas limit for the message execution. * @param _owner address of the owner of the mediator contract. * @param _wplsContract address of the WPLS contract on Home side. * @param _bridgedWPLSContract address of the bridged WPLS contract on Foreign side. */ function initialize( address _bridgeContract, address _mediatorContract, uint256[3] calldata _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ] uint256[2] calldata _executionDailyLimitExecutionMaxPerTxArray, // [ 0 = _executionDailyLimit, 1 = _executionMaxPerTx ] uint256 _requestGasLimit, address _owner, address _wplsContract, address _bridgedWPLSContract ) external onlyRelevantSender returns (bool) { require(!isInitialized()); _setBridgeContract(_bridgeContract); _setMediatorContractOnOtherSide(_mediatorContract); _setLimits(address(0), _dailyLimitMaxPerTxMinPerTxArray); _setExecutionLimits(address(0), _executionDailyLimitExecutionMaxPerTxArray); _setRequestGasLimit(_requestGasLimit); _setOwner(_owner); _setWPLSContract(_wplsContract); _setTokenAddressPair(_wplsContract, _bridgedWPLSContract); _initializeTokenBridgeLimits(_bridgedWPLSContract, 18); setInitialize(); return isInitialized(); } /** * @dev Handles the bridged tokens. * Checks that the value is inside the execution limits and invokes the Mint or Unlock accordingly. * @param _token token contract address on this side of the bridge. * @param _isNative true, if given token is native to this chain and Unlock should be used. * @param _recipient address that will receive the tokens. * @param _value amount of tokens to be received. * @return _value amount as no fees dudcted on foreign side. */ function _handleTokens( address _token, bool _isNative, address _recipient, uint256 _value ) internal override returns(uint256) { // prohibit withdrawal of tokens during other bridge operations (e.g. relayTokens) // such reentrant withdrawal can lead to an incorrect balanceDiff calculation require(!lock()); require(withinExecutionLimit(_token, _value)); addTotalExecutedPerDay(_token, getCurrentDay(), _value); _releaseTokens(_isNative, _token, _recipient, _value, _value); emit TokensBridged(_token, _recipient, _value, messageId()); return (_value); } /** * @dev Executes action on deposit of bridged tokens * @param _token address of the token contract * @param _from address of tokens sender * @param _receiver address of tokens receiver on the other side * @param _value requested amount of bridged tokens * @param _data additional transfer data to be used on the other side */ function bridgeSpecificActionsOnTokenTransfer( address _token, address _from, address _receiver, uint256 _value, bytes memory _data ) internal virtual override { require(_receiver != address(0) && _receiver != mediatorContractOnOtherSide()); require(isTokenRegistered(_token)); require(withinLimit(_token, _value)); addTotalSpentPerDay(_token, getCurrentDay(), _value); bytes memory data = _prepareMessage(nativeTokenAddress(_token), _token, _receiver, _value, _data); bytes32 _messageId = _passMessage(data); _recordBridgeOperation(_messageId, _token, _from, _value); } /** * @dev Internal function for sending an AMB message to the mediator on the other side. * @param _data data to be sent to the other side of the bridge. * @return id of the sent message. */ function _passMessage(bytes memory _data) internal override returns (bytes32) { return bridgeContract().requireToPassMessage(mediatorContractOnOtherSide(), _data, requestGasLimit()); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"newLimit","type":"uint256"}],"name":"DailyLimitChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"newLimit","type":"uint256"}],"name":"ExecutionDailyLimitChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"FailedMessageFixed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nativeToken","type":"address"},{"indexed":true,"internalType":"address","name":"bridgedToken","type":"address"}],"name":"NewTokenRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"}],"name":"TokensBridged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"}],"name":"TokensBridgingInitiated","type":"event"},{"inputs":[],"name":"bridgeContract","outputs":[{"internalType":"contract IAMB","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_nativeToken","type":"address"}],"name":"bridgedTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"}],"name":"claimTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bridgedToken","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"}],"name":"claimTokensFromTokenContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"dailyLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"executionDailyLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"executionMaxPerTx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_messageId","type":"bytes32"}],"name":"fixFailedMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"fixMediatorBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getBridgeInterfacesVersion","outputs":[{"internalType":"uint64","name":"major","type":"uint64"},{"internalType":"uint64","name":"minor","type":"uint64"},{"internalType":"uint64","name":"patch","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getBridgeMode","outputs":[{"internalType":"bytes4","name":"_data","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getCurrentDay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"handleBridgedTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"handleBridgedTokensAndCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"handleNativeTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"handleNativeTokensAndCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bridgeContract","type":"address"},{"internalType":"address","name":"_mediatorContract","type":"address"},{"internalType":"uint256[3]","name":"_dailyLimitMaxPerTxMinPerTxArray","type":"uint256[3]"},{"internalType":"uint256[2]","name":"_executionDailyLimitExecutionMaxPerTxArray","type":"uint256[2]"},{"internalType":"uint256","name":"_requestGasLimit","type":"uint256"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_wplsContract","type":"address"},{"internalType":"address","name":"_bridgedWPLSContract","type":"address"}],"name":"initialize","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"isBridgedTokenDeployAcknowledged","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"isRegisteredAsNativeToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"isTokenRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"maxAvailablePerTx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"maxPerTx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"mediatorBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mediatorContractOnOtherSide","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_messageId","type":"bytes32"}],"name":"messageFixed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"minPerTx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_bridgedToken","type":"address"}],"name":"nativeTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"onTokenTransfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC677","name":"token","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"relayTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC677","name":"token","type":"address"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"relayTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC677","name":"token","type":"address"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"relayTokensAndCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_messageId","type":"bytes32"}],"name":"requestFailedMessageFix","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestGasLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_bridgeContract","type":"address"}],"name":"setBridgeContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_dailyLimit","type":"uint256"}],"name":"setDailyLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_dailyLimit","type":"uint256"}],"name":"setExecutionDailyLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_maxPerTx","type":"uint256"}],"name":"setExecutionMaxPerTx","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_maxPerTx","type":"uint256"}],"name":"setMaxPerTx","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_mediatorContract","type":"address"}],"name":"setMediatorContractOnOtherSide","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_minPerTx","type":"uint256"}],"name":"setMinPerTx","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasLimit","type":"uint256"}],"name":"setRequestGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wplsContract","type":"address"}],"name":"setWPLSContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_day","type":"uint256"}],"name":"totalExecutedPerDay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_day","type":"uint256"}],"name":"totalSpentPerDay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withinExecutionLimit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withinLimit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wplsContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50614039806100206000396000f3fe608060405234801561001057600080fd5b50600436106102d65760003560e01c80637837cf9111610182578063c2173d43116100e9578063db6fff8c116100a2578063f2fde38b1161007c578063f2fde38b14610c60578063f3b8379114610c86578063f3f5141514610ca3578063f65c614a14610cc9576102d6565b8063db6fff8c14610bdc578063ec47de2a14610c08578063f2c54fe814610c34576102d6565b8063c2173d43146109d2578063c5345761146109f8578063cd59658314610abc578063d0342acd14610ac4578063d474e37a14610af2578063d740548114610b18576102d6565b8063a4b1c2431161013b578063a4b1c24314610863578063a4c0ed3614610889578063ab3a25d914610942578063ad58bdd11461096e578063ae813e9f146109a4578063be3b625b146109ca576102d6565b80637837cf9114610712578063867f7a4d1461073e578063871c0760146108025780638da5cb5b1461080a5780639a4a4395146108125780639cb7595a1461082f576102d6565b80632d70061f1161024157806359339982116101fa57806369ffa08a116101d457806369ffa08a1461063e5780636e5d6bea1461066c578063759c82a8146106925780637610722f146106ec576102d6565b806359339982146105c357806361c04f84146105e057806364696f9714610606576102d6565b80632d70061f146104fa578063392e53cd1461053c5780633a50bc87146105445780633e6968b61461057057806340f8dd8614610578578063437764df1461059e576102d6565b8063125e4cfb11610293578063125e4cfb146103f057806316ef191314610426578063194153d31461044c57806326aa101f14610472578063272255bb146104985780632803212f146104ce576102d6565b806301e4f53a146102db57806301fcc1d314610309578063032f693f146103355780630950d5151461036d5780630b26cf661461038a57806310775238146103b0575b600080fd5b610307600480360360408110156102f157600080fd5b506001600160a01b038135169060200135610cd1565b005b6103076004803603604081101561031f57600080fd5b506001600160a01b038135169060200135610d10565b61035b6004803603602081101561034b57600080fd5b50356001600160a01b0316610daf565b60408051918252519081900360200190f35b6103076004803603602081101561038357600080fd5b5035610e03565b610307600480360360208110156103a057600080fd5b50356001600160a01b0316610eac565b6103dc600480360360408110156103c657600080fd5b506001600160a01b038135169060200135610ec0565b604080519115158252519081900360200190f35b6103076004803603606081101561040657600080fd5b506001600160a01b03813581169160208101359091169060400135610f33565b61035b6004803603602081101561043c57600080fd5b50356001600160a01b0316610f6e565b61035b6004803603602081101561046257600080fd5b50356001600160a01b0316610fcb565b6103dc6004803603602081101561048857600080fd5b50356001600160a01b0316611026565b610307600480360360608110156104ae57600080fd5b506001600160a01b03813581169160208101359091169060400135611039565b610307600480360360408110156104e457600080fd5b506001600160a01b03813516906020013561105d565b6105206004803603602081101561051057600080fd5b50356001600160a01b031661112c565b604080516001600160a01b039092168252519081900360200190f35b6103dc611192565b6103dc6004803603604081101561055a57600080fd5b506001600160a01b0381351690602001356111e3565b61035b611239565b61035b6004803603602081101561058e57600080fd5b50356001600160a01b0316611242565b6105a66112a1565b604080516001600160e01b03199092168252519081900360200190f35b6103dc600480360360208110156105d957600080fd5b50356112ac565b610520600480360360208110156105f657600080fd5b50356001600160a01b03166112ff565b6103076004803603606081101561061c57600080fd5b506001600160a01b038135811691602081013582169160409091013516611368565b6103076004803603604081101561065457600080fd5b506001600160a01b03813581169160200135166113ed565b6103076004803603602081101561068257600080fd5b50356001600160a01b0316611424565b6103dc60048036036101608110156106a957600080fd5b506001600160a01b0381358116916020810135821691604082019160a081019160e082013591610100810135821691610120820135811691610140013516611435565b61035b6004803603602081101561070257600080fd5b50356001600160a01b031661161f565b6103076004803603604081101561072857600080fd5b506001600160a01b038135169060200135611679565b6103076004803603608081101561075457600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b81111561078e57600080fd5b8201836020820111156107a057600080fd5b803590602001918460018302840111600160201b831117156107c157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611751945050505050565b61052061177f565b6105206117d6565b6103076004803603602081101561082857600080fd5b503561182d565b610837611a19565b6040805167ffffffffffffffff9485168152928416602084015292168183015290519081900360600190f35b61035b6004803603602081101561087957600080fd5b50356001600160a01b0316611a23565b6103dc6004803603606081101561089f57600080fd5b6001600160a01b0382351691602081013591810190606081016040820135600160201b8111156108ce57600080fd5b8201836020820111156108e057600080fd5b803590602001918460018302840111600160201b8311171561090157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611a77945050505050565b61035b6004803603604081101561095857600080fd5b506001600160a01b038135169060200135611b2a565b6103076004803603606081101561098457600080fd5b506001600160a01b03813581169160208101359091169060400135611b90565b6103dc600480360360208110156109ba57600080fd5b50356001600160a01b0316611ba3565b61035b611bfc565b6103dc600480360360208110156109e857600080fd5b50356001600160a01b0316611c4a565b61030760048036036080811015610a0e57600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b811115610a4857600080fd5b820183602082011115610a5a57600080fd5b803590602001918460018302840111600160201b83111715610a7b57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611c77945050505050565b610520611cc3565b61030760048036036040811015610ada57600080fd5b506001600160a01b0381358116916020013516611d1a565b61030760048036036020811015610b0857600080fd5b50356001600160a01b0316611dd7565b61030760048036036080811015610b2e57600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b811115610b6857600080fd5b820183602082011115610b7a57600080fd5b803590602001918460018302840111600160201b83111715610b9b57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611de8945050505050565b61030760048036036040811015610bf257600080fd5b506001600160a01b038135169060200135611df4565b61030760048036036040811015610c1e57600080fd5b506001600160a01b038135169060200135611e91565b61035b60048036036040811015610c4a57600080fd5b506001600160a01b038135169060200135611f32565b61030760048036036020811015610c7657600080fd5b50356001600160a01b0316611f9b565b61030760048036036020811015610c9c57600080fd5b5035611fac565b61035b60048036036020811015610cb957600080fd5b50356001600160a01b0316611fbd565b610520612013565b610d0c8233836000805b506040519080825280601f01601f191660200182016040528015610d06576020820181803683370190505b50612046565b5050565b610d186121dd565b610d2182611026565b610d2a57600080fd5b801580610d495750600081118015610d495750610d4682611242565b81105b610d5257600080fd5b60408051700caf0cac6eae8d2dedc9ac2f0a0cae4a8f607b1b60208083019190915260609490941b6001600160601b0319166031820152815180820360250181526045909101825280519084012060009081529283905290912055565b60408051670dac2f0a0cae4a8f60c31b60208083019190915260609390931b6001600160601b03191660288201528151808203601c018152603c909101825280519083012060009081529182905290205490565b610e0b612204565b610e14816112ac565b15610e1e57600080fd5b6000610e29826122ae565b90506000610e3683612307565b90506000610e4384612364565b9050610e4e846123b3565b610e5983838361240c565b604080516001600160a01b03808616825284166020820152808201839052905185917f07b5483b8e4bd8ea240a474d5117738350e7d431e3668c48a97910b0b397796a919081900360600190a250505050565b610eb46121dd565b610ebd8161242d565b50565b600080610ede83610ed886610ed3611239565b611b2a565b906124a9565b90506000610eec6000611fbd565b118015610f01575080610efe85611fbd565b10155b8015610f155750610f1184610daf565b8311155b8015610f295750610f2584611a23565b8310155b9150505b92915050565b610f3b612204565b6000610f468461112c565b9050610f5181611026565b610f5a57600080fd5b610f67816000858561250a565b5050505050565b60408051700caf0cac6eae8d2dedc9ac2f0a0cae4a8f607b1b60208083019190915260609390931b6001600160601b0319166031820152815180820360250181526045909101825280519083012060009081529182905290205490565b604080516e6d65646961746f7242616c616e636560881b60208083019190915260609390931b6001600160601b031916602f820152815180820360230181526043909101825280519083012060009081529182905290205490565b60008061103283611a23565b1192915050565b611041612204565b61104a836125ae565b611057836001848461250a565b50505050565b6110656121dd565b61106e82611026565b61107757600080fd5b61108082610daf565b81118061108b575080155b61109457600080fd5b604080516919185a5b1e531a5b5a5d60b21b6020808301919091526001600160601b0319606086901b16602a8301528251601e818403018152603e83018085528151918301919091206000908152918290529083902084905583905290516001600160a01b038416917fca0b3dabefdbd8c72c0a9cf4a6e9d107da897abf036ef3f3f3b010cdd25941599190819003605e0190a25050565b604080516f686f6d65546f6b656e4164647265737360801b60208083019190915260609390931b6001600160601b03191660308201528151808203602401815260449091018252805190830120600090815260029092529020546001600160a01b031690565b7f0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba60005260046020527f078d888f9b66f3f8bfa10909e31f1e16240db73449f0500afdbbe3a70da457cc5460ff1690565b6000806111fb83610ed8866111f6611239565b611f32565b905060006112096000611242565b11801561121e57508061121b85611242565b10155b8015610f29575061122e84610f6e565b909211159392505050565b62015180420490565b6040805172195e1958dd5d1a5bdb91185a5b1e531a5b5a5d606a1b60208083019190915260609390931b6001600160601b0319166033820152815180820360270181526047909101825280519083012060009081529182905290205490565b6358a8b61360e11b90565b604080516b1b595cdcd859d9519a5e195960a21b602080830191909152602c80830185905283518084039091018152604c909201835281519181019190912060009081526004909152205460ff16919050565b6040805172666f726569676e546f6b656e4164647265737360681b60208083019190915260609390931b6001600160601b03191660338201528151808203602701815260479091018252805190830120600090815260029092529020546001600160a01b031690565b61137061266a565b826001600160a01b03166369ffa08a83836040518363ffffffff1660e01b815260040180836001600160a01b03168152602001826001600160a01b0316815260200192505050600060405180830381600087803b1580156113d057600080fd5b505af11580156113e4573d6000803e3d6000fd5b50505050505050565b6113f561266a565b6001600160a01b0382161580611411575061140f82611026565b155b61141a57600080fd5b610d0c82826126e3565b61142c6121dd565b610ebd8161271d565b60408051600481526024810182526020810180516001600160e01b03166337ef410160e11b1781529151815160009384936060933093919290918291908083835b602083106114955780518252601f199092019160209182019101611476565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146114f5576040519150601f19603f3d011682016040523d82523d6000602084013e6114fa565b606091505b5091509150811580611536575080516020148015611536575080806020019051602081101561152857600080fd5b50516001600160a01b031633145b8061154057503330145b61154957600080fd5b611551611192565b1561155b57600080fd5b6115648b61242d565b61156d8a61271d565b6115a160008a6003806020026040519081016040528092919082600360200280828437600092019190915250612787915050565b6040805180820182526115d091600091908b9060029083908390808284376000920191909152506128db915050565b6115d9876129ca565b6115e286612a2b565b6115eb85612af3565b6115f58585612b39565b611600846012612c34565b611608612db8565b611610611192565b9b9a5050505050505050505050565b60008061162b83610daf565b9050600061163884611fbd565b9050600061164885610ed3611239565b9050600081831161165a57600061165e565b8183035b905080841061166d578061166f565b835b9695505050505050565b6116816121dd565b61168a82611026565b61169357600080fd5b61169c82610f6e565b8111806116a7575080155b6116b057600080fd5b6040805172195e1958dd5d1a5bdb91185a5b1e531a5b5a5d606a1b6020808301919091526001600160601b0319606086901b16603383015282516027818403018152604783018085528151918301919091206000908152918290529083902084905583905290516001600160a01b038416917f4c177b42dbe934b3abbc0208c11a42e46589983431616f1710ab19969c5ed62e919081900360670190a25050565b611759612204565b611762846125ae565b6000611771856001868661250a565b9050610f6784868385612e0f565b7f98aa806e31e94a687a31c65769cb99670064dd7f5a87526da075c5fb4eab988060005260026020527f0c1206883be66049a02d4937078367c00b3d71dd1a9465df969363c6ddeac96d546001600160a01b031690565b7f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c060005260026020527fb7802e97e87ef2842a6cce7da7ffaeaedaa2f61a6a7870b23d9d01fc9b73712e546001600160a01b031690565b6000611837611cc3565b9050806001600160a01b031663cb08a10c836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561187d57600080fd5b505afa158015611891573d6000803e3d6000fd5b505050506040513d60208110156118a757600080fd5b5051156118b357600080fd5b306001600160a01b0316816001600160a01b0316633f9a8e7e846040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561190157600080fd5b505afa158015611915573d6000803e3d6000fd5b505050506040513d602081101561192b57600080fd5b50516001600160a01b03161461194057600080fd5b61194861177f565b6001600160a01b0316816001600160a01b0316634a610b04846040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561199557600080fd5b505afa1580156119a9573d6000803e3d6000fd5b505050506040513d60208110156119bf57600080fd5b50516001600160a01b0316146119d457600080fd5b6040805160248082018590528251808303909101815260449091019091526020810180516001600160e01b0316630950d51560e01b90811790915290610f6781612f7c565b6003806000909192565b60408051670dad2dca0cae4a8f60c31b60208083019190915260609390931b6001600160601b03191660288201528151808203601c018152603c909101825280519083012060009081529182905290205490565b600080516020613f9983398151915260009081526002602052600080516020613f79833981519152546001600160a01b0316611ab2336112ff565b6001600160a01b031614611ac557600080fd5b611acd613086565b611b205760408051600081526020810190915282518590601411611b1057611af4846130ab565b9050601484511115611b10578351601319016014850190815291505b611b1d33878388866130b2565b50505b5060019392505050565b604080516f746f74616c5370656e7450657244617960801b60208083019190915260609490941b6001600160601b031916603082015260448082019390935281518082039093018352606401815281519183019190912060009081529182905290205490565b611b9e838383600080610cdb565b505050565b604080516861636b4465706c6f7960b81b60208083019190915260609390931b6001600160601b03191660298201528151808203601d018152603d90910182528051908301206000908152600490925290205460ff1690565b7f2dfd6c9f781bb6bbb5369c114e949b69ebb440ef3d4dd6b2836225eb1dc3a2be60009081526020527f2de0d2cdc19d356cb53b5984f91bfd3b31fe0c678a0d190a6db39274bb34753f5490565b6000611c5582611026565b8015610f2d57506000611c67836112ff565b6001600160a01b03161492915050565b611c7f612204565b6000611c8a8561112c565b9050611c9581611026565b611c9e57600080fd5b6000611cad826000878761250a565b9050611cbb85838386612e0f565b505050505050565b7f811bbb11e8899da471f0e69a3ed55090fc90215227fc5fb1cb0d6e962ea7b74f60005260026020527fb4ed64697d3ef8518241966f7c6f28b0d72f20f51198717d198d2d55076c593d546001600160a01b031690565b611d2261266a565b806001600160a01b038116611d3657600080fd5b611d3f83611c4a565b611d4857600080fd5b6000611d5384613134565b905060008111611d6257600080fd5b6000611d6d8561161f565b905060008111611d7c57600080fd5b80821115611d88578091505b611d9a85611d94611239565b84613188565b60408051600080825260208201909252606091611dbc91889088908790613206565b90506000611dc982612f7c565b90506113e481888887613524565b611ddf6121dd565b610ebd81612af3565b61105784848484612046565b611dfc6121dd565b611e0582611026565b611e0e57600080fd5b801580611e345750611e1f82611a23565b81118015611e345750611e3182611fbd565b81105b611e3d57600080fd5b60408051670dac2f0a0cae4a8f60c31b60208083019190915260609490941b6001600160601b03191660288201528151808203601c018152603c909101825280519084012060009081529283905290912055565b611e996121dd565b611ea282611026565b611eab57600080fd5b600081118015611ec25750611ebf82611fbd565b81105b8015611ed55750611ed282610daf565b81105b611ede57600080fd5b60408051670dad2dca0cae4a8f60c31b60208083019190915260609490941b6001600160601b03191660288201528151808203601c018152603c909101825280519084012060009081529283905290912055565b6040805172746f74616c457865637574656450657244617960681b60208083019190915260609490941b6001600160601b031916603382015260478082019390935281518082039093018352606701815281519183019190912060009081529182905290205490565b611fa36121dd565b610ebd81612a2b565b611fb46121dd565b610ebd816129ca565b604080516919185a5b1e531a5b5a5d60b21b60208083019190915260609390931b6001600160601b031916602a8201528151808203601e018152603e909101825280519083012060009081529182905290205490565b600080516020613f998339815191526000526002602052600080516020613f79833981519152546001600160a01b031690565b600080516020613f998339815191526000526002602052600080516020613f79833981519152546001600160a01b0385811691161461208457600080fd5b61208c613086565b1561209657600080fd5b6000846001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156120e557600080fd5b505afa1580156120f9573d6000803e3d6000fd5b505050506040513d602081101561210f57600080fd5b5051905061211d6001613594565b6121326001600160a01b0386163330866135b8565b61213c6000613594565b60006121c182876001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561218f57600080fd5b505afa1580156121a3573d6000803e3d6000fd5b505050506040513d60208110156121b957600080fd5b505190613612565b9050838111156121d057600080fd5b611cbb86338784876130b2565b6121e56117d6565b6001600160a01b0316336001600160a01b03161461220257600080fd5b565b600061220e611cc3565b9050336001600160a01b0382161461222557600080fd5b61222d61177f565b6001600160a01b0316816001600160a01b031663d67bdd256040518163ffffffff1660e01b815260040160206040518083038186803b15801561226f57600080fd5b505afa158015612283573d6000803e3d6000fd5b505050506040513d602081101561229957600080fd5b50516001600160a01b031614610ebd57600080fd5b604080516b36b2b9b9b0b3b2aa37b5b2b760a11b602080830191909152602c80830185905283518084039091018152604c90920183528151918101919091206000908152600290915220546001600160a01b0316919050565b604080516f1b595cdcd859d9549958da5c1a595b9d60821b602080830191909152603080830185905283518084039091018152605090920183528151918101919091206000908152600290915220546001600160a01b0316919050565b604080516b6d65737361676556616c756560a01b602080830191909152602c80830185905283518084039091018152604c90920183528151918101919091206000908152908190522054919050565b604080516b1b595cdcd859d9519a5e195960a21b602080830191909152602c8083019490945282518083039094018452604c9091018252825192810192909220600090815260049092529020805460ff19166001179055565b611b9e600061241a856112ff565b6001600160a01b03161484848485613654565b612436816136a8565b61243f57600080fd5b7f811bbb11e8899da471f0e69a3ed55090fc90215227fc5fb1cb0d6e962ea7b74f60005260026020527fb4ed64697d3ef8518241966f7c6f28b0d72f20f51198717d198d2d55076c593d80546001600160a01b0319166001600160a01b0392909216919091179055565b600082820183811015612503576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6000612514613086565b1561251e57600080fd5b61252885836111e3565b61253157600080fd5b6125438561253d611239565b846136e1565b6125508486858586613654565b612558613762565b836001600160a01b0316866001600160a01b03167f9afd47907e25028cdaca89d193518c302bbb128617d5a992c5abd45815526593856040518082815260200191505060405180910390a450805b949350505050565b604080516861636b4465706c6f7960b81b6020808301919091526001600160601b0319606085901b1660298301528251601d818403018152603d909201835281519181019190912060009081526004909152205460ff16610ebd57604080516861636b4465706c6f7960b81b6020808301919091526001600160601b0319606085901b1660298301528251601d818403018152603d90920183528151918101919091206000908152600490915220805460ff1916600117905550565b306001600160a01b0316636fde82026040518163ffffffff1660e01b815260040160206040518083038186803b1580156126a357600080fd5b505afa1580156126b7573d6000803e3d6000fd5b505050506040513d60208110156126cd57600080fd5b50516001600160a01b0316331461220257600080fd5b806001600160a01b0381166126f757600080fd5b6001600160a01b0383166127135761270e826137d5565b611b9e565b611b9e83836137e0565b7f98aa806e31e94a687a31c65769cb99670064dd7f5a87526da075c5fb4eab988060005260026020527f0c1206883be66049a02d4937078367c00b3d71dd1a9465df969363c6ddeac96d80546001600160a01b0319166001600160a01b0392909216919091179055565b6040810151158015906127a1575060408101516020820151115b80156127b1575060208101518151115b6127ba57600080fd5b8051604080516919185a5b1e531a5b5a5d60b21b602082810191909152606086901b6001600160601b031916602a83018190528351808403601e018152603e8401855280519083012060009081528083528481209590955581860151670dac2f0a0cae4a8f60c31b605e850152606684018290528451605a818603018152607a8501865280519084012086528583528486205583860151670dad2dca0cae4a8f60c31b609a85015260a28401919091528351609681850301815260b690930184528251928201929092208452839052908220556001600160a01b038316907fca0b3dabefdbd8c72c0a9cf4a6e9d107da897abf036ef3f3f3b010cdd25941599083905b60200201516040518082815260200191505060405180910390a25050565b80516020820151106128ec57600080fd5b80516040805172195e1958dd5d1a5bdb91185a5b1e531a5b5a5d606a1b602082810191909152606086901b6001600160601b031916603383018190528351808403602701815260478401855280519083012060009081528083528481209590955581860151700caf0cac6eae8d2dedc9ac2f0a0cae4a8f607b1b606785015260788401919091528351606c818503018152608c90930184528251928201929092208452839052908220556001600160a01b038316907f4c177b42dbe934b3abbc0208c11a42e46589983431616f1710ab19969c5ed62e9083906128bd565b6129d261386d565b8111156129de57600080fd5b7f2dfd6c9f781bb6bbb5369c114e949b69ebb440ef3d4dd6b2836225eb1dc3a2be60009081526020527f2de0d2cdc19d356cb53b5984f91bfd3b31fe0c678a0d190a6db39274bb34753f55565b6001600160a01b038116612a3e57600080fd5b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0612a676117d6565b604080516001600160a01b03928316815291841660208301528051918290030190a17f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c060005260026020527fb7802e97e87ef2842a6cce7da7ffaeaedaa2f61a6a7870b23d9d01fc9b73712e80546001600160a01b0319166001600160a01b0392909216919091179055565b600080516020613f998339815191526000526002602052600080516020613f7983398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b604080516f686f6d65546f6b656e4164647265737360801b6020808301919091526001600160601b0319606086811b82166030850152845160248186030181526044850186528051908401206000908152600280855286822080546001600160a01b03808b166001600160a01b0319928316811790935572666f726569676e546f6b656e4164647265737360681b60648a0152948a901b90951660778801528751606b818903018152608b909701808952875197870197909720835294529485208054909216908716908117909155909290917f78d063210f4fb6b4cc932390bb8045fa2465e51349590182dab8b9e84c57a6ee9190a35050565b60006012821015612d285781601203600a0a90506000612c5e82612c586000611a23565b906138af565b90506000612c7083612c586000610daf565b90506000612c8284612c586000611fbd565b90506000612c9485612c586000610f6e565b90506000612ca686612c586000611242565b905084612cdc5760019450848411612cdc5760649350606491508383111580612ccf5750818111155b15612cdc57506127109150815b612d0088604051806060016040528086815260200187815260200188815250612787565b612d1e886040518060400160405280848152602001858152506128db565b5050505050611b9e565b60128203600a0a9050612d81836040518060600160405280612d5485612d4e6000611fbd565b906138f1565b8152602001612d6785612d4e6000610daf565b8152602001612d7a85612d4e6000611a23565b9052612787565b611b9e836040518060400160405280612d9e85612d4e6000611242565b8152602001612db185612d4e6000610f6e565b90526128db565b7f0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba60005260046020527f078d888f9b66f3f8bfa10909e31f1e16240db73449f0500afdbbe3a70da457cc805460ff19166001179055565b612e18846136a8565b1561105757836001600160a01b031663db7af85460e01b84848460405160240180846001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015612e87578181015183820152602001612e6f565b50505050905090810190601f168015612eb45780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990991698909817885251815191979096508695509350915081905083835b60208310612f1a5780518252601f199092019160209182019101612efb565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146113e4576040519150601f19603f3d011682016040523d82523d6000602084013e6113e4565b6000612f86611cc3565b6001600160a01b031663dc8601b3612f9c61177f565b84612fa5611bfc565b6040518463ffffffff1660e01b815260040180846001600160a01b0316815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b83811015613006578181015183820152602001612fee565b50505050905090810190601f1680156130335780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600087803b15801561305457600080fd5b505af1158015613068573d6000803e3d6000fd5b505050506040513d602081101561307e57600080fd5b505192915050565b7f6168652c307c1e813ca11cfb3a601f1cf3b22452021a5052d8b05f1f1f8a3e925490565b6014015190565b6001600160a01b038316158015906130e357506130cd61177f565b6001600160a01b0316836001600160a01b031614155b6130ec57600080fd5b6130f585611026565b6130fe57600080fd5b6131088583610ec0565b61311157600080fd5b61311d85611d94611239565b6060611dbc61312b876112ff565b87868686613206565b6000610f2d61314283610fcb565b604080516370a0823160e01b815230600482015290516001600160a01b038616916370a08231916024808301926020929190829003018186803b15801561218f57600080fd5b61319681610ed88585611b2a565b600080858560405160200180806f746f74616c5370656e7450657244617960801b815250601001836001600160a01b031660601b81526014018281526020019250505060405160208183030381529060405280519060200120815260200190815260200160002081905550505050565b60606000808351118061322b57506000356001600160e01b03191663d740548160e01b145b90506001600160a01b038716613389576132518661324c86610ed88a610fcb565b61394a565b806132aa57604080516001600160a01b0380891660248301528716604482015260648082018790528251808303909101815260849091019091526020810180516001600160e01b031663125e4cfb60e01b179052613381565b63c534576160e01b8686868660405160240180856001600160a01b03168152602001846001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561331a578181015183820152602001613302565b50505050905090810190601f1680156133475780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909916989098179097525050505050505b91505061351b565b856001600160a01b03166342966c68856040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156133cf57600080fd5b505af11580156133e3573d6000803e3d6000fd5b505050508061344057604080516001600160a01b03808a1660248301528716604482015260648082018790528251808303909101815260849091019091526020810180516001600160e01b031663272255bb60e01b179052613517565b63867f7a4d60e01b8786868660405160240180856001600160a01b03168152602001846001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b838110156134b0578181015183820152602001613498565b50505050905090810190601f1680156134dd5780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909916989098179097525050505050505b9150505b95945050505050565b61352e84846139a5565b6135388483613a11565b6135428482613a81565b83826001600160a01b0316846001600160a01b03167f59a9a8027b9c87b961e254899821c9a276b5efc35d1f7409ea4f291470f1629a846040518082815260200191505060405180910390a450505050565b7f6168652c307c1e813ca11cfb3a601f1cf3b22452021a5052d8b05f1f1f8a3e9255565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611057908590613ad0565b600061250383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613b81565b841561368a5761366e6001600160a01b0385168484613c18565b6136858461324c8361367f88610fcb565b90613612565b610f67565b610f67838361369887613c6a565b6001600160a01b03169190613c6d565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906125a6575050151592915050565b6136ef81610ed88585611f32565b6000808585604051602001808072746f74616c457865637574656450657244617960681b815250601301836001600160a01b031660601b81526014018281526020019250505060405160208183030381529060405280519060200120815260200190815260200160002081905550505050565b600061376c611cc3565b6001600160a01b031663669f618b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156137a457600080fd5b505afa1580156137b8573d6000803e3d6000fd5b505050506040513d60208110156137ce57600080fd5b5051905090565b47610d0c8282613cf9565b604080516370a0823160e01b8152306004820152905183916000916001600160a01b038416916370a08231916024808301926020929190829003018186803b15801561382b57600080fd5b505afa15801561383f573d6000803e3d6000fd5b505050506040513d602081101561385557600080fd5b505190506110576001600160a01b0383168483613c18565b6000613877611cc3565b6001600160a01b031663e5789d036040518163ffffffff1660e01b815260040160206040518083038186803b1580156137a457600080fd5b600061250383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613d5e565b60008261390057506000610f2d565b8282028284828161390d57fe5b04146125035760405162461bcd60e51b8152600401808060200182810382526021815260200180613fb96021913960400191505060405180910390fd5b604080516e6d65646961746f7242616c616e636560881b60208083019190915260609490941b6001600160601b031916602f820152815180820360230181526043909101825280519084012060009081529283905290912055565b604080516b36b2b9b9b0b3b2aa37b5b2b760a11b602080830191909152602c8083019590955282518083039095018552604c90910182528351938101939093206000908152600290935290912080546001600160a01b0319166001600160a01b03909216919091179055565b604080516f1b595cdcd859d9549958da5c1a595b9d60821b60208083019190915260308083019590955282518083039095018552605090910182528351938101939093206000908152600290935290912080546001600160a01b0319166001600160a01b03909216919091179055565b604080516b6d65737361676556616c756560a01b602080830191909152602c8083019590955282518083039095018552604c909101825283519381019390932060009081529283905290912055565b6060613b25826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613dc39092919063ffffffff16565b805190915015611b9e57808060200190516020811015613b4457600080fd5b5051611b9e5760405162461bcd60e51b815260040180806020018281038252602a815260200180613fda602a913960400191505060405180910390fd5b60008184841115613c105760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613bd5578181015183820152602001613bbd565b50505050905090810190601f168015613c025780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611b9e908490613ad0565b90565b826001600160a01b03166340c10f1983836040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015613cc457600080fd5b505af1158015613cd8573d6000803e3d6000fd5b505050506040513d6020811015613cee57600080fd5b5051611b9e57600080fd5b6040516001600160a01b0383169082156108fc029083906000818181858888f19350505050610d0c578082604051613d3090613f3a565b6001600160a01b039091168152604051908190036020019082f0905080158015611057573d6000803e3d6000fd5b60008183613dad5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315613bd5578181015183820152602001613bbd565b506000838581613db957fe5b0495945050505050565b60606125a684846000856060613dd8856136a8565b613e29576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b60208310613e685780518252601f199092019160209182019101613e49565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114613eca576040519150601f19603f3d011682016040523d82523d6000602084013e613ecf565b606091505b50915091508115613ee35791506125a69050565b805115613ef35780518082602001fd5b60405162461bcd60e51b8152602060048201818152865160248401528651879391928392604401919085019080838360008315613bd5578181015183820152602001613bbd565b603280613f478339019056fe60806040526040516032380380603283398181016040526020811015602357600080fd5b50516001600160a01b038116fffe0fe3ffe150fd185f2ac66d7b8f2d596f69ad58f66b6d6b8baa17e24bb8c19da859d6267c963dfa6f508daa0db28ce48957e9ccaf6be68a72221b89800942bdc7536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a2646970667358221220a64a4711655f37c159532d7668b91728a080adcc9c3d938727804ddf71d98d4164736f6c63430007050033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102d65760003560e01c80637837cf9111610182578063c2173d43116100e9578063db6fff8c116100a2578063f2fde38b1161007c578063f2fde38b14610c60578063f3b8379114610c86578063f3f5141514610ca3578063f65c614a14610cc9576102d6565b8063db6fff8c14610bdc578063ec47de2a14610c08578063f2c54fe814610c34576102d6565b8063c2173d43146109d2578063c5345761146109f8578063cd59658314610abc578063d0342acd14610ac4578063d474e37a14610af2578063d740548114610b18576102d6565b8063a4b1c2431161013b578063a4b1c24314610863578063a4c0ed3614610889578063ab3a25d914610942578063ad58bdd11461096e578063ae813e9f146109a4578063be3b625b146109ca576102d6565b80637837cf9114610712578063867f7a4d1461073e578063871c0760146108025780638da5cb5b1461080a5780639a4a4395146108125780639cb7595a1461082f576102d6565b80632d70061f1161024157806359339982116101fa57806369ffa08a116101d457806369ffa08a1461063e5780636e5d6bea1461066c578063759c82a8146106925780637610722f146106ec576102d6565b806359339982146105c357806361c04f84146105e057806364696f9714610606576102d6565b80632d70061f146104fa578063392e53cd1461053c5780633a50bc87146105445780633e6968b61461057057806340f8dd8614610578578063437764df1461059e576102d6565b8063125e4cfb11610293578063125e4cfb146103f057806316ef191314610426578063194153d31461044c57806326aa101f14610472578063272255bb146104985780632803212f146104ce576102d6565b806301e4f53a146102db57806301fcc1d314610309578063032f693f146103355780630950d5151461036d5780630b26cf661461038a57806310775238146103b0575b600080fd5b610307600480360360408110156102f157600080fd5b506001600160a01b038135169060200135610cd1565b005b6103076004803603604081101561031f57600080fd5b506001600160a01b038135169060200135610d10565b61035b6004803603602081101561034b57600080fd5b50356001600160a01b0316610daf565b60408051918252519081900360200190f35b6103076004803603602081101561038357600080fd5b5035610e03565b610307600480360360208110156103a057600080fd5b50356001600160a01b0316610eac565b6103dc600480360360408110156103c657600080fd5b506001600160a01b038135169060200135610ec0565b604080519115158252519081900360200190f35b6103076004803603606081101561040657600080fd5b506001600160a01b03813581169160208101359091169060400135610f33565b61035b6004803603602081101561043c57600080fd5b50356001600160a01b0316610f6e565b61035b6004803603602081101561046257600080fd5b50356001600160a01b0316610fcb565b6103dc6004803603602081101561048857600080fd5b50356001600160a01b0316611026565b610307600480360360608110156104ae57600080fd5b506001600160a01b03813581169160208101359091169060400135611039565b610307600480360360408110156104e457600080fd5b506001600160a01b03813516906020013561105d565b6105206004803603602081101561051057600080fd5b50356001600160a01b031661112c565b604080516001600160a01b039092168252519081900360200190f35b6103dc611192565b6103dc6004803603604081101561055a57600080fd5b506001600160a01b0381351690602001356111e3565b61035b611239565b61035b6004803603602081101561058e57600080fd5b50356001600160a01b0316611242565b6105a66112a1565b604080516001600160e01b03199092168252519081900360200190f35b6103dc600480360360208110156105d957600080fd5b50356112ac565b610520600480360360208110156105f657600080fd5b50356001600160a01b03166112ff565b6103076004803603606081101561061c57600080fd5b506001600160a01b038135811691602081013582169160409091013516611368565b6103076004803603604081101561065457600080fd5b506001600160a01b03813581169160200135166113ed565b6103076004803603602081101561068257600080fd5b50356001600160a01b0316611424565b6103dc60048036036101608110156106a957600080fd5b506001600160a01b0381358116916020810135821691604082019160a081019160e082013591610100810135821691610120820135811691610140013516611435565b61035b6004803603602081101561070257600080fd5b50356001600160a01b031661161f565b6103076004803603604081101561072857600080fd5b506001600160a01b038135169060200135611679565b6103076004803603608081101561075457600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b81111561078e57600080fd5b8201836020820111156107a057600080fd5b803590602001918460018302840111600160201b831117156107c157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611751945050505050565b61052061177f565b6105206117d6565b6103076004803603602081101561082857600080fd5b503561182d565b610837611a19565b6040805167ffffffffffffffff9485168152928416602084015292168183015290519081900360600190f35b61035b6004803603602081101561087957600080fd5b50356001600160a01b0316611a23565b6103dc6004803603606081101561089f57600080fd5b6001600160a01b0382351691602081013591810190606081016040820135600160201b8111156108ce57600080fd5b8201836020820111156108e057600080fd5b803590602001918460018302840111600160201b8311171561090157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611a77945050505050565b61035b6004803603604081101561095857600080fd5b506001600160a01b038135169060200135611b2a565b6103076004803603606081101561098457600080fd5b506001600160a01b03813581169160208101359091169060400135611b90565b6103dc600480360360208110156109ba57600080fd5b50356001600160a01b0316611ba3565b61035b611bfc565b6103dc600480360360208110156109e857600080fd5b50356001600160a01b0316611c4a565b61030760048036036080811015610a0e57600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b811115610a4857600080fd5b820183602082011115610a5a57600080fd5b803590602001918460018302840111600160201b83111715610a7b57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611c77945050505050565b610520611cc3565b61030760048036036040811015610ada57600080fd5b506001600160a01b0381358116916020013516611d1a565b61030760048036036020811015610b0857600080fd5b50356001600160a01b0316611dd7565b61030760048036036080811015610b2e57600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b811115610b6857600080fd5b820183602082011115610b7a57600080fd5b803590602001918460018302840111600160201b83111715610b9b57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611de8945050505050565b61030760048036036040811015610bf257600080fd5b506001600160a01b038135169060200135611df4565b61030760048036036040811015610c1e57600080fd5b506001600160a01b038135169060200135611e91565b61035b60048036036040811015610c4a57600080fd5b506001600160a01b038135169060200135611f32565b61030760048036036020811015610c7657600080fd5b50356001600160a01b0316611f9b565b61030760048036036020811015610c9c57600080fd5b5035611fac565b61035b60048036036020811015610cb957600080fd5b50356001600160a01b0316611fbd565b610520612013565b610d0c8233836000805b506040519080825280601f01601f191660200182016040528015610d06576020820181803683370190505b50612046565b5050565b610d186121dd565b610d2182611026565b610d2a57600080fd5b801580610d495750600081118015610d495750610d4682611242565b81105b610d5257600080fd5b60408051700caf0cac6eae8d2dedc9ac2f0a0cae4a8f607b1b60208083019190915260609490941b6001600160601b0319166031820152815180820360250181526045909101825280519084012060009081529283905290912055565b60408051670dac2f0a0cae4a8f60c31b60208083019190915260609390931b6001600160601b03191660288201528151808203601c018152603c909101825280519083012060009081529182905290205490565b610e0b612204565b610e14816112ac565b15610e1e57600080fd5b6000610e29826122ae565b90506000610e3683612307565b90506000610e4384612364565b9050610e4e846123b3565b610e5983838361240c565b604080516001600160a01b03808616825284166020820152808201839052905185917f07b5483b8e4bd8ea240a474d5117738350e7d431e3668c48a97910b0b397796a919081900360600190a250505050565b610eb46121dd565b610ebd8161242d565b50565b600080610ede83610ed886610ed3611239565b611b2a565b906124a9565b90506000610eec6000611fbd565b118015610f01575080610efe85611fbd565b10155b8015610f155750610f1184610daf565b8311155b8015610f295750610f2584611a23565b8310155b9150505b92915050565b610f3b612204565b6000610f468461112c565b9050610f5181611026565b610f5a57600080fd5b610f67816000858561250a565b5050505050565b60408051700caf0cac6eae8d2dedc9ac2f0a0cae4a8f607b1b60208083019190915260609390931b6001600160601b0319166031820152815180820360250181526045909101825280519083012060009081529182905290205490565b604080516e6d65646961746f7242616c616e636560881b60208083019190915260609390931b6001600160601b031916602f820152815180820360230181526043909101825280519083012060009081529182905290205490565b60008061103283611a23565b1192915050565b611041612204565b61104a836125ae565b611057836001848461250a565b50505050565b6110656121dd565b61106e82611026565b61107757600080fd5b61108082610daf565b81118061108b575080155b61109457600080fd5b604080516919185a5b1e531a5b5a5d60b21b6020808301919091526001600160601b0319606086901b16602a8301528251601e818403018152603e83018085528151918301919091206000908152918290529083902084905583905290516001600160a01b038416917fca0b3dabefdbd8c72c0a9cf4a6e9d107da897abf036ef3f3f3b010cdd25941599190819003605e0190a25050565b604080516f686f6d65546f6b656e4164647265737360801b60208083019190915260609390931b6001600160601b03191660308201528151808203602401815260449091018252805190830120600090815260029092529020546001600160a01b031690565b7f0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba60005260046020527f078d888f9b66f3f8bfa10909e31f1e16240db73449f0500afdbbe3a70da457cc5460ff1690565b6000806111fb83610ed8866111f6611239565b611f32565b905060006112096000611242565b11801561121e57508061121b85611242565b10155b8015610f29575061122e84610f6e565b909211159392505050565b62015180420490565b6040805172195e1958dd5d1a5bdb91185a5b1e531a5b5a5d606a1b60208083019190915260609390931b6001600160601b0319166033820152815180820360270181526047909101825280519083012060009081529182905290205490565b6358a8b61360e11b90565b604080516b1b595cdcd859d9519a5e195960a21b602080830191909152602c80830185905283518084039091018152604c909201835281519181019190912060009081526004909152205460ff16919050565b6040805172666f726569676e546f6b656e4164647265737360681b60208083019190915260609390931b6001600160601b03191660338201528151808203602701815260479091018252805190830120600090815260029092529020546001600160a01b031690565b61137061266a565b826001600160a01b03166369ffa08a83836040518363ffffffff1660e01b815260040180836001600160a01b03168152602001826001600160a01b0316815260200192505050600060405180830381600087803b1580156113d057600080fd5b505af11580156113e4573d6000803e3d6000fd5b50505050505050565b6113f561266a565b6001600160a01b0382161580611411575061140f82611026565b155b61141a57600080fd5b610d0c82826126e3565b61142c6121dd565b610ebd8161271d565b60408051600481526024810182526020810180516001600160e01b03166337ef410160e11b1781529151815160009384936060933093919290918291908083835b602083106114955780518252601f199092019160209182019101611476565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146114f5576040519150601f19603f3d011682016040523d82523d6000602084013e6114fa565b606091505b5091509150811580611536575080516020148015611536575080806020019051602081101561152857600080fd5b50516001600160a01b031633145b8061154057503330145b61154957600080fd5b611551611192565b1561155b57600080fd5b6115648b61242d565b61156d8a61271d565b6115a160008a6003806020026040519081016040528092919082600360200280828437600092019190915250612787915050565b6040805180820182526115d091600091908b9060029083908390808284376000920191909152506128db915050565b6115d9876129ca565b6115e286612a2b565b6115eb85612af3565b6115f58585612b39565b611600846012612c34565b611608612db8565b611610611192565b9b9a5050505050505050505050565b60008061162b83610daf565b9050600061163884611fbd565b9050600061164885610ed3611239565b9050600081831161165a57600061165e565b8183035b905080841061166d578061166f565b835b9695505050505050565b6116816121dd565b61168a82611026565b61169357600080fd5b61169c82610f6e565b8111806116a7575080155b6116b057600080fd5b6040805172195e1958dd5d1a5bdb91185a5b1e531a5b5a5d606a1b6020808301919091526001600160601b0319606086901b16603383015282516027818403018152604783018085528151918301919091206000908152918290529083902084905583905290516001600160a01b038416917f4c177b42dbe934b3abbc0208c11a42e46589983431616f1710ab19969c5ed62e919081900360670190a25050565b611759612204565b611762846125ae565b6000611771856001868661250a565b9050610f6784868385612e0f565b7f98aa806e31e94a687a31c65769cb99670064dd7f5a87526da075c5fb4eab988060005260026020527f0c1206883be66049a02d4937078367c00b3d71dd1a9465df969363c6ddeac96d546001600160a01b031690565b7f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c060005260026020527fb7802e97e87ef2842a6cce7da7ffaeaedaa2f61a6a7870b23d9d01fc9b73712e546001600160a01b031690565b6000611837611cc3565b9050806001600160a01b031663cb08a10c836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561187d57600080fd5b505afa158015611891573d6000803e3d6000fd5b505050506040513d60208110156118a757600080fd5b5051156118b357600080fd5b306001600160a01b0316816001600160a01b0316633f9a8e7e846040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561190157600080fd5b505afa158015611915573d6000803e3d6000fd5b505050506040513d602081101561192b57600080fd5b50516001600160a01b03161461194057600080fd5b61194861177f565b6001600160a01b0316816001600160a01b0316634a610b04846040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561199557600080fd5b505afa1580156119a9573d6000803e3d6000fd5b505050506040513d60208110156119bf57600080fd5b50516001600160a01b0316146119d457600080fd5b6040805160248082018590528251808303909101815260449091019091526020810180516001600160e01b0316630950d51560e01b90811790915290610f6781612f7c565b6003806000909192565b60408051670dad2dca0cae4a8f60c31b60208083019190915260609390931b6001600160601b03191660288201528151808203601c018152603c909101825280519083012060009081529182905290205490565b600080516020613f9983398151915260009081526002602052600080516020613f79833981519152546001600160a01b0316611ab2336112ff565b6001600160a01b031614611ac557600080fd5b611acd613086565b611b205760408051600081526020810190915282518590601411611b1057611af4846130ab565b9050601484511115611b10578351601319016014850190815291505b611b1d33878388866130b2565b50505b5060019392505050565b604080516f746f74616c5370656e7450657244617960801b60208083019190915260609490941b6001600160601b031916603082015260448082019390935281518082039093018352606401815281519183019190912060009081529182905290205490565b611b9e838383600080610cdb565b505050565b604080516861636b4465706c6f7960b81b60208083019190915260609390931b6001600160601b03191660298201528151808203601d018152603d90910182528051908301206000908152600490925290205460ff1690565b7f2dfd6c9f781bb6bbb5369c114e949b69ebb440ef3d4dd6b2836225eb1dc3a2be60009081526020527f2de0d2cdc19d356cb53b5984f91bfd3b31fe0c678a0d190a6db39274bb34753f5490565b6000611c5582611026565b8015610f2d57506000611c67836112ff565b6001600160a01b03161492915050565b611c7f612204565b6000611c8a8561112c565b9050611c9581611026565b611c9e57600080fd5b6000611cad826000878761250a565b9050611cbb85838386612e0f565b505050505050565b7f811bbb11e8899da471f0e69a3ed55090fc90215227fc5fb1cb0d6e962ea7b74f60005260026020527fb4ed64697d3ef8518241966f7c6f28b0d72f20f51198717d198d2d55076c593d546001600160a01b031690565b611d2261266a565b806001600160a01b038116611d3657600080fd5b611d3f83611c4a565b611d4857600080fd5b6000611d5384613134565b905060008111611d6257600080fd5b6000611d6d8561161f565b905060008111611d7c57600080fd5b80821115611d88578091505b611d9a85611d94611239565b84613188565b60408051600080825260208201909252606091611dbc91889088908790613206565b90506000611dc982612f7c565b90506113e481888887613524565b611ddf6121dd565b610ebd81612af3565b61105784848484612046565b611dfc6121dd565b611e0582611026565b611e0e57600080fd5b801580611e345750611e1f82611a23565b81118015611e345750611e3182611fbd565b81105b611e3d57600080fd5b60408051670dac2f0a0cae4a8f60c31b60208083019190915260609490941b6001600160601b03191660288201528151808203601c018152603c909101825280519084012060009081529283905290912055565b611e996121dd565b611ea282611026565b611eab57600080fd5b600081118015611ec25750611ebf82611fbd565b81105b8015611ed55750611ed282610daf565b81105b611ede57600080fd5b60408051670dad2dca0cae4a8f60c31b60208083019190915260609490941b6001600160601b03191660288201528151808203601c018152603c909101825280519084012060009081529283905290912055565b6040805172746f74616c457865637574656450657244617960681b60208083019190915260609490941b6001600160601b031916603382015260478082019390935281518082039093018352606701815281519183019190912060009081529182905290205490565b611fa36121dd565b610ebd81612a2b565b611fb46121dd565b610ebd816129ca565b604080516919185a5b1e531a5b5a5d60b21b60208083019190915260609390931b6001600160601b031916602a8201528151808203601e018152603e909101825280519083012060009081529182905290205490565b600080516020613f998339815191526000526002602052600080516020613f79833981519152546001600160a01b031690565b600080516020613f998339815191526000526002602052600080516020613f79833981519152546001600160a01b0385811691161461208457600080fd5b61208c613086565b1561209657600080fd5b6000846001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156120e557600080fd5b505afa1580156120f9573d6000803e3d6000fd5b505050506040513d602081101561210f57600080fd5b5051905061211d6001613594565b6121326001600160a01b0386163330866135b8565b61213c6000613594565b60006121c182876001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561218f57600080fd5b505afa1580156121a3573d6000803e3d6000fd5b505050506040513d60208110156121b957600080fd5b505190613612565b9050838111156121d057600080fd5b611cbb86338784876130b2565b6121e56117d6565b6001600160a01b0316336001600160a01b03161461220257600080fd5b565b600061220e611cc3565b9050336001600160a01b0382161461222557600080fd5b61222d61177f565b6001600160a01b0316816001600160a01b031663d67bdd256040518163ffffffff1660e01b815260040160206040518083038186803b15801561226f57600080fd5b505afa158015612283573d6000803e3d6000fd5b505050506040513d602081101561229957600080fd5b50516001600160a01b031614610ebd57600080fd5b604080516b36b2b9b9b0b3b2aa37b5b2b760a11b602080830191909152602c80830185905283518084039091018152604c90920183528151918101919091206000908152600290915220546001600160a01b0316919050565b604080516f1b595cdcd859d9549958da5c1a595b9d60821b602080830191909152603080830185905283518084039091018152605090920183528151918101919091206000908152600290915220546001600160a01b0316919050565b604080516b6d65737361676556616c756560a01b602080830191909152602c80830185905283518084039091018152604c90920183528151918101919091206000908152908190522054919050565b604080516b1b595cdcd859d9519a5e195960a21b602080830191909152602c8083019490945282518083039094018452604c9091018252825192810192909220600090815260049092529020805460ff19166001179055565b611b9e600061241a856112ff565b6001600160a01b03161484848485613654565b612436816136a8565b61243f57600080fd5b7f811bbb11e8899da471f0e69a3ed55090fc90215227fc5fb1cb0d6e962ea7b74f60005260026020527fb4ed64697d3ef8518241966f7c6f28b0d72f20f51198717d198d2d55076c593d80546001600160a01b0319166001600160a01b0392909216919091179055565b600082820183811015612503576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6000612514613086565b1561251e57600080fd5b61252885836111e3565b61253157600080fd5b6125438561253d611239565b846136e1565b6125508486858586613654565b612558613762565b836001600160a01b0316866001600160a01b03167f9afd47907e25028cdaca89d193518c302bbb128617d5a992c5abd45815526593856040518082815260200191505060405180910390a450805b949350505050565b604080516861636b4465706c6f7960b81b6020808301919091526001600160601b0319606085901b1660298301528251601d818403018152603d909201835281519181019190912060009081526004909152205460ff16610ebd57604080516861636b4465706c6f7960b81b6020808301919091526001600160601b0319606085901b1660298301528251601d818403018152603d90920183528151918101919091206000908152600490915220805460ff1916600117905550565b306001600160a01b0316636fde82026040518163ffffffff1660e01b815260040160206040518083038186803b1580156126a357600080fd5b505afa1580156126b7573d6000803e3d6000fd5b505050506040513d60208110156126cd57600080fd5b50516001600160a01b0316331461220257600080fd5b806001600160a01b0381166126f757600080fd5b6001600160a01b0383166127135761270e826137d5565b611b9e565b611b9e83836137e0565b7f98aa806e31e94a687a31c65769cb99670064dd7f5a87526da075c5fb4eab988060005260026020527f0c1206883be66049a02d4937078367c00b3d71dd1a9465df969363c6ddeac96d80546001600160a01b0319166001600160a01b0392909216919091179055565b6040810151158015906127a1575060408101516020820151115b80156127b1575060208101518151115b6127ba57600080fd5b8051604080516919185a5b1e531a5b5a5d60b21b602082810191909152606086901b6001600160601b031916602a83018190528351808403601e018152603e8401855280519083012060009081528083528481209590955581860151670dac2f0a0cae4a8f60c31b605e850152606684018290528451605a818603018152607a8501865280519084012086528583528486205583860151670dad2dca0cae4a8f60c31b609a85015260a28401919091528351609681850301815260b690930184528251928201929092208452839052908220556001600160a01b038316907fca0b3dabefdbd8c72c0a9cf4a6e9d107da897abf036ef3f3f3b010cdd25941599083905b60200201516040518082815260200191505060405180910390a25050565b80516020820151106128ec57600080fd5b80516040805172195e1958dd5d1a5bdb91185a5b1e531a5b5a5d606a1b602082810191909152606086901b6001600160601b031916603383018190528351808403602701815260478401855280519083012060009081528083528481209590955581860151700caf0cac6eae8d2dedc9ac2f0a0cae4a8f607b1b606785015260788401919091528351606c818503018152608c90930184528251928201929092208452839052908220556001600160a01b038316907f4c177b42dbe934b3abbc0208c11a42e46589983431616f1710ab19969c5ed62e9083906128bd565b6129d261386d565b8111156129de57600080fd5b7f2dfd6c9f781bb6bbb5369c114e949b69ebb440ef3d4dd6b2836225eb1dc3a2be60009081526020527f2de0d2cdc19d356cb53b5984f91bfd3b31fe0c678a0d190a6db39274bb34753f55565b6001600160a01b038116612a3e57600080fd5b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0612a676117d6565b604080516001600160a01b03928316815291841660208301528051918290030190a17f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c060005260026020527fb7802e97e87ef2842a6cce7da7ffaeaedaa2f61a6a7870b23d9d01fc9b73712e80546001600160a01b0319166001600160a01b0392909216919091179055565b600080516020613f998339815191526000526002602052600080516020613f7983398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b604080516f686f6d65546f6b656e4164647265737360801b6020808301919091526001600160601b0319606086811b82166030850152845160248186030181526044850186528051908401206000908152600280855286822080546001600160a01b03808b166001600160a01b0319928316811790935572666f726569676e546f6b656e4164647265737360681b60648a0152948a901b90951660778801528751606b818903018152608b909701808952875197870197909720835294529485208054909216908716908117909155909290917f78d063210f4fb6b4cc932390bb8045fa2465e51349590182dab8b9e84c57a6ee9190a35050565b60006012821015612d285781601203600a0a90506000612c5e82612c586000611a23565b906138af565b90506000612c7083612c586000610daf565b90506000612c8284612c586000611fbd565b90506000612c9485612c586000610f6e565b90506000612ca686612c586000611242565b905084612cdc5760019450848411612cdc5760649350606491508383111580612ccf5750818111155b15612cdc57506127109150815b612d0088604051806060016040528086815260200187815260200188815250612787565b612d1e886040518060400160405280848152602001858152506128db565b5050505050611b9e565b60128203600a0a9050612d81836040518060600160405280612d5485612d4e6000611fbd565b906138f1565b8152602001612d6785612d4e6000610daf565b8152602001612d7a85612d4e6000611a23565b9052612787565b611b9e836040518060400160405280612d9e85612d4e6000611242565b8152602001612db185612d4e6000610f6e565b90526128db565b7f0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba60005260046020527f078d888f9b66f3f8bfa10909e31f1e16240db73449f0500afdbbe3a70da457cc805460ff19166001179055565b612e18846136a8565b1561105757836001600160a01b031663db7af85460e01b84848460405160240180846001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015612e87578181015183820152602001612e6f565b50505050905090810190601f168015612eb45780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990991698909817885251815191979096508695509350915081905083835b60208310612f1a5780518252601f199092019160209182019101612efb565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146113e4576040519150601f19603f3d011682016040523d82523d6000602084013e6113e4565b6000612f86611cc3565b6001600160a01b031663dc8601b3612f9c61177f565b84612fa5611bfc565b6040518463ffffffff1660e01b815260040180846001600160a01b0316815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b83811015613006578181015183820152602001612fee565b50505050905090810190601f1680156130335780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600087803b15801561305457600080fd5b505af1158015613068573d6000803e3d6000fd5b505050506040513d602081101561307e57600080fd5b505192915050565b7f6168652c307c1e813ca11cfb3a601f1cf3b22452021a5052d8b05f1f1f8a3e925490565b6014015190565b6001600160a01b038316158015906130e357506130cd61177f565b6001600160a01b0316836001600160a01b031614155b6130ec57600080fd5b6130f585611026565b6130fe57600080fd5b6131088583610ec0565b61311157600080fd5b61311d85611d94611239565b6060611dbc61312b876112ff565b87868686613206565b6000610f2d61314283610fcb565b604080516370a0823160e01b815230600482015290516001600160a01b038616916370a08231916024808301926020929190829003018186803b15801561218f57600080fd5b61319681610ed88585611b2a565b600080858560405160200180806f746f74616c5370656e7450657244617960801b815250601001836001600160a01b031660601b81526014018281526020019250505060405160208183030381529060405280519060200120815260200190815260200160002081905550505050565b60606000808351118061322b57506000356001600160e01b03191663d740548160e01b145b90506001600160a01b038716613389576132518661324c86610ed88a610fcb565b61394a565b806132aa57604080516001600160a01b0380891660248301528716604482015260648082018790528251808303909101815260849091019091526020810180516001600160e01b031663125e4cfb60e01b179052613381565b63c534576160e01b8686868660405160240180856001600160a01b03168152602001846001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561331a578181015183820152602001613302565b50505050905090810190601f1680156133475780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909916989098179097525050505050505b91505061351b565b856001600160a01b03166342966c68856040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156133cf57600080fd5b505af11580156133e3573d6000803e3d6000fd5b505050508061344057604080516001600160a01b03808a1660248301528716604482015260648082018790528251808303909101815260849091019091526020810180516001600160e01b031663272255bb60e01b179052613517565b63867f7a4d60e01b8786868660405160240180856001600160a01b03168152602001846001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b838110156134b0578181015183820152602001613498565b50505050905090810190601f1680156134dd5780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909916989098179097525050505050505b9150505b95945050505050565b61352e84846139a5565b6135388483613a11565b6135428482613a81565b83826001600160a01b0316846001600160a01b03167f59a9a8027b9c87b961e254899821c9a276b5efc35d1f7409ea4f291470f1629a846040518082815260200191505060405180910390a450505050565b7f6168652c307c1e813ca11cfb3a601f1cf3b22452021a5052d8b05f1f1f8a3e9255565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611057908590613ad0565b600061250383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613b81565b841561368a5761366e6001600160a01b0385168484613c18565b6136858461324c8361367f88610fcb565b90613612565b610f67565b610f67838361369887613c6a565b6001600160a01b03169190613c6d565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906125a6575050151592915050565b6136ef81610ed88585611f32565b6000808585604051602001808072746f74616c457865637574656450657244617960681b815250601301836001600160a01b031660601b81526014018281526020019250505060405160208183030381529060405280519060200120815260200190815260200160002081905550505050565b600061376c611cc3565b6001600160a01b031663669f618b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156137a457600080fd5b505afa1580156137b8573d6000803e3d6000fd5b505050506040513d60208110156137ce57600080fd5b5051905090565b47610d0c8282613cf9565b604080516370a0823160e01b8152306004820152905183916000916001600160a01b038416916370a08231916024808301926020929190829003018186803b15801561382b57600080fd5b505afa15801561383f573d6000803e3d6000fd5b505050506040513d602081101561385557600080fd5b505190506110576001600160a01b0383168483613c18565b6000613877611cc3565b6001600160a01b031663e5789d036040518163ffffffff1660e01b815260040160206040518083038186803b1580156137a457600080fd5b600061250383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613d5e565b60008261390057506000610f2d565b8282028284828161390d57fe5b04146125035760405162461bcd60e51b8152600401808060200182810382526021815260200180613fb96021913960400191505060405180910390fd5b604080516e6d65646961746f7242616c616e636560881b60208083019190915260609490941b6001600160601b031916602f820152815180820360230181526043909101825280519084012060009081529283905290912055565b604080516b36b2b9b9b0b3b2aa37b5b2b760a11b602080830191909152602c8083019590955282518083039095018552604c90910182528351938101939093206000908152600290935290912080546001600160a01b0319166001600160a01b03909216919091179055565b604080516f1b595cdcd859d9549958da5c1a595b9d60821b60208083019190915260308083019590955282518083039095018552605090910182528351938101939093206000908152600290935290912080546001600160a01b0319166001600160a01b03909216919091179055565b604080516b6d65737361676556616c756560a01b602080830191909152602c8083019590955282518083039095018552604c909101825283519381019390932060009081529283905290912055565b6060613b25826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613dc39092919063ffffffff16565b805190915015611b9e57808060200190516020811015613b4457600080fd5b5051611b9e5760405162461bcd60e51b815260040180806020018281038252602a815260200180613fda602a913960400191505060405180910390fd5b60008184841115613c105760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613bd5578181015183820152602001613bbd565b50505050905090810190601f168015613c025780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611b9e908490613ad0565b90565b826001600160a01b03166340c10f1983836040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015613cc457600080fd5b505af1158015613cd8573d6000803e3d6000fd5b505050506040513d6020811015613cee57600080fd5b5051611b9e57600080fd5b6040516001600160a01b0383169082156108fc029083906000818181858888f19350505050610d0c578082604051613d3090613f3a565b6001600160a01b039091168152604051908190036020019082f0905080158015611057573d6000803e3d6000fd5b60008183613dad5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315613bd5578181015183820152602001613bbd565b506000838581613db957fe5b0495945050505050565b60606125a684846000856060613dd8856136a8565b613e29576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b60208310613e685780518252601f199092019160209182019101613e49565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114613eca576040519150601f19603f3d011682016040523d82523d6000602084013e613ecf565b606091505b50915091508115613ee35791506125a69050565b805115613ef35780518082602001fd5b60405162461bcd60e51b8152602060048201818152865160248401528651879391928392604401919085019080838360008315613bd5578181015183820152602001613bbd565b603280613f478339019056fe60806040526040516032380380603283398181016040526020811015602357600080fd5b50516001600160a01b038116fffe0fe3ffe150fd185f2ac66d7b8f2d596f69ad58f66b6d6b8baa17e24bb8c19da859d6267c963dfa6f508daa0db28ce48957e9ccaf6be68a72221b89800942bdc7536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a2646970667358221220a64a4711655f37c159532d7668b91728a080adcc9c3d938727804ddf71d98d4164736f6c63430007050033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.