Contract Address Details
contract
0x3B09067f5FbC8087391f6997ccd83337195eaC05
- Contract Name
- HomeAMBErc677ToErc677
- Creator
- 0xbf3d6f–442b53 at 0xa318d8–6715ae
- Balance
- 0 xDAI ( )
- Tokens
-
Fetching tokens...
- Transactions
- 1 Transactions
- Transfers
- 0 Transfers
- Gas Used
- 31,731
- Last Balance Update
- 23521299
- Contract name:
- HomeAMBErc677ToErc677
- Optimization enabled
- false
- Compiler version
- v0.4.24+commit.e67f0147
- EVM Version
- default
- Verified at
- 2020-06-19T12:14:57.176173Z
Contract source code
// File: contracts/interfaces/IAMB.sol pragma solidity 0.4.24; interface IAMB { 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 _data, uint256 _gas) external returns (bytes32); } // File: contracts/upgradeability/EternalStorage.sol pragma solidity 0.4.24; /** * @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/interfaces/IUpgradeabilityOwnerStorage.sol pragma solidity 0.4.24; interface IUpgradeabilityOwnerStorage { function upgradeabilityOwner() external view returns (address); } // File: contracts/upgradeable_contracts/Ownable.sol pragma solidity 0.4.24; /** * @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() { require(msg.sender == owner()); /* solcov ignore next */ _; } /** * @dev Throws if called by any account other than contract itself or owner. */ modifier onlyRelevantSender() { // proxy owner if used through proxy, address(0) otherwise require( !address(this).call(abi.encodeWithSelector(UPGRADEABILITY_OWNER)) || // covers usage without calling through storage proxy msg.sender == IUpgradeabilityOwnerStorage(this).upgradeabilityOwner() || // covers usage through regular proxy calls msg.sender == address(this) // covers calls through upgradeAndCall proxy method ); /* solcov ignore next */ _; } 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 { require(newOwner != address(0)); setOwner(newOwner); } /** * @dev Sets a new owner address */ function setOwner(address newOwner) internal { emit OwnershipTransferred(owner(), newOwner); addressStorage[OWNER] = newOwner; } } // File: contracts/upgradeable_contracts/Initializable.sol pragma solidity 0.4.24; 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: openzeppelin-solidity/contracts/AddressUtils.sol pragma solidity ^0.4.24; /** * Utility library of inline functions on addresses */ library AddressUtils { /** * Returns whether the target address is a contract * @dev This function will return false if invoked during the constructor of a contract, * as the code is not actually created until after the constructor finishes. * @param _addr address to check * @return whether the target address is a contract */ function isContract(address _addr) internal view returns (bool) { uint256 size; // XXX Currently there is no better way to check if there is a contract in an address // than to check the size of the code at that address. // See https://ethereum.stackexchange.com/a/14016/36603 // for more details about how this works. // TODO Check this again before the Serenity release, because all addresses will be // contracts then. // solium-disable-next-line security/no-inline-assembly assembly { size := extcodesize(_addr) } return size > 0; } } // File: openzeppelin-solidity/contracts/math/SafeMath.sol pragma solidity ^0.4.24; /** * @title SafeMath * @dev Math operations with safety checks that throw on error */ library SafeMath { /** * @dev Multiplies two numbers, throws on overflow. */ function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) { // Gas optimization: this is cheaper than asserting 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (_a == 0) { return 0; } c = _a * _b; assert(c / _a == _b); return c; } /** * @dev Integer division of two numbers, truncating the quotient. */ function div(uint256 _a, uint256 _b) internal pure returns (uint256) { // assert(_b > 0); // Solidity automatically throws when dividing by 0 // uint256 c = _a / _b; // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold return _a / _b; } /** * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 _a, uint256 _b) internal pure returns (uint256) { assert(_b <= _a); return _a - _b; } /** * @dev Adds two numbers, throws on overflow. */ function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) { c = _a + _b; assert(c >= _a); return c; } } // File: contracts/upgradeable_contracts/BasicTokenBridge.sol pragma solidity 0.4.24; contract BasicTokenBridge is EternalStorage, Ownable { using SafeMath for uint256; event DailyLimitChanged(uint256 newLimit); event ExecutionDailyLimitChanged(uint256 newLimit); bytes32 internal constant MIN_PER_TX = 0xbbb088c505d18e049d114c7c91f11724e69c55ad6c5397e2b929e68b41fa05d1; // keccak256(abi.encodePacked("minPerTx")) bytes32 internal constant MAX_PER_TX = 0x0f8803acad17c63ee38bf2de71e1888bc7a079a6f73658e274b08018bea4e29c; // keccak256(abi.encodePacked("maxPerTx")) bytes32 internal constant DAILY_LIMIT = 0x4a6a899679f26b73530d8cf1001e83b6f7702e04b6fdb98f3c62dc7e47e041a5; // keccak256(abi.encodePacked("dailyLimit")) bytes32 internal constant EXECUTION_MAX_PER_TX = 0xc0ed44c192c86d1cc1ba51340b032c2766b4a2b0041031de13c46dd7104888d5; // keccak256(abi.encodePacked("executionMaxPerTx")) bytes32 internal constant EXECUTION_DAILY_LIMIT = 0x21dbcab260e413c20dc13c28b7db95e2b423d1135f42bb8b7d5214a92270d237; // keccak256(abi.encodePacked("executionDailyLimit")) bytes32 internal constant DECIMAL_SHIFT = 0x1e8ecaafaddea96ed9ac6d2642dcdfe1bebe58a930b1085842d8fc122b371ee5; // keccak256(abi.encodePacked("decimalShift")) function totalSpentPerDay(uint256 _day) public view returns (uint256) { return uintStorage[keccak256(abi.encodePacked("totalSpentPerDay", _day))]; } function totalExecutedPerDay(uint256 _day) public view returns (uint256) { return uintStorage[keccak256(abi.encodePacked("totalExecutedPerDay", _day))]; } function dailyLimit() public view returns (uint256) { return uintStorage[DAILY_LIMIT]; } function executionDailyLimit() public view returns (uint256) { return uintStorage[EXECUTION_DAILY_LIMIT]; } function maxPerTx() public view returns (uint256) { return uintStorage[MAX_PER_TX]; } function executionMaxPerTx() public view returns (uint256) { return uintStorage[EXECUTION_MAX_PER_TX]; } function minPerTx() public view returns (uint256) { return uintStorage[MIN_PER_TX]; } function decimalShift() public view returns (uint256) { return uintStorage[DECIMAL_SHIFT]; } function withinLimit(uint256 _amount) public view returns (bool) { uint256 nextLimit = totalSpentPerDay(getCurrentDay()).add(_amount); return dailyLimit() >= nextLimit && _amount <= maxPerTx() && _amount >= minPerTx(); } function withinExecutionLimit(uint256 _amount) public view returns (bool) { uint256 nextLimit = totalExecutedPerDay(getCurrentDay()).add(_amount); return executionDailyLimit() >= nextLimit && _amount <= executionMaxPerTx(); } function getCurrentDay() public view returns (uint256) { // solhint-disable-next-line not-rely-on-time return now / 1 days; } function setTotalSpentPerDay(uint256 _day, uint256 _value) internal { uintStorage[keccak256(abi.encodePacked("totalSpentPerDay", _day))] = _value; } function setTotalExecutedPerDay(uint256 _day, uint256 _value) internal { uintStorage[keccak256(abi.encodePacked("totalExecutedPerDay", _day))] = _value; } function setDailyLimit(uint256 _dailyLimit) external onlyOwner { require(_dailyLimit > maxPerTx() || _dailyLimit == 0); uintStorage[DAILY_LIMIT] = _dailyLimit; emit DailyLimitChanged(_dailyLimit); } function setExecutionDailyLimit(uint256 _dailyLimit) external onlyOwner { require(_dailyLimit > executionMaxPerTx() || _dailyLimit == 0); uintStorage[EXECUTION_DAILY_LIMIT] = _dailyLimit; emit ExecutionDailyLimitChanged(_dailyLimit); } function setExecutionMaxPerTx(uint256 _maxPerTx) external onlyOwner { require(_maxPerTx < executionDailyLimit()); uintStorage[EXECUTION_MAX_PER_TX] = _maxPerTx; } function setMaxPerTx(uint256 _maxPerTx) external onlyOwner { require(_maxPerTx == 0 || (_maxPerTx > minPerTx() && _maxPerTx < dailyLimit())); uintStorage[MAX_PER_TX] = _maxPerTx; } function setMinPerTx(uint256 _minPerTx) external onlyOwner { require(_minPerTx > 0 && _minPerTx < dailyLimit() && _minPerTx < maxPerTx()); uintStorage[MIN_PER_TX] = _minPerTx; } } // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol pragma solidity ^0.4.24; /** * @title ERC20Basic * @dev Simpler version of ERC20 interface * See https://github.com/ethereum/EIPs/issues/179 */ contract ERC20Basic { function totalSupply() public view returns (uint256); function balanceOf(address _who) public view returns (uint256); function transfer(address _to, uint256 _value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol pragma solidity ^0.4.24; /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ contract ERC20 is ERC20Basic { function allowance(address _owner, address _spender) public view returns (uint256); function transferFrom(address _from, address _to, uint256 _value) public returns (bool); function approve(address _spender, uint256 _value) public returns (bool); event Approval( address indexed owner, address indexed spender, uint256 value ); } // File: contracts/interfaces/ERC677.sol pragma solidity 0.4.24; contract ERC677 is ERC20 { event Transfer(address indexed from, address indexed to, uint256 value, bytes data); function transferAndCall(address, uint256, bytes) external returns (bool); function increaseAllowance(address spender, uint256 addedValue) public returns (bool); function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool); } // File: contracts/interfaces/ERC677Receiver.sol pragma solidity 0.4.24; contract ERC677Receiver { function onTokenTransfer(address _from, uint256 _value, bytes _data) external returns (bool); } // File: contracts/upgradeable_contracts/ERC677Storage.sol pragma solidity 0.4.24; contract ERC677Storage { bytes32 internal constant ERC677_TOKEN = 0xa8b0ade3e2b734f043ce298aca4cc8d19d74270223f34531d0988b7d00cba21d; // keccak256(abi.encodePacked("erc677token")) } // File: contracts/libraries/Bytes.sol pragma solidity 0.4.24; /** * @title Bytes * @dev Helper methods to transform bytes to other solidity types. */ library Bytes { /** * @dev Converts bytes array to bytes32. * Truncates bytes array if its size is more than 32 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 32 bytes. * A case when _bytes has length less than 32 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 bytes32 type * @return bytes32 type of the firsts 32 bytes array in parameter. */ function bytesToBytes32(bytes _bytes) internal pure returns (bytes32 result) { assembly { result := mload(add(_bytes, 32)) } } /** * @dev Truncate bytes array if its size is more than 20 bytes. * NOTE: Similar to the bytesToBytes32 function, make sure that _bytes is not shorter than 20 bytes. * @param _bytes to be converted to address type * @return address included in the firsts 20 bytes of the bytes array in parameter. */ function bytesToAddress(bytes _bytes) internal pure returns (address addr) { assembly { addr := mload(add(_bytes, 20)) } } } // File: contracts/upgradeable_contracts/BaseERC677Bridge.sol pragma solidity 0.4.24; contract BaseERC677Bridge is BasicTokenBridge, ERC677Receiver, ERC677Storage { function erc677token() public view returns (ERC677) { return ERC677(addressStorage[ERC677_TOKEN]); } function setErc677token(address _token) internal { require(AddressUtils.isContract(_token)); addressStorage[ERC677_TOKEN] = _token; } function onTokenTransfer(address _from, uint256 _value, bytes _data) external returns (bool) { ERC677 token = erc677token(); require(msg.sender == address(token)); require(withinLimit(_value)); setTotalSpentPerDay(getCurrentDay(), totalSpentPerDay(getCurrentDay()).add(_value)); bridgeSpecificActionsOnTokenTransfer(token, _from, _value, _data); return true; } function chooseReceiver(address _from, bytes _data) internal view returns (address recipient) { recipient = _from; if (_data.length > 0) { require(_data.length == 20); recipient = Bytes.bytesToAddress(_data); require(recipient != address(0)); require(recipient != bridgeContractOnOtherSide()); } } /* solcov ignore next */ function bridgeSpecificActionsOnTokenTransfer(ERC677 _token, address _from, uint256 _value, bytes _data) internal; /* solcov ignore next */ function bridgeContractOnOtherSide() internal view returns (address); } // File: contracts/upgradeable_contracts/BaseOverdrawManagement.sol pragma solidity 0.4.24; contract BaseOverdrawManagement is EternalStorage { event AmountLimitExceeded(address recipient, uint256 value, bytes32 transactionHash); event AssetAboveLimitsFixed(bytes32 indexed transactionHash, uint256 value, uint256 remaining); bytes32 internal constant OUT_OF_LIMIT_AMOUNT = 0x145286dc85799b6fb9fe322391ba2d95683077b2adf34dd576dedc437e537ba7; // keccak256(abi.encodePacked("outOfLimitAmount")) function outOfLimitAmount() public view returns (uint256) { return uintStorage[OUT_OF_LIMIT_AMOUNT]; } function fixedAssets(bytes32 _txHash) public view returns (bool) { return boolStorage[keccak256(abi.encodePacked("fixedAssets", _txHash))]; } function setOutOfLimitAmount(uint256 _value) internal { uintStorage[OUT_OF_LIMIT_AMOUNT] = _value; } function txAboveLimits(bytes32 _txHash) internal view returns (address recipient, uint256 value) { recipient = addressStorage[keccak256(abi.encodePacked("txOutOfLimitRecipient", _txHash))]; value = uintStorage[keccak256(abi.encodePacked("txOutOfLimitValue", _txHash))]; } function setTxAboveLimits(address _recipient, uint256 _value, bytes32 _txHash) internal { addressStorage[keccak256(abi.encodePacked("txOutOfLimitRecipient", _txHash))] = _recipient; setTxAboveLimitsValue(_value, _txHash); } function setTxAboveLimitsValue(uint256 _value, bytes32 _txHash) internal { uintStorage[keccak256(abi.encodePacked("txOutOfLimitValue", _txHash))] = _value; } function setFixedAssets(bytes32 _txHash) internal { boolStorage[keccak256(abi.encodePacked("fixedAssets", _txHash))] = true; } /* solcov ignore next */ function fixAssetsAboveLimits(bytes32 txHash, bool unlockOnForeign, uint256 valueToUnlock) external; } // File: contracts/upgradeable_contracts/ReentrancyGuard.sol pragma solidity 0.4.24; contract ReentrancyGuard is EternalStorage { bytes32 internal constant LOCK = 0x6168652c307c1e813ca11cfb3a601f1cf3b22452021a5052d8b05f1f1f8a3e92; // keccak256(abi.encodePacked("lock")) function lock() internal returns (bool) { return boolStorage[LOCK]; } function setLock(bool _lock) internal { boolStorage[LOCK] = _lock; } } // File: contracts/upgradeable_contracts/Upgradeable.sol pragma solidity 0.4.24; contract Upgradeable { // Avoid using onlyUpgradeabilityOwner name to prevent issues with implementation from proxy contract modifier onlyIfUpgradeabilityOwner() { require(msg.sender == IUpgradeabilityOwnerStorage(this).upgradeabilityOwner()); /* solcov ignore next */ _; } } // File: contracts/upgradeable_contracts/Sacrifice.sol pragma solidity 0.4.24; contract Sacrifice { constructor(address _recipient) public payable { selfdestruct(_recipient); } } // File: contracts/libraries/Address.sol pragma solidity 0.4.24; /** * @title Address * @dev Helper methods for Address type. */ library Address { /** * @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 _receiver, uint256 _value) internal { if (!_receiver.send(_value)) { (new Sacrifice).value(_value)(_receiver); } } } // File: contracts/upgradeable_contracts/Claimable.sol pragma solidity 0.4.24; contract Claimable { bytes4 internal constant TRANSFER = 0xa9059cbb; // transfer(address,uint256) modifier validAddress(address _to) { require(_to != address(0)); /* solcov ignore next */ _; } function claimValues(address _token, address _to) internal { if (_token == address(0)) { claimNativeCoins(_to); } else { claimErc20Tokens(_token, _to); } } function claimNativeCoins(address _to) internal { uint256 value = address(this).balance; Address.safeSendValue(_to, value); } function claimErc20Tokens(address _token, address _to) internal { ERC20Basic token = ERC20Basic(_token); uint256 balance = token.balanceOf(this); safeTransfer(_token, _to, balance); } function safeTransfer(address _token, address _to, uint256 _value) internal { bytes memory returnData; bool returnDataResult; bytes memory callData = abi.encodeWithSelector(TRANSFER, _to, _value); assembly { let result := call(gas, _token, 0x0, add(callData, 0x20), mload(callData), 0, 32) returnData := mload(0) returnDataResult := mload(0) switch result case 0 { revert(0, 0) } } // Return data is optional if (returnData.length > 0) { require(returnDataResult); } } } // File: contracts/upgradeable_contracts/VersionableBridge.sol pragma solidity 0.4.24; contract VersionableBridge { function getBridgeInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) { return (5, 0, 0); } /* solcov ignore next */ function getBridgeMode() external pure returns (bytes4); } // File: contracts/upgradeable_contracts/BasicAMBMediator.sol pragma solidity 0.4.24; /** * @title BasicAMBMediator * @dev Basic storage and methods needed by mediators to interact with AMB bridge. */ 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 REQUEST_GAS_LIMIT = 0x2dfd6c9f781bb6bbb5369c114e949b69ebb440ef3d4dd6b2836225eb1dc3a2be; // keccak256(abi.encodePacked("requestGasLimit")) /** * @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 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 _requestGasLimit the gas limit for the message execution. */ function setRequestGasLimit(uint256 _requestGasLimit) external onlyOwner { _setRequestGasLimit(_requestGasLimit); } /** * @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 returns (address) { return addressStorage[MEDIATOR_CONTRACT]; } /** * @dev Tells the 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 a valid AMB bridge contract address. * @param _bridgeContract the address of the bridge contract. */ function _setBridgeContract(address _bridgeContract) internal { require(AddressUtils.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 gas limit to be used in the message execution by the AMB bridge on the other network. * @param _requestGasLimit the gas limit for the message execution. */ function _setRequestGasLimit(uint256 _requestGasLimit) internal { require(_requestGasLimit <= maxGasPerTx()); uintStorage[REQUEST_GAS_LIMIT] = _requestGasLimit; } /** * @dev Tells the address that generated the message on the other network that is currently being executed by * the AMB bridge. * @return the address of the message sender. */ function messageSender() internal view returns (address) { return bridgeContract().messageSender(); } /** * @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(); } } // File: contracts/upgradeable_contracts/TokenBridgeMediator.sol pragma solidity 0.4.24; /** * @title TokenBridgeMediator * @dev Common mediator functionality to handle operations related to token bridge messages sent to AMB bridge. */ contract TokenBridgeMediator is BasicAMBMediator, BasicTokenBridge { event FailedMessageFixed(bytes32 indexed messageId, address recipient, uint256 value); event TokensBridged(address indexed recipient, uint256 value, bytes32 indexed 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))]; } /** * @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; } /** * @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 Call AMB bridge to require the invocation of handleBridgedTokens method of the mediator on the other network. * Store information related to the bridged tokens in case the message execution fails on the other network * and the action needs to be fixed/rolled back. * @param _from address of sender, if bridge operation fails, tokens will be returned to this address * @param _receiver address of receiver on the other side, will eventually receive bridged tokens * @param _value bridged amount of tokens */ function passMessage(address _from, address _receiver, uint256 _value) internal { bytes4 methodSelector = this.handleBridgedTokens.selector; bytes memory data = abi.encodeWithSelector(methodSelector, _receiver, _value); bytes32 _messageId = bridgeContract().requireToPassMessage( mediatorContractOnOtherSide(), data, requestGasLimit() ); setMessageValue(_messageId, _value); setMessageRecipient(_messageId, _from); } /** * @dev Handles the bridged tokens. Checks that the value is inside the execution limits and invokes the method * to execute the Mint or Unlock accordingly. * @param _recipient address that will receive the tokens * @param _value amount of tokens to be received */ function handleBridgedTokens(address _recipient, uint256 _value) external { require(msg.sender == address(bridgeContract())); require(messageSender() == mediatorContractOnOtherSide()); if (withinExecutionLimit(_value)) { setTotalExecutedPerDay(getCurrentDay(), totalExecutedPerDay(getCurrentDay()).add(_value)); executeActionOnBridgedTokens(_recipient, _value); } else { executeActionOnBridgedTokensOutOfLimit(_recipient, _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 { require(!bridgeContract().messageCallStatus(_messageId)); require(bridgeContract().failedMessageReceiver(_messageId) == address(this)); require(bridgeContract().failedMessageSender(_messageId) == mediatorContractOnOtherSide()); bytes4 methodSelector = this.fixFailedMessage.selector; bytes memory data = abi.encodeWithSelector(methodSelector, _messageId); bridgeContract().requireToPassMessage(mediatorContractOnOtherSide(), data, requestGasLimit()); } /** * @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) external { require(msg.sender == address(bridgeContract())); require(messageSender() == mediatorContractOnOtherSide()); require(!messageFixed(_messageId)); address recipient = messageRecipient(_messageId); uint256 value = messageValue(_messageId); setMessageFixed(_messageId); executeActionOnFixedTokens(recipient, value); emit FailedMessageFixed(_messageId, recipient, value); } /* solcov ignore next */ function executeActionOnBridgedTokensOutOfLimit(address _recipient, uint256 _value) internal; /* solcov ignore next */ function executeActionOnBridgedTokens(address _recipient, uint256 _value) internal; /* solcov ignore next */ function executeActionOnFixedTokens(address _recipient, uint256 _value) internal; } // File: contracts/upgradeable_contracts/amb_erc677_to_erc677/BasicAMBErc677ToErc677.sol pragma solidity 0.4.24; /** * @title BasicAMBErc677ToErc677 * @dev Common functionality for erc677-to-erc677 mediator intended to work on top of AMB bridge. */ contract BasicAMBErc677ToErc677 is Initializable, ReentrancyGuard, Upgradeable, Claimable, VersionableBridge, BaseOverdrawManagement, BaseERC677Bridge, TokenBridgeMediator { function initialize( address _bridgeContract, address _mediatorContract, address _erc677token, uint256[] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ] uint256[] _executionDailyLimitExecutionMaxPerTxArray, // [ 0 = _executionDailyLimit, 1 = _executionMaxPerTx ] uint256 _requestGasLimit, uint256 _decimalShift, address _owner ) public onlyRelevantSender returns (bool) { require(!isInitialized()); require( _dailyLimitMaxPerTxMinPerTxArray[2] > 0 && // _minPerTx > 0 _dailyLimitMaxPerTxMinPerTxArray[1] > _dailyLimitMaxPerTxMinPerTxArray[2] && // _maxPerTx > _minPerTx _dailyLimitMaxPerTxMinPerTxArray[0] > _dailyLimitMaxPerTxMinPerTxArray[1] // _dailyLimit > _maxPerTx ); require(_executionDailyLimitExecutionMaxPerTxArray[1] < _executionDailyLimitExecutionMaxPerTxArray[0]); // _executionMaxPerTx < _executionDailyLimit _setBridgeContract(_bridgeContract); _setMediatorContractOnOtherSide(_mediatorContract); setErc677token(_erc677token); uintStorage[DAILY_LIMIT] = _dailyLimitMaxPerTxMinPerTxArray[0]; uintStorage[MAX_PER_TX] = _dailyLimitMaxPerTxMinPerTxArray[1]; uintStorage[MIN_PER_TX] = _dailyLimitMaxPerTxMinPerTxArray[2]; uintStorage[EXECUTION_DAILY_LIMIT] = _executionDailyLimitExecutionMaxPerTxArray[0]; uintStorage[EXECUTION_MAX_PER_TX] = _executionDailyLimitExecutionMaxPerTxArray[1]; _setRequestGasLimit(_requestGasLimit); uintStorage[DECIMAL_SHIFT] = _decimalShift; setOwner(_owner); setInitialize(); emit DailyLimitChanged(_dailyLimitMaxPerTxMinPerTxArray[0]); emit ExecutionDailyLimitChanged(_executionDailyLimitExecutionMaxPerTxArray[0]); return isInitialized(); } function bridgeContractOnOtherSide() internal view returns (address) { return mediatorContractOnOtherSide(); } function relayTokens(address _from, address _receiver, uint256 _value) external { require(_from == msg.sender || _from == _receiver); _relayTokens(_from, _receiver, _value); } function _relayTokens(address _from, address _receiver, uint256 _value) 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(!lock()); ERC677 token = erc677token(); address to = address(this); require(withinLimit(_value)); setTotalSpentPerDay(getCurrentDay(), totalSpentPerDay(getCurrentDay()).add(_value)); setLock(true); token.transferFrom(_from, to, _value); setLock(false); bridgeSpecificActionsOnTokenTransfer(token, _from, _value, abi.encodePacked(_receiver)); } function relayTokens(address _receiver, uint256 _value) external { _relayTokens(msg.sender, _receiver, _value); } function onTokenTransfer(address _from, uint256 _value, bytes _data) external returns (bool) { ERC677 oldXMoonToken = ERC677(0xC5C35D01B20f8d5cb65C60f02113EF6cd8e79910); ERC677 token = erc677token(); require((msg.sender == address(token)) || (msg.sender == address(oldXMoonToken))); if (!lock()) { require(withinLimit(_value)); setTotalSpentPerDay(getCurrentDay(), totalSpentPerDay(getCurrentDay()).add(_value)); } if (msg.sender == address(oldXMoonToken)) bridgeSpecificActionsOnTokenTransfer(oldXMoonToken, _from, _value, _data); else bridgeSpecificActionsOnTokenTransfer(token, _from, _value, _data); return true; } function getBridgeInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) { return (1, 1, 1); } function getBridgeMode() external pure returns (bytes4 _data) { return 0x76595b56; // bytes4(keccak256(abi.encodePacked("erc-to-erc-amb"))) } /** * @dev Execute the action to be performed when the bridge tokens are out of execution limits. * @param _recipient address intended to receive the tokens * @param _value amount of tokens to be received */ function executeActionOnBridgedTokensOutOfLimit(address _recipient, uint256 _value) internal { bytes32 _messageId = messageId(); address recipient; uint256 value; (recipient, value) = txAboveLimits(_messageId); require(recipient == address(0) && value == 0); setOutOfLimitAmount(outOfLimitAmount().add(_value)); setTxAboveLimits(_recipient, _value, _messageId); emit AmountLimitExceeded(_recipient, _value, _messageId); } /** * @dev Fixes locked tokens, that were out of execution limits during the call to handleBridgedTokens * @param messageId reference for bridge operation that was out of execution limits * @param unlockOnForeign true if fixed tokens should be unlocked to the other side of the bridge * @param valueToUnlock unlocked amount of tokens, should be less than maxPerTx() and saved txAboveLimitsValue */ function fixAssetsAboveLimits(bytes32 messageId, bool unlockOnForeign, uint256 valueToUnlock) external onlyIfUpgradeabilityOwner { require(!fixedAssets(messageId)); require(valueToUnlock <= maxPerTx()); address recipient; uint256 value; (recipient, value) = txAboveLimits(messageId); require(recipient != address(0) && value > 0 && value >= valueToUnlock); setOutOfLimitAmount(outOfLimitAmount().sub(valueToUnlock)); uint256 pendingValue = value.sub(valueToUnlock); setTxAboveLimitsValue(pendingValue, messageId); emit AssetAboveLimitsFixed(messageId, valueToUnlock, pendingValue); if (pendingValue == 0) { setFixedAssets(messageId); } if (unlockOnForeign) { passMessage(recipient, recipient, valueToUnlock); } } function claimTokens(address _token, address _to) public onlyIfUpgradeabilityOwner validAddress(_to) { claimValues(_token, _to); } } // File: contracts/interfaces/IBurnableMintableERC677Token.sol pragma solidity 0.4.24; contract IBurnableMintableERC677Token is ERC677 { function mint(address _to, uint256 _amount) public returns (bool); function burn(uint256 _value) public; function claimTokens(address _token, address _to) public; } // File: contracts/upgradeable_contracts/amb_erc677_to_erc677/HomeAMBErc677ToErc677.sol pragma solidity 0.4.24; /** * @title HomeAMBErc677ToErc677 * @dev Home side implementation for erc677-to-erc677 mediator intended to work on top of AMB bridge. * It is designed to be used as an implementation contract of EternalStorageProxy contract. */ contract HomeAMBErc677ToErc677 is BasicAMBErc677ToErc677 { /** * @dev Executes action on the request to deposit tokens relayed from the other network * @param _recipient address of tokens receiver * @param _value amount of bridged tokens */ function executeActionOnBridgedTokens(address _recipient, uint256 _value) internal { uint256 value = _value.mul(10**decimalShift()); bytes32 _messageId = messageId(); IBurnableMintableERC677Token(erc677token()).mint(_recipient, value); emit TokensBridged(_recipient, value, _messageId); } /** * @dev Executes action on withdrawal of bridged tokens * @param _token address of token contract * @param _from address of tokens sender * @param _value requsted amount of bridged tokens * @param _data alternative receiver, if specified */ function bridgeSpecificActionsOnTokenTransfer(ERC677 _token, address _from, uint256 _value, bytes _data) internal { if (!lock()) { IBurnableMintableERC677Token(_token).burn(_value); passMessage(_from, chooseReceiver(_from, _data), _value); } } function executeActionOnFixedTokens(address _recipient, uint256 _value) internal { IBurnableMintableERC677Token(erc677token()).mint(_recipient, _value); } // Selector: 0xf0ebb23e function migrateToAnotherxMOONToken() external { bytes32 migrateToAnotherxMOONTokenStorage = 0x850b0e45ac6387011aef8a3113b9f3fda9e1dea43ef0f51aa585cc9a30956629; // keccak256(abi.encodePacked("migrateToAnotherxMOONToken20200619")) require(!boolStorage[migrateToAnotherxMOONTokenStorage]); setErc677token(0x1e16aa4Df73d29C029d94CeDa3e3114EC191E25A); boolStorage[migrateToAnotherxMOONTokenStorage] = true; } }
Contract ABI
[{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"relayTokens","inputs":[{"type":"address","name":"_receiver"},{"type":"uint256","name":"_value"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"fixFailedMessage","inputs":[{"type":"bytes32","name":"_messageId"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setBridgeContract","inputs":[{"type":"address","name":"_bridgeContract"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"erc677token","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"fixedAssets","inputs":[{"type":"bytes32","name":"_txHash"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"totalSpentPerDay","inputs":[{"type":"uint256","name":"_day"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isInitialized","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setExecutionDailyLimit","inputs":[{"type":"uint256","name":"_dailyLimit"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getCurrentDay","inputs":[],"constant":true},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"bytes4","name":"_data"}],"name":"getBridgeMode","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"executionDailyLimit","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"totalExecutedPerDay","inputs":[{"type":"uint256","name":"_day"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"messageFixed","inputs":[{"type":"bytes32","name":"_messageId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"dailyLimit","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"claimTokens","inputs":[{"type":"address","name":"_token"},{"type":"address","name":"_to"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setMediatorContractOnOtherSide","inputs":[{"type":"address","name":"_mediatorContract"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"initialize","inputs":[{"type":"address","name":"_bridgeContract"},{"type":"address","name":"_mediatorContract"},{"type":"address","name":"_erc677token"},{"type":"uint256[]","name":"_dailyLimitMaxPerTxMinPerTxArray"},{"type":"uint256[]","name":"_executionDailyLimitExecutionMaxPerTxArray"},{"type":"uint256","name":"_requestGasLimit"},{"type":"uint256","name":"_decimalShift"},{"type":"address","name":"_owner"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"mediatorContractOnOtherSide","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"withinExecutionLimit","inputs":[{"type":"uint256","name":"_amount"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"executionMaxPerTx","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"handleBridgedTokens","inputs":[{"type":"address","name":"_recipient"},{"type":"uint256","name":"_value"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"owner","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"requestFailedMessageFix","inputs":[{"type":"bytes32","name":"_messageId"}],"constant":false},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"uint64","name":"major"},{"type":"uint64","name":"minor"},{"type":"uint64","name":"patch"}],"name":"getBridgeInterfacesVersion","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"outOfLimitAmount","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setMinPerTx","inputs":[{"type":"uint256","name":"_minPerTx"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"onTokenTransfer","inputs":[{"type":"address","name":"_from"},{"type":"uint256","name":"_value"},{"type":"bytes","name":"_data"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"fixAssetsAboveLimits","inputs":[{"type":"bytes32","name":"messageId"},{"type":"bool","name":"unlockOnForeign"},{"type":"uint256","name":"valueToUnlock"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"relayTokens","inputs":[{"type":"address","name":"_from"},{"type":"address","name":"_receiver"},{"type":"uint256","name":"_value"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setDailyLimit","inputs":[{"type":"uint256","name":"_dailyLimit"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"requestGasLimit","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setMaxPerTx","inputs":[{"type":"uint256","name":"_maxPerTx"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"bridgeContract","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"decimalShift","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"minPerTx","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"withinLimit","inputs":[{"type":"uint256","name":"_amount"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"migrateToAnotherxMOONToken","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setExecutionMaxPerTx","inputs":[{"type":"uint256","name":"_maxPerTx"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setRequestGasLimit","inputs":[{"type":"uint256","name":"_requestGasLimit"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"maxPerTx","inputs":[],"constant":true},{"type":"event","name":"FailedMessageFixed","inputs":[{"type":"bytes32","name":"messageId","indexed":true},{"type":"address","name":"recipient","indexed":false},{"type":"uint256","name":"value","indexed":false}],"anonymous":false},{"type":"event","name":"TokensBridged","inputs":[{"type":"address","name":"recipient","indexed":true},{"type":"uint256","name":"value","indexed":false},{"type":"bytes32","name":"messageId","indexed":true}],"anonymous":false},{"type":"event","name":"DailyLimitChanged","inputs":[{"type":"uint256","name":"newLimit","indexed":false}],"anonymous":false},{"type":"event","name":"ExecutionDailyLimitChanged","inputs":[{"type":"uint256","name":"newLimit","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":false},{"type":"address","name":"newOwner","indexed":false}],"anonymous":false},{"type":"event","name":"AmountLimitExceeded","inputs":[{"type":"address","name":"recipient","indexed":false},{"type":"uint256","name":"value","indexed":false},{"type":"bytes32","name":"transactionHash","indexed":false}],"anonymous":false},{"type":"event","name":"AssetAboveLimitsFixed","inputs":[{"type":"bytes32","name":"transactionHash","indexed":true},{"type":"uint256","name":"value","indexed":false},{"type":"uint256","name":"remaining","indexed":false}],"anonymous":false}]
Deployed ByteCode
0x6080604052600436106101f9576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806301e4f53a146101fe5780630950d5151461024b5780630b26cf661461027c57806318d8f9c9146102bf5780632888bb9c146103165780632bd0bb051461035f578063392e53cd146103a05780633dd95d1b146103cf5780633e6968b6146103fc578063437764df1461042757806343b37dd3146104905780634fb3fef7146104bb57806359339982146104fc57806367eeba0c1461054557806369ffa08a146105705780636e5d6bea146105d35780637acee4b014610616578063871c07601461076b578063879ce676146107c25780638aa1949a146108075780638b6c0354146108325780638da5cb5b1461087f5780639a4a4395146108d65780639cb7595a14610907578063a01893451461097c578063a2a6ca27146109a7578063a4c0ed36146109d4578063a7444c0d14610a51578063ad58bdd114610a98578063b20d30a914610b05578063be3b625b14610b32578063c6f6f21614610b5d578063cd59658314610b8a578063dae5f0fd14610be1578063df25f3f014610c0c578063ea9f496814610c37578063f0ebb23e14610c7c578063f20151e114610c93578063f2fde38b14610cc0578063f3b8379114610d03578063f968adbe14610d30575b600080fd5b34801561020a57600080fd5b50610249600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610d5b565b005b34801561025757600080fd5b5061027a6004803603810190808035600019169060200190929190505050610d6a565b005b34801561028857600080fd5b506102bd600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ea9565b005b3480156102cb57600080fd5b506102d4610ef6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561032257600080fd5b506103456004803603810190808035600019169060200190929190505050610f5c565b604051808215151515815260200191505060405180910390f35b34801561036b57600080fd5b5061038a6004803603810190808035906020019092919050505061103f565b6040518082815260200191505060405180910390f35b3480156103ac57600080fd5b506103b561110c565b604051808215151515815260200191505060405180910390f35b3480156103db57600080fd5b506103fa6004803603810190808035906020019092919050505061115f565b005b34801561040857600080fd5b5061041161123c565b6040518082815260200191505060405180910390f35b34801561043357600080fd5b5061043c611252565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b34801561049c57600080fd5b506104a561127d565b6040518082815260200191505060405180910390f35b3480156104c757600080fd5b506104e6600480360381019080803590602001909291905050506112c2565b6040518082815260200191505060405180910390f35b34801561050857600080fd5b5061052b600480360381019080803560001916906020019092919050505061138f565b604051808215151515815260200191505060405180910390f35b34801561055157600080fd5b5061055a611472565b6040518082815260200191505060405180910390f35b34801561057c57600080fd5b506105d1600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506114b7565b005b3480156105df57600080fd5b50610614600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506115db565b005b34801561062257600080fd5b50610751600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091929192908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611628565b604051808215151515815260200191505060405180910390f35b34801561077757600080fd5b50610780611c29565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107ce57600080fd5b506107ed60048036038101908080359060200190929190505050611c8f565b604051808215151515815260200191505060405180910390f35b34801561081357600080fd5b5061081c611cdc565b6040518082815260200191505060405180910390f35b34801561083e57600080fd5b5061087d600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611d21565b005b34801561088b57600080fd5b50610894611e08565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156108e257600080fd5b506109056004803603810190808035600019169060200190929190505050611e6e565b005b34801561091357600080fd5b5061091c612327565b604051808467ffffffffffffffff1667ffffffffffffffff1681526020018367ffffffffffffffff1667ffffffffffffffff1681526020018267ffffffffffffffff1667ffffffffffffffff168152602001935050505060405180910390f35b34801561098857600080fd5b50610991612345565b6040518082815260200191505060405180910390f35b3480156109b357600080fd5b506109d26004803603810190808035906020019092919050505061238a565b005b3480156109e057600080fd5b50610a37600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001908201803590602001919091929391929390505050612443565b604051808215151515815260200191505060405180910390f35b348015610a5d57600080fd5b50610a966004803603810190808035600019169060200190929190803515159060200190929190803590602001909291905050506125f2565b005b348015610aa457600080fd5b50610b03600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050612811565b005b348015610b1157600080fd5b50610b3060048036038101908080359060200190929190505050612891565b005b348015610b3e57600080fd5b50610b4761296e565b6040518082815260200191505060405180910390f35b348015610b6957600080fd5b50610b88600480360381019080803590602001909291905050506129b3565b005b348015610b9657600080fd5b50610b9f612a6b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610bed57600080fd5b50610bf6612ad1565b6040518082815260200191505060405180910390f35b348015610c1857600080fd5b50610c21612b16565b6040518082815260200191505060405180910390f35b348015610c4357600080fd5b50610c6260048036038101908080359060200190929190505050612b5b565b604051808215151515815260200191505060405180910390f35b348015610c8857600080fd5b50610c91612bbb565b005b348015610c9f57600080fd5b50610cbe60048036038101908080359060200190929190505050612c6c565b005b348015610ccc57600080fd5b50610d01600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612d07565b005b348015610d0f57600080fd5b50610d2e60048036038101908080359060200190929190505050612d90565b005b348015610d3c57600080fd5b50610d45612ddd565b6040518082815260200191505060405180910390f35b610d66338383612e22565b5050565b600080610d75612a6b565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610dae57600080fd5b610db6611c29565b73ffffffffffffffffffffffffffffffffffffffff16610dd4613020565b73ffffffffffffffffffffffffffffffffffffffff16141515610df657600080fd5b610dff8361138f565b151515610e0b57600080fd5b610e14836130cd565b9150610e1f836131c3565b9050610e2a83613298565b610e348282613380565b82600019167f06297b0797e3363e96e454edd4ab62862051bf559a7a431ce09415306771d1338383604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a2505050565b610eb1611e08565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610eea57600080fd5b610ef38161346a565b50565b6000600260007fa8b0ade3e2b734f043ce298aca4cc8d19d74270223f34531d0988b7d00cba21d6001026000191660001916815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000600460008360405160200180807f6669786564417373657473000000000000000000000000000000000000000000815250600b0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083101515610fe75780518252602082019150602081019050602083039250610fc2565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390206000191660001916815260200190815260200160002060009054906101000a900460ff169050919050565b60008060008360405160200180807f746f74616c5370656e74506572446179000000000000000000000000000000008152506010018281526020019150506040516020818303038152906040526040518082805190602001908083835b6020831015156110c1578051825260208201915060208101905060208303925061109c565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916600019168152602001908152602001600020549050919050565b6000600460007f0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba6001026000191660001916815260200190815260200160002060009054906101000a900460ff16905090565b611167611e08565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156111a057600080fd5b6111a8611cdc565b8111806111b55750600081145b15156111c057600080fd5b806000807f21dbcab260e413c20dc13c28b7db95e2b423d1135f42bb8b7d5214a92270d23760010260001916600019168152602001908152602001600020819055507f9bebf928b90863f24cc31f726a3a7545efd409f1dcf552301b1ee3710da70d3b816040518082815260200191505060405180910390a150565b6000620151804281151561124c57fe5b04905090565b60006376595b567c010000000000000000000000000000000000000000000000000000000002905090565b60008060007f21dbcab260e413c20dc13c28b7db95e2b423d1135f42bb8b7d5214a92270d2376001026000191660001916815260200190815260200160002054905090565b60008060008360405160200180807f746f74616c4578656375746564506572446179000000000000000000000000008152506013018281526020019150506040516020818303038152906040526040518082805190602001908083835b602083101515611344578051825260208201915060208101905060208303925061131f565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916600019168152602001908152602001600020549050919050565b6000600460008360405160200180807f6d65737361676546697865640000000000000000000000000000000000000000815250600c0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310151561141a57805182526020820191506020810190506020830392506113f5565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390206000191660001916815260200190815260200160002060009054906101000a900460ff169050919050565b60008060007f4a6a899679f26b73530d8cf1001e83b6f7702e04b6fdb98f3c62dc7e47e041a56001026000191660001916815260200190815260200160002054905090565b3073ffffffffffffffffffffffffffffffffffffffff16636fde82026040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561151b57600080fd5b505af115801561152f573d6000803e3d6000fd5b505050506040513d602081101561154557600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561158f57600080fd5b80600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515156115cc57600080fd5b6115d683836134fe565b505050565b6115e3611e08565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561161c57600080fd5b61162581613550565b50565b60003073ffffffffffffffffffffffffffffffffffffffff16636fde82027c010000000000000000000000000000000000000000000000000000000002604051602401604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405180828051906020019080838360005b838110156116f55780820151818401526020810190506116da565b50505050905090810190601f1680156117225780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af1915050158061180c57503073ffffffffffffffffffffffffffffffffffffffff16636fde82026040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156117a257600080fd5b505af11580156117b6573d6000803e3d6000fd5b505050506040513d60208110156117cc57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b8061184257503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561184d57600080fd5b61185561110c565b15151561186157600080fd5b600086600281518110151561187257fe5b906020019060200201511180156118b8575085600281518110151561189357fe5b906020019060200201518660018151811015156118ac57fe5b90602001906020020151115b80156118f357508560018151811015156118ce57fe5b906020019060200201518660008151811015156118e757fe5b90602001906020020151115b15156118fe57600080fd5b84600081518110151561190d57fe5b9060200190602002015185600181518110151561192657fe5b9060200190602002015110151561193c57600080fd5b6119458961346a565b61194e88613550565b611957876135d0565b85600081518110151561196657fe5b906020019060200201516000807f4a6a899679f26b73530d8cf1001e83b6f7702e04b6fdb98f3c62dc7e47e041a560010260001916600019168152602001908152602001600020819055508560018151811015156119c057fe5b906020019060200201516000807f0f8803acad17c63ee38bf2de71e1888bc7a079a6f73658e274b08018bea4e29c6001026000191660001916815260200190815260200160002081905550856002815181101515611a1a57fe5b906020019060200201516000807fbbb088c505d18e049d114c7c91f11724e69c55ad6c5397e2b929e68b41fa05d16001026000191660001916815260200190815260200160002081905550846000815181101515611a7457fe5b906020019060200201516000807f21dbcab260e413c20dc13c28b7db95e2b423d1135f42bb8b7d5214a92270d2376001026000191660001916815260200190815260200160002081905550846001815181101515611ace57fe5b906020019060200201516000807fc0ed44c192c86d1cc1ba51340b032c2766b4a2b0041031de13c46dd7104888d56001026000191660001916815260200190815260200160002081905550611b2284613664565b826000807f1e8ecaafaddea96ed9ac6d2642dcdfe1bebe58a930b1085842d8fc122b371ee56001026000191660001916815260200190815260200160002081905550611b6d826136bf565b611b756137dd565b7fad4123ae17c414d9c6d2fec478b402e6b01856cc250fd01fbfd252fda0089d3c866000815181101515611ba557fe5b906020019060200201516040518082815260200191505060405180910390a17f9bebf928b90863f24cc31f726a3a7545efd409f1dcf552301b1ee3710da70d3b856000815181101515611bf457fe5b906020019060200201516040518082815260200191505060405180910390a1611c1b61110c565b905098975050505050505050565b6000600260007f98aa806e31e94a687a31c65769cb99670064dd7f5a87526da075c5fb4eab98806001026000191660001916815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080611cb483611ca6611ca161123c565b6112c2565b61383690919063ffffffff16565b905080611cbf61127d565b10158015611cd45750611cd0611cdc565b8311155b915050919050565b60008060007fc0ed44c192c86d1cc1ba51340b032c2766b4a2b0041031de13c46dd7104888d56001026000191660001916815260200190815260200160002054905090565b611d29612a6b565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515611d6257600080fd5b611d6a611c29565b73ffffffffffffffffffffffffffffffffffffffff16611d88613020565b73ffffffffffffffffffffffffffffffffffffffff16141515611daa57600080fd5b611db381611c8f565b15611df957611dea611dc361123c565b611de583611dd7611dd261123c565b6112c2565b61383690919063ffffffff16565b613852565b611df4828261391e565b611e04565b611e038282613a89565b5b5050565b6000600260007f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c06001026000191660001916815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006060611e7a612a6b565b73ffffffffffffffffffffffffffffffffffffffff1663cb08a10c846040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808260001916600019168152602001915050602060405180830381600087803b158015611ef057600080fd5b505af1158015611f04573d6000803e3d6000fd5b505050506040513d6020811015611f1a57600080fd5b8101908080519060200190929190505050151515611f3757600080fd5b3073ffffffffffffffffffffffffffffffffffffffff16611f56612a6b565b73ffffffffffffffffffffffffffffffffffffffff16633f9a8e7e856040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808260001916600019168152602001915050602060405180830381600087803b158015611fcc57600080fd5b505af1158015611fe0573d6000803e3d6000fd5b505050506040513d6020811015611ff657600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff1614151561202957600080fd5b612031611c29565b73ffffffffffffffffffffffffffffffffffffffff1661204f612a6b565b73ffffffffffffffffffffffffffffffffffffffff16634a610b04856040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808260001916600019168152602001915050602060405180830381600087803b1580156120c557600080fd5b505af11580156120d9573d6000803e3d6000fd5b505050506040513d60208110156120ef57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff1614151561212257600080fd5b630950d5157c01000000000000000000000000000000000000000000000000000000000291508183604051602401808260001916600019168152602001915050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506121c9612a6b565b73ffffffffffffffffffffffffffffffffffffffff1663dc8601b36121ec611c29565b836121f561296e565b6040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b8381101561229857808201518184015260208101905061227d565b50505050905090810190601f1680156122c55780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600087803b1580156122e657600080fd5b505af11580156122fa573d6000803e3d6000fd5b505050506040513d602081101561231057600080fd5b810190808051906020019092919050505050505050565b60008060006001806001829250819150809050925092509250909192565b60008060007f145286dc85799b6fb9fe322391ba2d95683077b2adf34dd576dedc437e537ba76001026000191660001916815260200190815260200160002054905090565b612392611e08565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156123cb57600080fd5b6000811180156123e157506123de611472565b81105b80156123f357506123f0612ddd565b81105b15156123fe57600080fd5b806000807fbbb088c505d18e049d114c7c91f11724e69c55ad6c5397e2b929e68b41fa05d1600102600019166000191681526020019081526020016000208190555050565b600080600073c5c35d01b20f8d5cb65c60f02113ef6cd8e799109150612467610ef6565b90508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806124ce57508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156124d957600080fd5b6124e1613b9f565b151561252e576124f086612b5b565b15156124fb57600080fd5b61252d61250661123c565b6125288861251a61251561123c565b61103f565b61383690919063ffffffff16565b613bf2565b5b8173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156125a5576125a082888888888080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050613cbe565b6125e4565b6125e381888888888080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050613cbe565b5b600192505050949350505050565b60008060003073ffffffffffffffffffffffffffffffffffffffff16636fde82026040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561265b57600080fd5b505af115801561266f573d6000803e3d6000fd5b505050506040513d602081101561268557600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156126cf57600080fd5b6126d886610f5c565b1515156126e457600080fd5b6126ec612ddd565b84111515156126fa57600080fd5b61270386613d6e565b8093508194505050600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141580156127485750600082115b80156127545750838210155b151561275f57600080fd5b61278161277c8561276e612345565b613f3390919063ffffffff16565b613f4c565b6127948483613f3390919063ffffffff16565b90506127a08187613f91565b85600019167f5bcec6564fe8d2cbb4e4eb8237510ceb6b291a5c2ee2e429948d25e9c924c1fa8583604051808381526020018281526020019250505060405180910390a260008114156127f7576127f686614065565b5b84156128095761280883848661414d565b5b505050505050565b3373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16148061287657508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16145b151561288157600080fd5b61288c838383612e22565b505050565b612899611e08565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156128d257600080fd5b6128da612ddd565b8111806128e75750600081145b15156128f257600080fd5b806000807f4a6a899679f26b73530d8cf1001e83b6f7702e04b6fdb98f3c62dc7e47e041a560010260001916600019168152602001908152602001600020819055507fad4123ae17c414d9c6d2fec478b402e6b01856cc250fd01fbfd252fda0089d3c816040518082815260200191505060405180910390a150565b60008060007f2dfd6c9f781bb6bbb5369c114e949b69ebb440ef3d4dd6b2836225eb1dc3a2be6001026000191660001916815260200190815260200160002054905090565b6129bb611e08565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156129f457600080fd5b6000811480612a1b5750612a06612b16565b81118015612a1a5750612a17611472565b81105b5b1515612a2657600080fd5b806000807f0f8803acad17c63ee38bf2de71e1888bc7a079a6f73658e274b08018bea4e29c600102600019166000191681526020019081526020016000208190555050565b6000600260007f811bbb11e8899da471f0e69a3ed55090fc90215227fc5fb1cb0d6e962ea7b74f6001026000191660001916815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060007f1e8ecaafaddea96ed9ac6d2642dcdfe1bebe58a930b1085842d8fc122b371ee56001026000191660001916815260200190815260200160002054905090565b60008060007fbbb088c505d18e049d114c7c91f11724e69c55ad6c5397e2b929e68b41fa05d16001026000191660001916815260200190815260200160002054905090565b600080612b8083612b72612b6d61123c565b61103f565b61383690919063ffffffff16565b905080612b8b611472565b10158015612ba05750612b9c612ddd565b8311155b8015612bb35750612baf612b16565b8310155b915050919050565b60007f850b0e45ac6387011aef8a3113b9f3fda9e1dea43ef0f51aa585cc9a30956629600102905060046000826000191660001916815260200190815260200160002060009054906101000a900460ff16151515612c1857600080fd5b612c35731e16aa4df73d29c029d94ceda3e3114ec191e25a6135d0565b600160046000836000191660001916815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b612c74611e08565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515612cad57600080fd5b612cb561127d565b81101515612cc257600080fd5b806000807fc0ed44c192c86d1cc1ba51340b032c2766b4a2b0041031de13c46dd7104888d5600102600019166000191681526020019081526020016000208190555050565b612d0f611e08565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515612d4857600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515612d8457600080fd5b612d8d816136bf565b50565b612d98611e08565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515612dd157600080fd5b612dda81613664565b50565b60008060007f0f8803acad17c63ee38bf2de71e1888bc7a079a6f73658e274b08018bea4e29c6001026000191660001916815260200190815260200160002054905090565b600080612e2d613b9f565b151515612e3957600080fd5b612e41610ef6565b9150309050612e4f83612b5b565b1515612e5a57600080fd5b612e8c612e6561123c565b612e8785612e79612e7461123c565b61103f565b61383690919063ffffffff16565b613bf2565b612e96600161439c565b8173ffffffffffffffffffffffffffffffffffffffff166323b872dd8683866040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b158015612f6d57600080fd5b505af1158015612f81573d6000803e3d6000fd5b505050506040513d6020811015612f9757600080fd5b810190808051906020019092919050505050612fb3600061439c565b61301982868587604051602001808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401915050604051602081830303815290604052613cbe565b5050505050565b600061302a612a6b565b73ffffffffffffffffffffffffffffffffffffffff1663d67bdd256040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561308d57600080fd5b505af11580156130a1573d6000803e3d6000fd5b505050506040513d60208110156130b757600080fd5b8101908080519060200190929190505050905090565b6000600260008360405160200180807f6d657373616765526563697069656e740000000000000000000000000000000081525060100182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b6020831015156131585780518252602082019150602081019050602083039250613133565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390206000191660001916815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b60008060008360405160200180807f6d65737361676556616c75650000000000000000000000000000000000000000815250600c0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310151561324d5780518252602082019150602081019050602083039250613228565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916600019168152602001908152602001600020549050919050565b6001600460008360405160200180807f6d65737361676546697865640000000000000000000000000000000000000000815250600c0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310151561332357805182526020820191506020810190506020830392506132fe565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390206000191660001916815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b613388610ef6565b73ffffffffffffffffffffffffffffffffffffffff166340c10f1983836040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561342a57600080fd5b505af115801561343e573d6000803e3d6000fd5b505050506040513d602081101561345457600080fd5b8101908080519060200190929190505050505050565b613473816143f5565b151561347e57600080fd5b80600260007f811bbb11e8899da471f0e69a3ed55090fc90215227fc5fb1cb0d6e962ea7b74f6001026000191660001916815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156135415761353c81614408565b61354c565b61354b8282614432565b5b5050565b80600260007f98aa806e31e94a687a31c65769cb99670064dd7f5a87526da075c5fb4eab98806001026000191660001916815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6135d9816143f5565b15156135e457600080fd5b80600260007fa8b0ade3e2b734f043ce298aca4cc8d19d74270223f34531d0988b7d00cba21d6001026000191660001916815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61366c614521565b811115151561367a57600080fd5b806000807f2dfd6c9f781bb6bbb5369c114e949b69ebb440ef3d4dd6b2836225eb1dc3a2be600102600019166000191681526020019081526020016000208190555050565b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e06136e8611e08565b82604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a180600260007f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c06001026000191660001916815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6001600460007f0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba6001026000191660001916815260200190815260200160002060006101000a81548160ff021916908315150217905550565b6000818301905082811015151561384957fe5b80905092915050565b806000808460405160200180807f746f74616c4578656375746564506572446179000000000000000000000000008152506013018281526020019150506040516020818303038152906040526040518082805190602001908083835b6020831015156138d357805182526020820191506020810190506020830392506138ae565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916600019168152602001908152602001600020819055505050565b60008061393e61392c612ad1565b600a0a846145ce90919063ffffffff16565b9150613948614606565b9050613952610ef6565b73ffffffffffffffffffffffffffffffffffffffff166340c10f1985846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156139f457600080fd5b505af1158015613a08573d6000803e3d6000fd5b505050506040513d6020811015613a1e57600080fd5b81019080805190602001909291905050505080600019168473ffffffffffffffffffffffffffffffffffffffff167f2f9a6098d4503a127779ba975f5f6b04f842362b1809f346989e9abc0b4dedb6846040518082815260200191505060405180910390a350505050565b6000806000613a96614606565b9250613aa183613d6e565b8092508193505050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16148015613ae55750600081145b1515613af057600080fd5b613b12613b0d85613aff612345565b61383690919063ffffffff16565b613f4c565b613b1d8585856146b3565b7f159c0773f543f1e17d5e78327702770947055eb4e871b529bbc78bc9fde45692858585604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018381526020018260001916600019168152602001935050505060405180910390a15050505050565b6000600460007f6168652c307c1e813ca11cfb3a601f1cf3b22452021a5052d8b05f1f1f8a3e926001026000191660001916815260200190815260200160002060009054906101000a900460ff16905090565b806000808460405160200180807f746f74616c5370656e74506572446179000000000000000000000000000000008152506010018281526020019150506040516020818303038152906040526040518082805190602001908083835b602083101515613c735780518252602082019150602081019050602083039250613c4e565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916600019168152602001908152602001600020819055505050565b613cc6613b9f565b1515613d68578373ffffffffffffffffffffffffffffffffffffffff166342966c68836040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b158015613d3b57600080fd5b505af1158015613d4f573d6000803e3d6000fd5b50505050613d6783613d6185846147cd565b8461414d565b5b50505050565b600080600260008460405160200180807f74784f75744f664c696d6974526563697069656e74000000000000000000000081525060150182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083101515613dfa5780518252602082019150602081019050602083039250613dd5565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390206000191660001916815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691506000808460405160200180807f74784f75744f664c696d697456616c756500000000000000000000000000000081525060110182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083101515613ee85780518252602082019150602081019050602083039250613ec3565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916600019168152602001908152602001600020549050915091565b6000828211151515613f4157fe5b818303905092915050565b806000807f145286dc85799b6fb9fe322391ba2d95683077b2adf34dd576dedc437e537ba7600102600019166000191681526020019081526020016000208190555050565b816000808360405160200180807f74784f75744f664c696d697456616c756500000000000000000000000000000081525060110182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310151561401a5780518252602082019150602081019050602083039250613ff5565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916600019168152602001908152602001600020819055505050565b6001600460008360405160200180807f6669786564417373657473000000000000000000000000000000000000000000815250600b0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b6020831015156140f057805182526020820191506020810190506020830392506140cb565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390206000191660001916815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b600060606000638b6c03547c0100000000000000000000000000000000000000000000000000000000029250828585604051602401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509150614226612a6b565b73ffffffffffffffffffffffffffffffffffffffff1663dc8601b3614249611c29565b8461425261296e565b6040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156142f55780820151818401526020810190506142da565b50505050905090810190601f1680156143225780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600087803b15801561434357600080fd5b505af1158015614357573d6000803e3d6000fd5b505050506040513d602081101561436d57600080fd5b8101908080519060200190929190505050905061438a818561487c565b6143948187614950565b505050505050565b80600460007f6168652c307c1e813ca11cfb3a601f1cf3b22452021a5052d8b05f1f1f8a3e926001026000191660001916815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b600080823b905060008111915050919050565b60003073ffffffffffffffffffffffffffffffffffffffff1631905061442e8282614a5f565b5050565b6000808391508173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156144d357600080fd5b505af11580156144e7573d6000803e3d6000fd5b505050506040513d60208110156144fd57600080fd5b8101908080519060200190929190505050905061451b848483614afe565b50505050565b600061452b612a6b565b73ffffffffffffffffffffffffffffffffffffffff1663e5789d036040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561458e57600080fd5b505af11580156145a2573d6000803e3d6000fd5b505050506040513d60208110156145b857600080fd5b8101908080519060200190929190505050905090565b6000808314156145e15760009050614600565b81830290508183828115156145f257fe5b041415156145fc57fe5b8090505b92915050565b6000614610612a6b565b73ffffffffffffffffffffffffffffffffffffffff1663669f618b6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561467357600080fd5b505af1158015614687573d6000803e3d6000fd5b505050506040513d602081101561469d57600080fd5b8101908080519060200190929190505050905090565b82600260008360405160200180807f74784f75744f664c696d6974526563697069656e74000000000000000000000081525060150182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310151561473d5780518252602082019150602081019050602083039250614718565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390206000191660001916815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506147c88282613f91565b505050565b600082905060008251111561487657601482511415156147ec57600080fd5b6147f582614c19565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561483357600080fd5b61483b614c27565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561487557600080fd5b5b92915050565b806000808460405160200180807f6d65737361676556616c75650000000000000000000000000000000000000000815250600c0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310151561490557805182526020820191506020810190506020830392506148e0565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916600019168152602001908152602001600020819055505050565b80600260008460405160200180807f6d657373616765526563697069656e740000000000000000000000000000000081525060100182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b6020831015156149da57805182526020820191506020810190506020830392506149b5565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390206000191660001916815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501515614afa578082614aa4614c36565b808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019150506040518091039082f080158015614af5573d6000803e3d6000fd5b509050505b5050565b60606000606063a9059cbb7c0100000000000000000000000000000000000000000000000000000000028585604051602401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506020600082516020840160008a5af1600051935060005192508060008114614bf357614bf8565b600080fd5b5050600083511115614c1157811515614c1057600080fd5b5b505050505050565b600060148201519050919050565b6000614c31611c29565b905090565b604051603f80614c468339019056006080604052604051602080603f833981018060405281019080805190602001909291905050508073ffffffffffffffffffffffffffffffffffffffff16ff00a165627a7a72305820865cb8bdee21a63ac1beca624af54ac015c6db33a200d6bddbc05f36cc0fc0440029