Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- HomeAMB
- Optimization enabled
- true
- Compiler version
- v0.4.24+commit.e67f0147
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2023-05-15T08:53:07.232000Z
Contract source code
// File: contracts/interfaces/IAMBInformationReceiver.sol
pragma solidity 0.4.24;
interface IAMBInformationReceiver {
function onInformationReceived(bytes32 messageId, bool status, bytes result) external;
}
// File: contracts/interfaces/IBridgeValidators.sol
pragma solidity 0.4.24;
interface IBridgeValidators {
function isValidator(address _validator) external view returns (bool);
function requiredSignatures() external view returns (uint256);
function owner() external view returns (address);
}
// File: contracts/libraries/Message.sol
pragma solidity 0.4.24;
library Message {
function addressArrayContains(address[] array, address value) internal pure returns (bool) {
for (uint256 i = 0; i < array.length; i++) {
if (array[i] == value) {
return true;
}
}
return false;
}
// layout of message :: bytes:
// offset 0: 32 bytes :: uint256 - message length
// offset 32: 20 bytes :: address - recipient address
// offset 52: 32 bytes :: uint256 - value
// offset 84: 32 bytes :: bytes32 - transaction hash
// offset 116: 20 bytes :: address - contract address to prevent double spending
// mload always reads 32 bytes.
// so we can and have to start reading recipient at offset 20 instead of 32.
// if we were to read at 32 the address would contain part of value and be corrupted.
// when reading from offset 20 mload will read 12 bytes (most of them zeros) followed
// by the 20 recipient address bytes and correctly convert it into an address.
// this saves some storage/gas over the alternative solution
// which is padding address to 32 bytes and reading recipient at offset 32.
// for more details see discussion in:
// https://github.com/paritytech/parity-bridge/issues/61
function parseMessage(bytes message)
internal
pure
returns (address recipient, uint256 amount, bytes32 txHash, address contractAddress)
{
require(isMessageValid(message));
assembly {
recipient := mload(add(message, 20))
amount := mload(add(message, 52))
txHash := mload(add(message, 84))
contractAddress := mload(add(message, 104))
}
}
function isMessageValid(bytes _msg) internal pure returns (bool) {
return _msg.length == requiredMessageLength();
}
function requiredMessageLength() internal pure returns (uint256) {
return 104;
}
function recoverAddressFromSignedMessage(bytes signature, bytes message, bool isAMBMessage)
internal
pure
returns (address)
{
require(signature.length == 65);
bytes32 r;
bytes32 s;
bytes1 v;
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := mload(add(signature, 0x60))
}
require(uint8(v) == 27 || uint8(v) == 28);
require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0);
return ecrecover(hashMessage(message, isAMBMessage), uint8(v), r, s);
}
function hashMessage(bytes message, bool isAMBMessage) internal pure returns (bytes32) {
bytes memory prefix = "\x19Ethereum Signed Message:\n";
if (isAMBMessage) {
return keccak256(abi.encodePacked(prefix, uintToString(message.length), message));
} else {
string memory msgLength = "104";
return keccak256(abi.encodePacked(prefix, msgLength, message));
}
}
/**
* @dev Validates provided signatures, only first requiredSignatures() number
* of signatures are going to be validated, these signatures should be from different validators.
* @param _message bytes message used to generate signatures
* @param _signatures bytes blob with signatures to be validated.
* First byte X is a number of signatures in a blob,
* next X bytes are v components of signatures,
* next 32 * X bytes are r components of signatures,
* next 32 * X bytes are s components of signatures.
* @param _validatorContract contract, which conforms to the IBridgeValidators interface,
* where info about current validators and required signatures is stored.
* @param isAMBMessage true if _message is an AMB message with arbitrary length.
*/
function hasEnoughValidSignatures(
bytes _message,
bytes _signatures,
IBridgeValidators _validatorContract,
bool isAMBMessage
) internal view {
require(isAMBMessage || isMessageValid(_message));
uint256 requiredSignatures = _validatorContract.requiredSignatures();
uint256 amount;
assembly {
amount := and(mload(add(_signatures, 1)), 0xff)
}
require(amount >= requiredSignatures);
bytes32 hash = hashMessage(_message, isAMBMessage);
address[] memory encounteredAddresses = new address[](requiredSignatures);
for (uint256 i = 0; i < requiredSignatures; i++) {
uint8 v;
bytes32 r;
bytes32 s;
uint256 posr = 33 + amount + 32 * i;
uint256 poss = posr + 32 * amount;
assembly {
v := mload(add(_signatures, add(2, i)))
r := mload(add(_signatures, posr))
s := mload(add(_signatures, poss))
}
address recoveredAddress = ecrecover(hash, v, r, s);
require(_validatorContract.isValidator(recoveredAddress));
require(!addressArrayContains(encounteredAddresses, recoveredAddress));
encounteredAddresses[i] = recoveredAddress;
}
}
function uintToString(uint256 i) internal pure returns (string) {
if (i == 0) return "0";
uint256 j = i;
uint256 length;
while (j != 0) {
length++;
j /= 10;
}
bytes memory bstr = new bytes(length);
uint256 k = length - 1;
while (i != 0) {
bstr[k--] = bytes1(48 + (i % 10));
i /= 10;
}
return string(bstr);
}
}
// File: contracts/libraries/ArbitraryMessage.sol
pragma solidity 0.4.24;
library ArbitraryMessage {
/**
* @dev Unpacks data fields from AMB message
* layout of message :: bytes:
* offset 0 : 32 bytes :: uint256 - message length
* offset 32 : 32 bytes :: bytes32 - messageId
* offset 64 : 20 bytes :: address - sender address
* offset 84 : 20 bytes :: address - executor contract
* offset 104 : 4 bytes :: uint32 - gasLimit
* offset 108 : 1 bytes :: uint8 - source chain id length (X)
* offset 109 : 1 bytes :: uint8 - destination chain id length (Y)
* offset 110 : 1 bytes :: uint8 - dataType
* offset 111 : X bytes :: bytes - source chain id
* offset 111 + X : Y bytes :: bytes - destination chain id
* NOTE: when message structure is changed, make sure that MESSAGE_PACKING_VERSION from VersionableAMB is updated as well
* NOTE: assembly code uses calldatacopy, make sure that message is passed as the first argument in the calldata
* @param _data encoded message
*/
function unpackData(bytes _data)
internal
pure
returns (
bytes32 messageId,
address sender,
address executor,
uint32 gasLimit,
uint8 dataType,
uint256[2] chainIds,
bytes memory data
)
{
// 32 (message id) + 20 (sender) + 20 (executor) + 4 (gasLimit) + 1 (source chain id length) + 1 (destination chain id length) + 1 (dataType)
uint256 srcdataptr = 32 + 20 + 20 + 4 + 1 + 1 + 1;
uint256 datasize;
assembly {
messageId := mload(add(_data, 32)) // 32 bytes
sender := and(mload(add(_data, 52)), 0xffffffffffffffffffffffffffffffffffffffff) // 20 bytes
// executor (20 bytes) + gasLimit (4 bytes) + srcChainIdLength (1 byte) + dstChainIdLength (1 bytes) + dataType (1 byte) + remainder (5 bytes)
let blob := mload(add(_data, 84))
// after bit shift left 12 bytes are zeros automatically
executor := shr(96, blob)
gasLimit := and(shr(64, blob), 0xffffffff)
dataType := byte(26, blob)
// load source chain id length
let chainIdLength := byte(24, blob)
// at this moment srcdataptr points to sourceChainId
// mask for sourceChainId
// e.g. length X -> (1 << (X * 8)) - 1
let mask := sub(shl(shl(3, chainIdLength), 1), 1)
// increase payload offset by length of source chain id
srcdataptr := add(srcdataptr, chainIdLength)
// write sourceChainId
mstore(chainIds, and(mload(add(_data, srcdataptr)), mask))
// at this moment srcdataptr points to destinationChainId
// load destination chain id length
chainIdLength := byte(25, blob)
// mask for destinationChainId
// e.g. length X -> (1 << (X * 8)) - 1
mask := sub(shl(shl(3, chainIdLength), 1), 1)
// increase payload offset by length of destination chain id
srcdataptr := add(srcdataptr, chainIdLength)
// write destinationChainId
mstore(add(chainIds, 32), and(mload(add(_data, srcdataptr)), mask))
// at this moment srcdataptr points to payload
// datasize = message length - payload offset
datasize := sub(mload(_data), srcdataptr)
}
data = new bytes(datasize);
assembly {
// 36 = 4 (selector) + 32 (bytes length header)
srcdataptr := add(srcdataptr, 36)
// calldataload(4) - offset of first bytes argument in the calldata
calldatacopy(add(data, 32), add(calldataload(4), srcdataptr), datasize)
}
}
}
// File: contracts/interfaces/IUpgradeabilityOwnerStorage.sol
pragma solidity 0.4.24;
interface IUpgradeabilityOwnerStorage {
function upgradeabilityOwner() external view returns (address);
}
// 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/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/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: contracts/upgradeable_contracts/InitializableBridge.sol
pragma solidity 0.4.24;
contract InitializableBridge is Initializable {
bytes32 internal constant DEPLOYED_AT_BLOCK = 0xb120ceec05576ad0c710bc6e85f1768535e27554458f05dcbb5c65b8c7a749b0; // keccak256(abi.encodePacked("deployedAtBlock"))
function deployedAtBlock() external view returns (uint256) {
return uintStorage[DEPLOYED_AT_BLOCK];
}
}
// 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: contracts/upgradeable_contracts/ValidatorStorage.sol
pragma solidity 0.4.24;
contract ValidatorStorage {
bytes32 internal constant VALIDATOR_CONTRACT = 0x5a74bb7e202fb8e4bf311841c7d64ec19df195fee77d7e7ae749b27921b6ddfe; // keccak256(abi.encodePacked("validatorContract"))
}
// File: contracts/upgradeable_contracts/Validatable.sol
pragma solidity 0.4.24;
contract Validatable is EternalStorage, ValidatorStorage {
function validatorContract() public view returns (IBridgeValidators) {
return IBridgeValidators(addressStorage[VALIDATOR_CONTRACT]);
}
modifier onlyValidator() {
require(validatorContract().isValidator(msg.sender));
/* solcov ignore next */
_;
}
function requiredSignatures() public view returns (uint256) {
return validatorContract().requiredSignatures();
}
}
// 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 {
_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/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: 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: 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);
}
contract LegacyERC20 {
function transfer(address _spender, uint256 _value) public; // returns (bool);
function transferFrom(address _owner, address _spender, uint256 _value) public; // returns (bool);
}
// File: contracts/libraries/SafeERC20.sol
pragma solidity 0.4.24;
/**
* @title SafeERC20
* @dev Helper methods for safe token transfers.
* Functions perform additional checks to be sure that token transfer really happened.
*/
library SafeERC20 {
using SafeMath for uint256;
/**
* @dev Same as ERC20.transfer(address,uint256) but with extra consistency checks.
* @param _token address of the token contract
* @param _to address of the receiver
* @param _value amount of tokens to send
*/
function safeTransfer(address _token, address _to, uint256 _value) internal {
LegacyERC20(_token).transfer(_to, _value);
assembly {
if returndatasize {
returndatacopy(0, 0, 32)
if iszero(mload(0)) {
revert(0, 0)
}
}
}
}
/**
* @dev Same as ERC20.transferFrom(address,address,uint256) but with extra consistency checks.
* @param _token address of the token contract
* @param _from address of the sender
* @param _value amount of tokens to send
*/
function safeTransferFrom(address _token, address _from, uint256 _value) internal {
LegacyERC20(_token).transferFrom(_from, address(this), _value);
assembly {
if returndatasize {
returndatacopy(0, 0, 32)
if iszero(mload(0)) {
revert(0, 0)
}
}
}
}
}
// File: contracts/upgradeable_contracts/Claimable.sol
pragma solidity 0.4.24;
/**
* @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 address;
/**
* Throws if a given address is equal to address(0)
*/
modifier validAddress(address _to) {
require(_to != address(0));
/* solcov ignore next */
_;
}
/**
* @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;
Address.safeSendValue(_to, value);
}
/**
* @dev Internal function for withdrawing all tokens of ssome 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 {
ERC20Basic token = ERC20Basic(_token);
uint256 balance = token.balanceOf(this);
_token.safeTransfer(_to, balance);
}
}
// 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 (6, 1, 0);
}
/* solcov ignore next */
function getBridgeMode() external pure returns (bytes4);
}
// File: contracts/upgradeable_contracts/DecimalShiftBridge.sol
pragma solidity 0.4.24;
contract DecimalShiftBridge is EternalStorage {
using SafeMath for uint256;
bytes32 internal constant DECIMAL_SHIFT = 0x1e8ecaafaddea96ed9ac6d2642dcdfe1bebe58a930b1085842d8fc122b371ee5; // keccak256(abi.encodePacked("decimalShift"))
/**
* @dev Internal function for setting the decimal shift for bridge operations.
* Decimal shift can be positive, negative, or equal to zero.
* It has the following meaning: N tokens in the foreign chain are equivalent to N * pow(10, shift) tokens on the home side.
* @param _shift new value of decimal shift.
*/
function _setDecimalShift(int256 _shift) internal {
// since 1 wei * 10**77 > 2**255, it does not make any sense to use higher values
require(_shift > -77 && _shift < 77);
uintStorage[DECIMAL_SHIFT] = uint256(_shift);
}
/**
* @dev Returns the value of foreign-to-home decimal shift.
* @return decimal shift.
*/
function decimalShift() public view returns (int256) {
return int256(uintStorage[DECIMAL_SHIFT]);
}
/**
* @dev Converts the amount of home tokens into the equivalent amount of foreign tokens.
* @param _value amount of home tokens.
* @return equivalent amount of foreign tokens.
*/
function _unshiftValue(uint256 _value) internal view returns (uint256) {
return _shiftUint(_value, -decimalShift());
}
/**
* @dev Converts the amount of foreign tokens into the equivalent amount of home tokens.
* @param _value amount of foreign tokens.
* @return equivalent amount of home tokens.
*/
function _shiftValue(uint256 _value) internal view returns (uint256) {
return _shiftUint(_value, decimalShift());
}
/**
* @dev Calculates _value * pow(10, _shift).
* @param _value amount of tokens.
* @param _shift decimal shift to apply.
* @return shifted value.
*/
function _shiftUint(uint256 _value, int256 _shift) private pure returns (uint256) {
if (_shift == 0) {
return _value;
}
if (_shift > 0) {
return _value.mul(10**uint256(_shift));
}
return _value.div(10**uint256(-_shift));
}
}
// File: contracts/upgradeable_contracts/BasicBridge.sol
pragma solidity 0.4.24;
contract BasicBridge is
InitializableBridge,
Validatable,
Ownable,
Upgradeable,
Claimable,
VersionableBridge,
DecimalShiftBridge
{
event GasPriceChanged(uint256 gasPrice);
event RequiredBlockConfirmationChanged(uint256 requiredBlockConfirmations);
bytes32 internal constant GAS_PRICE = 0x55b3774520b5993024893d303890baa4e84b1244a43c60034d1ced2d3cf2b04b; // keccak256(abi.encodePacked("gasPrice"))
bytes32 internal constant REQUIRED_BLOCK_CONFIRMATIONS = 0x916daedf6915000ff68ced2f0b6773fe6f2582237f92c3c95bb4d79407230071; // keccak256(abi.encodePacked("requiredBlockConfirmations"))
/**
* @dev Public setter for fallback gas price value. Only bridge owner can call this method.
* @param _gasPrice new value for the gas price.
*/
function setGasPrice(uint256 _gasPrice) external onlyOwner {
_setGasPrice(_gasPrice);
}
function gasPrice() external view returns (uint256) {
return uintStorage[GAS_PRICE];
}
function setRequiredBlockConfirmations(uint256 _blockConfirmations) external onlyOwner {
_setRequiredBlockConfirmations(_blockConfirmations);
}
function _setRequiredBlockConfirmations(uint256 _blockConfirmations) internal {
require(_blockConfirmations > 0);
uintStorage[REQUIRED_BLOCK_CONFIRMATIONS] = _blockConfirmations;
emit RequiredBlockConfirmationChanged(_blockConfirmations);
}
function requiredBlockConfirmations() external view returns (uint256) {
return uintStorage[REQUIRED_BLOCK_CONFIRMATIONS];
}
/**
* @dev Internal function for updating fallback gas price value.
* @param _gasPrice new value for the gas price, zero gas price is allowed.
*/
function _setGasPrice(uint256 _gasPrice) internal {
uintStorage[GAS_PRICE] = _gasPrice;
emit GasPriceChanged(_gasPrice);
}
}
// File: contracts/upgradeable_contracts/arbitrary_message/VersionableAMB.sol
pragma solidity 0.4.24;
contract VersionableAMB is VersionableBridge {
// message format version as a single 4-bytes number padded to 32-bytes
// value, included into every outgoing relay request
//
// the message version should be updated every time when
// - new field appears
// - some field removed
// - fields order is changed
bytes32 internal constant MESSAGE_PACKING_VERSION = 0x00050000 << 224;
/**
* Returns currently used bridge version
* @return (major, minor, patch) version triple
*/
function getBridgeInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) {
return (6, 2, 0);
}
}
// File: contracts/upgradeable_contracts/arbitrary_message/BasicAMB.sol
pragma solidity 0.4.24;
contract BasicAMB is BasicBridge, VersionableAMB {
bytes32 internal constant MAX_GAS_PER_TX = 0x2670ecc91ec356e32067fd27b36614132d727b84a1e03e08f412a4f2cf075974; // keccak256(abi.encodePacked("maxGasPerTx"))
bytes32 internal constant NONCE = 0x7ab1577440dd7bedf920cb6de2f9fc6bf7ba98c78c85a3fa1f8311aac95e1759; // keccak256(abi.encodePacked("nonce"))
bytes32 internal constant SOURCE_CHAIN_ID = 0x67d6f42a1ed69c62022f2d160ddc6f2f0acd37ad1db0c24f4702d7d3343a4add; // keccak256(abi.encodePacked("sourceChainId"))
bytes32 internal constant SOURCE_CHAIN_ID_LENGTH = 0xe504ae1fd6471eea80f18b8532a61a9bb91fba4f5b837f80a1cfb6752350af44; // keccak256(abi.encodePacked("sourceChainIdLength"))
bytes32 internal constant DESTINATION_CHAIN_ID = 0xbbd454018e72a3f6c02bbd785bacc49e46292744f3f6761276723823aa332320; // keccak256(abi.encodePacked("destinationChainId"))
bytes32 internal constant DESTINATION_CHAIN_ID_LENGTH = 0xfb792ae4ad11102b93f26a51b3749c2b3667f8b561566a4806d4989692811594; // keccak256(abi.encodePacked("destinationChainIdLength"))
bytes32 internal constant ALLOW_REENTRANT_REQUESTS = 0xffa3a5a0e192028fc343362a39c5688e5a60819a4dc5ab3ee70c25bc25b78dd6; // keccak256(abi.encodePacked("allowReentrantRequests"))
/**
* Initializes AMB contract
* @param _sourceChainId chain id of a network where this contract is deployed
* @param _destinationChainId chain id of a network where all outgoing messages are directed
* @param _validatorContract address of the validators contract
* @param _maxGasPerTx maximum amount of gas per one message execution
* @param _gasPrice default gas price used by oracles for sending transactions in this network
* @param _requiredBlockConfirmations number of block confirmations oracle will wait before processing passed messages
* @param _owner address of new bridge owner
*/
function initialize(
uint256 _sourceChainId,
uint256 _destinationChainId,
address _validatorContract,
uint256 _maxGasPerTx,
uint256 _gasPrice,
uint256 _requiredBlockConfirmations,
address _owner
) external onlyRelevantSender returns (bool) {
require(!isInitialized());
require(AddressUtils.isContract(_validatorContract));
_setChainIds(_sourceChainId, _destinationChainId);
addressStorage[VALIDATOR_CONTRACT] = _validatorContract;
uintStorage[DEPLOYED_AT_BLOCK] = block.number;
uintStorage[MAX_GAS_PER_TX] = _maxGasPerTx;
_setGasPrice(_gasPrice);
_setRequiredBlockConfirmations(_requiredBlockConfirmations);
_setOwner(_owner);
setInitialize();
return isInitialized();
}
function getBridgeMode() external pure returns (bytes4 _data) {
return 0x2544fbb9; // bytes4(keccak256(abi.encodePacked("arbitrary-message-bridge-core")))
}
function maxGasPerTx() public view returns (uint256) {
return uintStorage[MAX_GAS_PER_TX];
}
function setMaxGasPerTx(uint256 _maxGasPerTx) external onlyOwner {
uintStorage[MAX_GAS_PER_TX] = _maxGasPerTx;
}
/**
* Internal function for retrieving chain id for the source network
* @return chain id for the current network
*/
function sourceChainId() public view returns (uint256) {
return uintStorage[SOURCE_CHAIN_ID];
}
/**
* Internal function for retrieving chain id for the destination network
* @return chain id for the destination network
*/
function destinationChainId() public view returns (uint256) {
return uintStorage[DESTINATION_CHAIN_ID];
}
/**
* Updates chain ids of used networks
* @param _sourceChainId chain id for current network
* @param _destinationChainId chain id for opposite network
*/
function setChainIds(uint256 _sourceChainId, uint256 _destinationChainId) external onlyOwner {
_setChainIds(_sourceChainId, _destinationChainId);
}
/**
* Sets the flag to allow passing new AMB requests in the opposite direction,
* while other AMB message is being processed.
* Only owner can call this method.
* @param _enable true, if reentrant requests are allowed.
*/
function setAllowReentrantRequests(bool _enable) external onlyOwner {
boolStorage[ALLOW_REENTRANT_REQUESTS] = _enable;
}
/**
* Tells if passing reentrant requests is allowed.
* @return true, if reentrant requests are allowed.
*/
function allowReentrantRequests() public view returns (bool) {
return boolStorage[ALLOW_REENTRANT_REQUESTS];
}
/**
* @dev Withdraws the erc20 tokens or native coins from this contract.
* @param _token address of the claimed token or address(0) for native coins.
* @param _to address of the tokens/coins receiver.
*/
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
claimValues(_token, _to);
}
/**
* Internal function for retrieving current nonce value
* @return nonce value
*/
function _nonce() internal view returns (uint64) {
return uint64(uintStorage[NONCE]);
}
/**
* Internal function for updating nonce value
* @param _nonce new nonce value
*/
function _setNonce(uint64 _nonce) internal {
uintStorage[NONCE] = uint256(_nonce);
}
/**
* Internal function for updating chain ids of used networks
* @param _sourceChainId chain id for current network
* @param _destinationChainId chain id for opposite network
*/
function _setChainIds(uint256 _sourceChainId, uint256 _destinationChainId) internal {
require(_sourceChainId > 0 && _destinationChainId > 0);
require(_sourceChainId != _destinationChainId);
// Length fields are needed further when encoding the message.
// Chain ids are compressed, so that leading zero bytes are not preserved.
// In order to save some gas during calls to MessageDelivery.c,
// lengths of chain ids are precalculated and being saved in the storage.
uint256 sourceChainIdLength = 0;
uint256 destinationChainIdLength = 0;
uint256 mask = 0xff;
for (uint256 i = 1; sourceChainIdLength == 0 || destinationChainIdLength == 0; i++) {
if (sourceChainIdLength == 0 && _sourceChainId & mask == _sourceChainId) {
sourceChainIdLength = i;
}
if (destinationChainIdLength == 0 && _destinationChainId & mask == _destinationChainId) {
destinationChainIdLength = i;
}
mask = (mask << 8) | 0xff;
}
uintStorage[SOURCE_CHAIN_ID] = _sourceChainId;
uintStorage[SOURCE_CHAIN_ID_LENGTH] = sourceChainIdLength;
uintStorage[DESTINATION_CHAIN_ID] = _destinationChainId;
uintStorage[DESTINATION_CHAIN_ID_LENGTH] = destinationChainIdLength;
}
/**
* Internal function for retrieving chain id length for the source network
* @return chain id for the current network
*/
function _sourceChainIdLength() internal view returns (uint256) {
return uintStorage[SOURCE_CHAIN_ID_LENGTH];
}
/**
* Internal function for retrieving chain id length for the destination network
* @return chain id for the destination network
*/
function _destinationChainIdLength() internal view returns (uint256) {
return uintStorage[DESTINATION_CHAIN_ID_LENGTH];
}
/**
* Internal function for validating version of the received message
* @param _messageId id of the received message
*/
function _isMessageVersionValid(bytes32 _messageId) internal returns (bool) {
return
_messageId & 0xffffffff00000000000000000000000000000000000000000000000000000000 == MESSAGE_PACKING_VERSION;
}
/**
* Internal function for validating destination chain id of the received message
* @param _chainId destination chain id of the received message
*/
function _isDestinationChainIdValid(uint256 _chainId) internal returns (bool res) {
return _chainId == sourceChainId();
}
}
// 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/arbitrary_message/MessageProcessor.sol
pragma solidity 0.4.24;
contract MessageProcessor is EternalStorage {
/**
* @dev Returns a status of the message that came from the other side.
* @param _messageId id of the message from the other side that triggered a call.
* @return true if call executed successfully.
*/
function messageCallStatus(bytes32 _messageId) external view returns (bool) {
return boolStorage[keccak256(abi.encodePacked("messageCallStatus", _messageId))];
}
/**
* @dev Sets a status of the message that came from the other side.
* @param _messageId id of the message from the other side that triggered a call.
* @param _status execution status, true if executed successfully.
*/
function setMessageCallStatus(bytes32 _messageId, bool _status) internal {
boolStorage[keccak256(abi.encodePacked("messageCallStatus", _messageId))] = _status;
}
/**
* @dev Returns a data hash of the failed message that came from the other side.
* NOTE: dataHash was used previously to identify outgoing message before AMB message id was introduced.
* It is kept for backwards compatibility with old mediators contracts.
* @param _messageId id of the message from the other side that triggered a call.
* @return keccak256 hash of message data.
*/
function failedMessageDataHash(bytes32 _messageId) external view returns (bytes32) {
return bytes32(uintStorage[keccak256(abi.encodePacked("failedMessageDataHash", _messageId))]);
}
/**
* @dev Sets a data hash of the failed message that came from the other side.
* NOTE: dataHash was used previously to identify outgoing message before AMB message id was introduced.
* It is kept for backwards compatibility with old mediators contracts.
* @param _messageId id of the message from the other side that triggered a call.
* @param data of the processed message.
*/
function setFailedMessageDataHash(bytes32 _messageId, bytes data) internal {
uintStorage[keccak256(abi.encodePacked("failedMessageDataHash", _messageId))] = uint256(keccak256(data));
}
/**
* @dev Returns a receiver address of the failed message that came from the other side.
* @param _messageId id of the message from the other side that triggered a call.
* @return receiver address.
*/
function failedMessageReceiver(bytes32 _messageId) external view returns (address) {
return addressStorage[keccak256(abi.encodePacked("failedMessageReceiver", _messageId))];
}
/**
* @dev Sets a sender address of the failed message that came from the other side.
* @param _messageId id of the message from the other side that triggered a call.
* @param _receiver address of the receiver.
*/
function setFailedMessageReceiver(bytes32 _messageId, address _receiver) internal {
addressStorage[keccak256(abi.encodePacked("failedMessageReceiver", _messageId))] = _receiver;
}
/**
* @dev Returns a sender address of the failed message that came from the other side.
* @param _messageId id of the message from the other side that triggered a call.
* @return sender address on the other side.
*/
function failedMessageSender(bytes32 _messageId) external view returns (address) {
return addressStorage[keccak256(abi.encodePacked("failedMessageSender", _messageId))];
}
/**
* @dev Sets a sender address of the failed message that came from the other side.
* @param _messageId id of the message from the other side that triggered a call.
* @param _sender address of the sender on the other side.
*/
function setFailedMessageSender(bytes32 _messageId, address _sender) internal {
addressStorage[keccak256(abi.encodePacked("failedMessageSender", _messageId))] = _sender;
}
/**
* @dev Returns an address of the sender on the other side for the currently processed message.
* Can be used by executors for getting other side caller address.
* @return address of the sender on the other side.
*/
function messageSender() external view returns (address sender) {
assembly {
// Even though this is not the same as addressStorage[keccak256(abi.encodePacked("messageSender"))],
// 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.
sender := sload(0x7b58b2a669d8e0992eae9eaef641092c0f686fd31070e7236865557fa1571b5b) // keccak256(abi.encodePacked("messageSender"))
}
}
/**
* @dev Sets an address of the sender on the other side for the currently processed message.
* @param _sender address of the sender on the other side.
*/
function setMessageSender(address _sender) internal {
assembly {
// Even though this is not the same as addressStorage[keccak256(abi.encodePacked("messageSender"))],
// 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(0x7b58b2a669d8e0992eae9eaef641092c0f686fd31070e7236865557fa1571b5b, _sender) // keccak256(abi.encodePacked("messageSender"))
}
}
/**
* @dev Returns an id of the currently processed message.
* @return id of the message that originated on the other side.
*/
function messageId() public view returns (bytes32 id) {
assembly {
// Even though this is not the same as uintStorage[keccak256(abi.encodePacked("messageId"))],
// 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.
id := sload(0xe34bb2103dc34f2c144cc216c132d6ffb55dac57575c22e089161bbe65083304) // keccak256(abi.encodePacked("messageId"))
}
}
/**
* @dev Returns an id of the currently processed message.
* NOTE: transactionHash was used previously to identify incoming message before AMB message id was introduced.
* It is kept for backwards compatibility with old mediators contracts, although it doesn't return txHash anymore.
* @return id of the message that originated on the other side.
*/
function transactionHash() external view returns (bytes32) {
return messageId();
}
/**
* @dev Sets a message id of the currently processed message.
* @param _messageId id of the message that originated on the other side.
*/
function setMessageId(bytes32 _messageId) internal {
assembly {
// Even though this is not the same as uintStorage[keccak256(abi.encodePacked("messageId"))],
// 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(0xe34bb2103dc34f2c144cc216c132d6ffb55dac57575c22e089161bbe65083304, _messageId) // keccak256(abi.encodePacked("messageId"))
}
}
/**
* @dev Returns an originating chain id of the currently processed message.
* @return source chain id of the message that originated on the other side.
*/
function messageSourceChainId() external view returns (uint256 id) {
assembly {
// Even though this is not the same as uintStorage[keccak256(abi.encodePacked("messageSourceChainId"))],
// 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.
id := sload(0x7f0fcd9e49860f055dd0c1682d635d309ecb5e3011654c716d9eb59a7ddec7d2) // keccak256(abi.encodePacked("messageSourceChainId"))
}
}
/**
* @dev Sets an originating chain id of the currently processed message.
* @param _sourceChainId source chain id of the message that originated on the other side.
*/
function setMessageSourceChainId(uint256 _sourceChainId) internal {
assembly {
// Even though this is not the same as uintStorage[keccak256(abi.encodePacked("messageSourceChainId"))],
// 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(0x7f0fcd9e49860f055dd0c1682d635d309ecb5e3011654c716d9eb59a7ddec7d2, _sourceChainId) // keccak256(abi.encodePacked("messageSourceChainId"))
}
}
/**
* @dev Processes received message. Makes a call to the message executor,
* sets dataHash, receive, sender variables for failed messages.
* @param _sender sender address on the other side.
* @param _executor address of an executor.
* @param _messageId id of the processed message.
* @param _gasLimit gas limit for a call to executor.
* @param _sourceChainId source chain id is of the received message.
* @param _data calldata for a call to executor.
*/
function processMessage(
address _sender,
address _executor,
bytes32 _messageId,
uint256 _gasLimit,
uint8, /* dataType */
uint256 _sourceChainId,
bytes memory _data
) internal {
bool status = _passMessage(_sender, _executor, _data, _gasLimit, _messageId, _sourceChainId);
setMessageCallStatus(_messageId, status);
if (!status) {
setFailedMessageDataHash(_messageId, _data);
setFailedMessageReceiver(_messageId, _executor);
setFailedMessageSender(_messageId, _sender);
}
emitEventOnMessageProcessed(_sender, _executor, _messageId, status);
}
/**
* @dev Makes a call to the message executor.
* @param _sender sender address on the other side.
* @param _contract address of an executor contract.
* @param _data calldata for a call to executor.
* @param _gas gas limit for a call to executor. 2^32 - 1, if caller will pass all available gas for the execution.
* @param _messageId id of the processed message.
* @param _sourceChainId source chain id is of the received message.
*/
function _passMessage(
address _sender,
address _contract,
bytes _data,
uint256 _gas,
bytes32 _messageId,
uint256 _sourceChainId
) internal returns (bool) {
setMessageSender(_sender);
setMessageId(_messageId);
setMessageSourceChainId(_sourceChainId);
// After EIP-150, max gas cost allowed to be passed to the internal call is equal to the 63/64 of total gas left.
// In reality, min(gasLimit, 63/64 * gasleft()) will be used as the call gas limit.
// Imagine a situation, when message requires 10000000 gas to be executed successfully.
// Also suppose, that at this point, gasleft() is equal to 10158000, so the callee will receive ~ 10158000 * 63 / 64 = 9999300 gas.
// That amount of gas is not enough, so the call will fail. At the same time,
// even if the callee failed the bridge contract still has ~ 158000 gas to
// finish its execution and it will be enough. The internal call fails but
// only because the oracle provides incorrect gas limit for the transaction
// This check is needed here in order to force contract to pass exactly the requested amount of gas.
// Avoiding it may lead to the unwanted message failure in some extreme cases.
require(_gas == 0xffffffff || (gasleft() * 63) / 64 > _gas);
bool status = _contract.call.gas(_gas)(_data);
_validateExecutionStatus(status);
setMessageSender(address(0));
setMessageId(bytes32(0));
setMessageSourceChainId(0);
return status;
}
/**
* @dev Validates message execution status. In simplest case, does nothing.
* @param _status message execution status.
*/
function _validateExecutionStatus(bool _status) internal {
(_status);
}
/* solcov ignore next */
function emitEventOnMessageProcessed(address sender, address executor, bytes32 messageId, bool status) internal;
}
// File: contracts/upgradeable_contracts/arbitrary_message/MessageDelivery.sol
pragma solidity 0.4.24;
contract MessageDelivery is BasicAMB, MessageProcessor {
using SafeMath for uint256;
uint256 internal constant SEND_TO_ORACLE_DRIVEN_LANE = 0x00;
// after EIP2929, call to warmed contract address costs 100 instead of 2600
uint256 internal constant MIN_GAS_PER_CALL = 100;
/**
* @dev Requests message relay to the opposite network
* @param _contract executor address on the other side
* @param _data calldata passed to the executor on the other side
* @param _gas gas limit used on the other network for executing a message
*/
function requireToPassMessage(address _contract, bytes memory _data, uint256 _gas) public returns (bytes32) {
return _sendMessage(_contract, _data, _gas, SEND_TO_ORACLE_DRIVEN_LANE);
}
/**
* @dev Initiates sending of an AMB message to the opposite network
* @param _contract executor address on the other side
* @param _data calldata passed to the executor on the other side
* @param _gas gas limit used on the other network for executing a message
* @param _dataType AMB message dataType to be included as a part of the header
*/
function _sendMessage(address _contract, bytes memory _data, uint256 _gas, uint256 _dataType)
internal
returns (bytes32)
{
// it is not allowed to pass messages while other messages are processed
// if other is not explicitly configured
require(messageId() == bytes32(0) || allowReentrantRequests());
require(_gas >= MIN_GAS_PER_CALL && _gas <= maxGasPerTx());
uint256 selector;
assembly {
selector := and(mload(add(_data, 4)), 0xffffffff)
}
// In order to prevent possible unauthorized ERC20 withdrawals, the following function signatures are prohibited:
// * transfer(address,uint256)
// * approve(address,uint256)
// * transferFrom(address,address,uint256)
// * approveAndCall(address,uint256,bytes)
// * transferAndCall(address,uint256,bytes)
// See https://medium.com/immunefi/xdai-stake-arbitrary-call-method-bug-postmortem-f80a90ac56e3 for more details
require(
selector != 0xa9059cbb &&
selector != 0x095ea7b3 &&
selector != 0x23b872dd &&
selector != 0x4000aea0 &&
selector != 0xcae9ca51
);
(bytes32 _messageId, bytes memory header) = _packHeader(_contract, _gas, _dataType);
bytes memory eventData = abi.encodePacked(header, _data);
emitEventOnMessageRequest(_messageId, eventData);
return _messageId;
}
/**
* @dev Packs message header into a single bytes blob
* @param _contract executor address on the other side
* @param _gas gas limit used on the other network for executing a message
* @param _dataType AMB message dataType to be included as a part of the header
*/
function _packHeader(address _contract, uint256 _gas, uint256 _dataType)
internal
view
returns (bytes32 _messageId, bytes memory header)
{
uint256 srcChainId = sourceChainId();
uint256 srcChainIdLength = _sourceChainIdLength();
uint256 dstChainId = destinationChainId();
uint256 dstChainIdLength = _destinationChainIdLength();
_messageId = _getNewMessageId(srcChainId);
// 79 = 4 + 20 + 8 + 20 + 20 + 4 + 1 + 1 + 1
header = new bytes(79 + srcChainIdLength + dstChainIdLength);
// In order to save the gas, the header is packed in the reverse order.
// With such approach, it is possible to store right-aligned values without any additional bit shifts.
assembly {
let ptr := add(header, mload(header)) // points to the last word of header
mstore(ptr, dstChainId)
mstore(sub(ptr, dstChainIdLength), srcChainId)
mstore(add(header, 79), _dataType)
mstore(add(header, 78), dstChainIdLength)
mstore(add(header, 77), srcChainIdLength)
mstore(add(header, 76), _gas)
mstore(add(header, 72), _contract)
mstore(add(header, 52), caller)
mstore(add(header, 32), _messageId)
}
}
/**
* @dev Generates a new messageId for the passed request/message.
* Increments the nonce accordingly.
* @param _srcChainId source chain id of the newly created message. Should be a chain id of the current network.
* @return unique message id to use for the new request/message.
*/
function _getNewMessageId(uint256 _srcChainId) internal returns (bytes32) {
uint64 nonce = _nonce();
_setNonce(nonce + 1);
// Bridge id is recalculated every time again and again, since it is still cheaper than using SLOAD opcode (800 gas)
bytes32 bridgeId = keccak256(abi.encodePacked(_srcChainId, address(this))) &
0x00000000ffffffffffffffffffffffffffffffffffffffff0000000000000000;
return MESSAGE_PACKING_VERSION | bridgeId | bytes32(nonce);
}
/* solcov ignore next */
function emitEventOnMessageRequest(bytes32 messageId, bytes encodedData) internal;
}
// File: contracts/upgradeable_contracts/arbitrary_message/BasicHomeAMB.sol
pragma solidity 0.4.24;
contract BasicHomeAMB is BasicAMB, MessageDelivery {
event SignedForUserRequest(address indexed signer, bytes32 messageHash);
event SignedForAffirmation(address indexed signer, bytes32 messageHash);
event CollectedSignatures(
address authorityResponsibleForRelay,
bytes32 messageHash,
uint256 NumberOfCollectedSignatures
);
uint256 internal constant SEND_TO_MANUAL_LANE = 0x80;
function executeAffirmation(bytes message) external onlyValidator {
bytes32 hashMsg = keccak256(abi.encodePacked(message));
bytes32 hashSender = keccak256(abi.encodePacked(msg.sender, hashMsg));
// Duplicated affirmations
require(!affirmationsSigned(hashSender));
setAffirmationsSigned(hashSender, true);
uint256 signed = numAffirmationsSigned(hashMsg);
require(!isAlreadyProcessed(signed));
// the check above assumes that the case when the value could be overflew will not happen in the addition operation below
signed = signed + 1;
setNumAffirmationsSigned(hashMsg, signed);
emit SignedForAffirmation(msg.sender, hashMsg);
if (signed >= requiredSignatures()) {
setNumAffirmationsSigned(hashMsg, markAsProcessed(signed));
handleMessage(message);
}
}
/**
* @dev Requests message relay to the opposite network, message is sent to the manual lane.
* @param _contract executor address on the other side.
* @param _data calldata passed to the executor on the other side.
* @param _gas gas limit used on the other network for executing a message.
*/
function requireToConfirmMessage(address _contract, bytes memory _data, uint256 _gas) public returns (bytes32) {
return _sendMessage(_contract, _data, _gas, SEND_TO_MANUAL_LANE);
}
/**
* Parses given message, processes a call inside it
* @param _message relayed message
*/
function handleMessage(bytes _message) internal {
bytes32 messageId;
address sender;
address executor;
uint32 gasLimit;
uint8 dataType;
uint256[2] memory chainIds;
bytes memory data;
(messageId, sender, executor, gasLimit, dataType, chainIds, data) = ArbitraryMessage.unpackData(_message);
require(_isMessageVersionValid(messageId));
require(_isDestinationChainIdValid(chainIds[1]));
processMessage(sender, executor, messageId, gasLimit, dataType, chainIds[0], data);
}
function submitSignature(bytes signature, bytes message) external onlyValidator {
// ensure that `signature` is really `message` signed by `msg.sender`
require(msg.sender == Message.recoverAddressFromSignedMessage(signature, message, true));
bytes32 hashMsg = keccak256(abi.encodePacked(message));
bytes32 hashSender = keccak256(abi.encodePacked(msg.sender, hashMsg));
uint256 signed = numMessagesSigned(hashMsg);
require(!isAlreadyProcessed(signed));
// the check above assumes that the case when the value could be overflew
// will not happen in the addition operation below
signed = signed + 1;
if (signed > 1) {
// Duplicated signatures
require(!messagesSigned(hashSender));
} else {
setMessages(hashMsg, message);
}
setMessagesSigned(hashSender, true);
bytes32 signIdx = keccak256(abi.encodePacked(hashMsg, (signed.sub(1))));
setSignatures(signIdx, signature);
setNumMessagesSigned(hashMsg, signed);
emit SignedForUserRequest(msg.sender, hashMsg);
uint256 reqSigs = requiredSignatures();
if (signed >= reqSigs) {
setNumMessagesSigned(hashMsg, markAsProcessed(signed));
emit CollectedSignatures(msg.sender, hashMsg, reqSigs);
}
}
function isAlreadyProcessed(uint256 _number) public pure returns (bool) {
return _number & (2**255) == 2**255;
}
function numMessagesSigned(bytes32 _message) public view returns (uint256) {
return uintStorage[keccak256(abi.encodePacked("numMessagesSigned", _message))];
}
function signature(bytes32 _hash, uint256 _index) public view returns (bytes) {
bytes32 signIdx = keccak256(abi.encodePacked(_hash, _index));
return bytesStorage[keccak256(abi.encodePacked("signatures", signIdx))];
}
function messagesSigned(bytes32 _message) public view returns (bool) {
return boolStorage[keccak256(abi.encodePacked("messagesSigned", _message))];
}
function message(bytes32 _hash) public view returns (bytes) {
return messages(_hash);
}
function affirmationsSigned(bytes32 _hash) public view returns (bool) {
return boolStorage[keccak256(abi.encodePacked("affirmationsSigned", _hash))];
}
function numAffirmationsSigned(bytes32 _hash) public view returns (uint256) {
return uintStorage[keccak256(abi.encodePacked("numAffirmationsSigned", _hash))];
}
function setMessagesSigned(bytes32 _hash, bool _status) internal {
boolStorage[keccak256(abi.encodePacked("messagesSigned", _hash))] = _status;
}
function messages(bytes32 _hash) internal view returns (bytes) {
return bytesStorage[keccak256(abi.encodePacked("messages", _hash))];
}
function setSignatures(bytes32 _hash, bytes _signature) internal {
bytesStorage[keccak256(abi.encodePacked("signatures", _hash))] = _signature;
}
function setMessages(bytes32 _hash, bytes _message) internal {
bytesStorage[keccak256(abi.encodePacked("messages", _hash))] = _message;
}
function setNumMessagesSigned(bytes32 _message, uint256 _number) internal {
uintStorage[keccak256(abi.encodePacked("numMessagesSigned", _message))] = _number;
}
function markAsProcessed(uint256 _v) internal pure returns (uint256) {
return _v | (2**255);
}
function setAffirmationsSigned(bytes32 _hash, bool _status) internal {
boolStorage[keccak256(abi.encodePacked("affirmationsSigned", _hash))] = _status;
}
function setNumAffirmationsSigned(bytes32 _hash, uint256 _number) internal {
uintStorage[keccak256(abi.encodePacked("numAffirmationsSigned", _hash))] = _number;
}
}
// File: contracts/upgradeable_contracts/arbitrary_message/AsyncInformationProcessor.sol
pragma solidity 0.4.24;
/**
* @title AsyncInformationProcessor
* @dev Functionality for making and processing async calls on Home side of the AMB.
*/
contract AsyncInformationProcessor is BasicHomeAMB {
event UserRequestForInformation(
bytes32 indexed messageId,
bytes32 indexed requestSelector,
address indexed sender,
bytes data
);
event SignedForInformation(address indexed signer, bytes32 indexed messageId);
event InformationRetrieved(bytes32 indexed messageId, bool status, bool callbackStatus);
event EnabledAsyncRequestSelector(bytes32 indexed requestSelector, bool enable);
/**
* @dev Makes an asynchronous request to get information from the opposite network.
* Call result will be returned later to the callee, by using the onInformationReceived(bytes) callback function.
* @param _requestSelector selector for the async request.
* @param _data payload for the given selector
*/
function requireToGetInformation(bytes32 _requestSelector, bytes _data) external returns (bytes32) {
// it is not allowed to pass messages while other messages are processed
// if other is not explicitly configured
require(messageId() == bytes32(0) || allowReentrantRequests());
// only contracts are allowed to call this method, since EOA won't be able to receive a callback.
require(AddressUtils.isContract(msg.sender));
require(isAsyncRequestSelectorEnabled(_requestSelector));
bytes32 _messageId = _getNewMessageId(sourceChainId());
_setAsyncRequestSender(_messageId, msg.sender);
emit UserRequestForInformation(_messageId, _requestSelector, msg.sender, _data);
return _messageId;
}
/**
* Tells if the specific async request selector is allowed to be used and supported by the bridge oracles.
* @param _requestSelector selector for the async request.
* @return true, if selector is allowed to be used.
*/
function isAsyncRequestSelectorEnabled(bytes32 _requestSelector) public view returns (bool) {
return boolStorage[keccak256(abi.encodePacked("enableRequestSelector", _requestSelector))];
}
/**
* Enables or disables the specific async request selector.
* Only owner can call this method.
* @param _requestSelector selector for the async request.
* @param _enable true, if the selector should be allowed.
*/
function enableAsyncRequestSelector(bytes32 _requestSelector, bool _enable) external onlyOwner {
boolStorage[keccak256(abi.encodePacked("enableRequestSelector", _requestSelector))] = _enable;
emit EnabledAsyncRequestSelector(_requestSelector, _enable);
}
/**
* @dev Submits result of the async call.
* Only validators are allowed to call this method.
* Once enough confirmations are collected, callback function is called.
* @param _messageId unique id of the request that was previously made.
* @param _status true, if JSON-RPC request succeeded, false otherwise.
* @param _result call result returned by the other side of the bridge.
*/
function confirmInformation(bytes32 _messageId, bool _status, bytes _result) external onlyValidator {
bytes32 hashMsg = keccak256(abi.encodePacked(_messageId, _status, _result));
bytes32 hashSender = keccak256(abi.encodePacked(msg.sender, hashMsg));
// Duplicated confirmations
require(!affirmationsSigned(hashSender));
setAffirmationsSigned(hashSender, true);
uint256 signed = numAffirmationsSigned(hashMsg);
require(!isAlreadyProcessed(signed));
// the check above assumes that the case when the value could be overflew will not happen in the addition operation below
signed = signed + 1;
setNumAffirmationsSigned(hashMsg, signed);
emit SignedForInformation(msg.sender, _messageId);
if (signed >= requiredSignatures()) {
setNumAffirmationsSigned(hashMsg, markAsProcessed(signed));
address sender = _restoreAsyncRequestSender(_messageId);
bytes memory data = abi.encodeWithSelector(
IAMBInformationReceiver(address(0)).onInformationReceived.selector,
_messageId,
_status,
_result
);
uint256 gas = maxGasPerTx();
require((gasleft() * 63) / 64 > gas);
bool callbackStatus = sender.call.gas(gas)(data);
emit InformationRetrieved(_messageId, _status, callbackStatus);
}
}
/**
* Internal function for saving async request sender for future use.
* @param _messageId id of the sent async request.
* @param _sender address of the request sender, receiver of the callback.
*/
function _setAsyncRequestSender(bytes32 _messageId, address _sender) internal {
addressStorage[keccak256(abi.encodePacked("asyncSender", _messageId))] = _sender;
}
/**
* Internal function for restoring async request sender information.
* @param _messageId id of the sent async request.
* @return address of async request sender and callback receiver.
*/
function _restoreAsyncRequestSender(bytes32 _messageId) internal returns (address) {
bytes32 hash = keccak256(abi.encodePacked("asyncSender", _messageId));
address sender = addressStorage[hash];
require(sender != address(0));
delete addressStorage[hash];
return sender;
}
}
// File: contracts/upgradeable_contracts/arbitrary_message/HomeAMB.sol
pragma solidity 0.4.24;
contract HomeAMB is AsyncInformationProcessor {
event UserRequestForSignature(bytes32 indexed messageId, bytes encodedData);
event AffirmationCompleted(
address indexed sender,
address indexed executor,
bytes32 indexed messageId,
bool status
);
function emitEventOnMessageRequest(bytes32 messageId, bytes encodedData) internal {
emit UserRequestForSignature(messageId, encodedData);
}
function emitEventOnMessageProcessed(address sender, address executor, bytes32 messageId, bool status) internal {
emit AffirmationCompleted(sender, executor, messageId, status);
}
}
Contract ABI
[{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"transactionHash","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"numMessagesSigned","inputs":[{"type":"bytes32","name":"_message"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"confirmInformation","inputs":[{"type":"bytes32","name":"_messageId"},{"type":"bool","name":"_status"},{"type":"bytes","name":"_result"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"sourceChainId","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes","name":""}],"name":"signature","inputs":[{"type":"bytes32","name":"_hash"},{"type":"uint256","name":"_index"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"initialize","inputs":[{"type":"uint256","name":"_sourceChainId"},{"type":"uint256","name":"_destinationChainId"},{"type":"address","name":"_validatorContract"},{"type":"uint256","name":"_maxGasPerTx"},{"type":"uint256","name":"_gasPrice"},{"type":"uint256","name":"_requiredBlockConfirmations"},{"type":"address","name":"_owner"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isInitialized","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"requiredBlockConfirmations","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"failedMessageReceiver","inputs":[{"type":"bytes32","name":"_messageId"}],"constant":true},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"bytes4","name":"_data"}],"name":"getBridgeMode","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setChainIds","inputs":[{"type":"uint256","name":"_sourceChainId"},{"type":"uint256","name":"_destinationChainId"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes","name":""}],"name":"message","inputs":[{"type":"bytes32","name":"_hash"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"failedMessageSender","inputs":[{"type":"bytes32","name":"_messageId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"allowReentrantRequests","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"requireToGetInformation","inputs":[{"type":"bytes32","name":"_requestSelector"},{"type":"bytes","name":"_data"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"submitSignature","inputs":[{"type":"bytes","name":"signature"},{"type":"bytes","name":"message"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":"id"}],"name":"messageId","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":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"numAffirmationsSigned","inputs":[{"type":"bytes32","name":"_hash"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"affirmationsSigned","inputs":[{"type":"bytes32","name":"_hash"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setMaxGasPerTx","inputs":[{"type":"uint256","name":"_maxGasPerTx"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"requiredSignatures","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"owner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"messagesSigned","inputs":[{"type":"bytes32","name":"_message"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"requireToConfirmMessage","inputs":[{"type":"address","name":"_contract"},{"type":"bytes","name":"_data"},{"type":"uint256","name":"_gas"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"validatorContract","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"deployedAtBlock","inputs":[],"constant":true},{"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":"id"}],"name":"messageSourceChainId","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setRequiredBlockConfirmations","inputs":[{"type":"uint256","name":"_blockConfirmations"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"destinationChainId","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setGasPrice","inputs":[{"type":"uint256","name":"_gasPrice"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setAllowReentrantRequests","inputs":[{"type":"bool","name":"_enable"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"enableAsyncRequestSelector","inputs":[{"type":"bytes32","name":"_requestSelector"},{"type":"bool","name":"_enable"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"messageCallStatus","inputs":[{"type":"bytes32","name":"_messageId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"sender"}],"name":"messageSender","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"int256","name":""}],"name":"decimalShift","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"requireToPassMessage","inputs":[{"type":"address","name":"_contract"},{"type":"bytes","name":"_data"},{"type":"uint256","name":"_gas"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"failedMessageDataHash","inputs":[{"type":"bytes32","name":"_messageId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"maxGasPerTx","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"executeAffirmation","inputs":[{"type":"bytes","name":"message"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isAsyncRequestSelectorEnabled","inputs":[{"type":"bytes32","name":"_requestSelector"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"gasPrice","inputs":[],"constant":true},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isAlreadyProcessed","inputs":[{"type":"uint256","name":"_number"}],"constant":true},{"type":"event","name":"UserRequestForSignature","inputs":[{"type":"bytes32","name":"messageId","indexed":true},{"type":"bytes","name":"encodedData","indexed":false}],"anonymous":false},{"type":"event","name":"AffirmationCompleted","inputs":[{"type":"address","name":"sender","indexed":true},{"type":"address","name":"executor","indexed":true},{"type":"bytes32","name":"messageId","indexed":true},{"type":"bool","name":"status","indexed":false}],"anonymous":false},{"type":"event","name":"UserRequestForInformation","inputs":[{"type":"bytes32","name":"messageId","indexed":true},{"type":"bytes32","name":"requestSelector","indexed":true},{"type":"address","name":"sender","indexed":true},{"type":"bytes","name":"data","indexed":false}],"anonymous":false},{"type":"event","name":"SignedForInformation","inputs":[{"type":"address","name":"signer","indexed":true},{"type":"bytes32","name":"messageId","indexed":true}],"anonymous":false},{"type":"event","name":"InformationRetrieved","inputs":[{"type":"bytes32","name":"messageId","indexed":true},{"type":"bool","name":"status","indexed":false},{"type":"bool","name":"callbackStatus","indexed":false}],"anonymous":false},{"type":"event","name":"EnabledAsyncRequestSelector","inputs":[{"type":"bytes32","name":"requestSelector","indexed":true},{"type":"bool","name":"enable","indexed":false}],"anonymous":false},{"type":"event","name":"SignedForUserRequest","inputs":[{"type":"address","name":"signer","indexed":true},{"type":"bytes32","name":"messageHash","indexed":false}],"anonymous":false},{"type":"event","name":"SignedForAffirmation","inputs":[{"type":"address","name":"signer","indexed":true},{"type":"bytes32","name":"messageHash","indexed":false}],"anonymous":false},{"type":"event","name":"CollectedSignatures","inputs":[{"type":"address","name":"authorityResponsibleForRelay","indexed":false},{"type":"bytes32","name":"messageHash","indexed":false},{"type":"uint256","name":"NumberOfCollectedSignatures","indexed":false}],"anonymous":false},{"type":"event","name":"GasPriceChanged","inputs":[{"type":"uint256","name":"gasPrice","indexed":false}],"anonymous":false},{"type":"event","name":"RequiredBlockConfirmationChanged","inputs":[{"type":"uint256","name":"requiredBlockConfirmations","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":false},{"type":"address","name":"newOwner","indexed":false}],"anonymous":false}]
Contract Creation Code
0x608060405234801561001057600080fd5b50614353806100206000396000f30060806040526004361061020b5763ffffffff60e060020a6000350416630ac1c31381146102105780630cbf0601146102375780630f08d4d01461024f5780631544298e1461027b5780631812d9961461029057806325fbf4ee14610320578063392e53cd1461036d5780633f0a9f65146103825780633f9a8e7e14610397578063437764df146103cb578063467ad35a14610412578063490a32c61461042d5780634a610b04146104455780634d4cb7a21461045d578063525ea93714610472578063630cea8e14610496578063669f618b146104c257806369ffa08a146104d75780636ae1a976146104fe5780637698da24146105165780637bac29c71461052e5780638d068043146105465780638da5cb5b1461055b5780638f4b4b981461057057806394643f711461058857806399439089146105f15780639a454b99146106065780639cb7595a1461061b5780639e307dff1461065c578063acf5c68914610671578063b075061114610689578063bf1fe4201461069e578063c2231ad2146106b6578063c29b1e8a146106d0578063cb08a10c146106ed578063d67bdd2514610705578063dae5f0fd1461071a578063dc8601b31461072f578063e37c328914610798578063e5789d03146107b0578063e7a2c01f146107c5578063f2fde38b146107e5578063fb67e77914610806578063fe173b971461081e578063ffd19e8c14610833575b600080fd5b34801561021c57600080fd5b5061022561084b565b60408051918252519081900360200190f35b34801561024357600080fd5b5061022560043561085b565b34801561025b57600080fd5b50610279600480359060248035151591604435918201910135610920565b005b34801561028757600080fd5b50610225610d54565b34801561029c57600080fd5b506102ab600435602435610da2565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102e55781810151838201526020016102cd565b50505050905090810190601f1680156103125780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561032c57600080fd5b50610359600435602435600160a060020a03604435811690606435906084359060a4359060c43516610f7f565b604080519115158252519081900360200190f35b34801561037957600080fd5b506103596111f3565b34801561038e57600080fd5b50610225611244565b3480156103a357600080fd5b506103af600435611292565b60408051600160a060020a039092168252519081900360200190f35b3480156103d757600080fd5b506103e0611361565b604080517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff199092168252519081900360200190f35b34801561041e57600080fd5b50610279600435602435611385565b34801561043957600080fd5b506102ab6004356113af565b34801561045157600080fd5b506103af6004356113c0565b34801561046957600080fd5b50610359611444565b34801561047e57600080fd5b50610225600480359060248035908101910135611495565b3480156104a257600080fd5b50610279602460048035828101929082013591813591820191013561155d565b3480156104ce57600080fd5b50610225611989565b3480156104e357600080fd5b50610279600160a060020a03600435811690602435166119ae565b34801561050a57600080fd5b50610225600435611a36565b34801561052257600080fd5b50610359600435611ab9565b34801561053a57600080fd5b50610279600435611b82565b34801561055257600080fd5b50610225611beb565b34801561056757600080fd5b506103af611c63565b34801561057c57600080fd5b50610359600435611cba565b34801561059457600080fd5b5060408051602060046024803582810135601f8101859004850286018501909652858552610225958335600160a060020a03169536956044949193909101919081908401838280828437509497505093359450611d3e9350505050565b3480156105fd57600080fd5b506103af611d55565b34801561061257600080fd5b50610225611dac565b34801561062757600080fd5b50610630611dfa565b6040805167ffffffffffffffff9485168152928416602084015292168183015290519081900360600190f35b34801561066857600080fd5b50610225611e05565b34801561067d57600080fd5b50610279600435611e2a565b34801561069557600080fd5b50610225611e52565b3480156106aa57600080fd5b50610279600435611ea0565b3480156106c257600080fd5b506102796004351515611ec5565b3480156106dc57600080fd5b506102796004356024351515611f3c565b3480156106f957600080fd5b50610359600435612060565b34801561071157600080fd5b506103af6120e4565b34801561072657600080fd5b50610225612109565b34801561073b57600080fd5b5060408051602060046024803582810135601f8101859004850286018501909652858552610225958335600160a060020a031695369560449491939091019190819084018382808284375094975050933594506121579350505050565b3480156107a457600080fd5b50610225600435612166565b3480156107bc57600080fd5b506102256121e9565b3480156107d157600080fd5b506102796004803560248101910135612237565b3480156107f157600080fd5b50610279600160a060020a03600435166124be565b34801561081257600080fd5b506103596004356124e3565b34801561082a57600080fd5b50610225612567565b34801561083f57600080fd5b506103596004356125b5565b6000610855611989565b90505b90565b60008060008360405160200180807f6e756d4d657373616765735369676e656400000000000000000000000000000081525060110182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106108df5780518252601f1990920191602091820191016108c0565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205495945050505050565b6000806000806060600080610933611d55565b600160a060020a031663facd743b336040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b15801561098d57600080fd5b505af11580156109a1573d6000803e3d6000fd5b505050506040513d60208110156109b757600080fd5b505115156109c457600080fd5b8a8a8a8a604051602001808560001916600019168152602001841515151560f860020a02815260010183838082843782019150509450505050506040516020818303038152906040526040518082805190602001908083835b60208310610a3c5780518252601f199092019160209182019101610a1d565b51815160209384036101000a600019018019909216911617905260408051929094018290038220336c0100000000000000000000000002838301526034808401829052855180850390910181526054909301948590528251909d509195509293508392850191508083835b60208310610ac65780518252601f199092019160209182019101610aa7565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209550610afe86611ab9565b15610b0857600080fd5b610b138660016125dd565b610b1c87611a36565b9450610b27856125b5565b15610b3157600080fd5b846001019450610b4187866126af565b6040518b9033907fa8430f88dd0556970a712fd927c7d52ff7ed1256e9c8ee3aa291cd3d6eb8205f90600090a3610b76611beb565b8510610d4757610b8e87610b8987612774565b6126af565b610b978b612799565b604051602481018d81528c15156044830152606060648301908152608483018c90529296507ff534de5b00000000000000000000000000000000000000000000000000000000928e928e928e928e9260a401848480828437820191505095505050505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509250610c626121e9565b91508160405a603f02811515610c7457fe5b0411610c7f57600080fd5b83600160a060020a0316828460405180828051906020019080838360005b83811015610cb5578181015183820152602001610c9d565b50505050905090810190601f168015610ce25780820380516001836020036101000a031916815260200191505b5091505060006040518083038160008787f19250505090508a600019167f11c068ae71d815e1839c207016edea79bf33158bd1f50d34e79b0c5aaf52367b8b836040518083151515158152602001821515151581526020019250505060405180910390a25b5050505050505050505050565b7f67d6f42a1ed69c62022f2d160ddc6f2f0acd37ad1db0c24f4702d7d3343a4add60009081526020527ff6c66672b1a9fe5622677597b0da8fd180a2c85696efbcf7fe4b1e0f4f0f61085490565b604080516020808201859052818301849052825180830384018152606092830193849052805192936000939192909182918401908083835b60208310610df95780518252601f199092019160209182019101610dda565b51815160209384036101000a6000190180199092169116179052604080519290940182900382207f7369676e6174757265730000000000000000000000000000000000000000000083830152602a80840182905285518085039091018152604a9093019485905282519097506003965060009550919392508291908401908083835b60208310610e9a5780518252601f199092019160209182019101610e7b565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020600019166000191681526020019081526020016000208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610f715780601f10610f4657610100808354040283529160200191610f71565b820191906000526020600020905b815481529060010190602001808311610f5457829003601f168201915b505050505091505092915050565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f6fde8202000000000000000000000000000000000000000000000000000000001781529151815160009330939291829190808383895b83811015611000578181015183820152602001610fe8565b50505050905090810190601f16801561102d5780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af191505015806110bf575030600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561108757600080fd5b505af115801561109b573d6000803e3d6000fd5b505050506040513d60208110156110b157600080fd5b5051600160a060020a031633145b806110c957503330145b15156110d457600080fd5b6110dc6111f3565b156110e657600080fd5b6110ef866128a0565b15156110fa57600080fd5b61110488886128a8565b7fab54f3fbbe62c59b7876a9bf9bd5e0c22dbae93f4d8ee0438f7ce62b198eb0e0805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03881617905560006020819052437fe66bef0282a446f9848e2903380099bb6e431483ee78778868f33b4a154c818b557f2670ecc91ec356e32067fd27b36614132d727b84a1e03e08f412a4f2cf07597490527f3d7fe2ee9790702383ef0118b516833ef2542132d3ca4ac6c77f62f1230fa6108590556111c5846129f8565b6111ce83612a7e565b6111d782612b11565b6111df612be8565b6111e76111f3565b98975050505050505050565b7f0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba60005260046020527f078d888f9b66f3f8bfa10909e31f1e16240db73449f0500afdbbe3a70da457cc5460ff1690565b7f916daedf6915000ff68ced2f0b6773fe6f2582237f92c3c95bb4d7940723007160009081526020527fd2ea0feb732edb0ffe32efd33a6b9d24d46b16eb34a4d07ce256537b6f131e425490565b6000600260008360405160200180807f6661696c65644d6573736167655265636569766572000000000000000000000081525060150182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106113175780518252601f1990920191602091820191016112f8565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002054600160a060020a031695945050505050565b7f2544fbb90000000000000000000000000000000000000000000000000000000090565b61138d611c63565b600160a060020a031633146113a157600080fd5b6113ab82826128a8565b5050565b60606113ba82612c3f565b92915050565b6000600260008360405160200180807f6661696c65644d65737361676553656e646572000000000000000000000000008152506013018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106113175780518252601f1990920191602091820191016112f8565b7fffa3a5a0e192028fc343362a39c5688e5a60819a4dc5ab3ee70c25bc25b78dd660005260046020527f265a43ea29ede07170a30cb6d77d0ab5810eee752b72432f7be348bde74aa08f5460ff1690565b600080806114a1611989565b14806114b057506114b0611444565b15156114bb57600080fd5b6114c4336128a0565b15156114cf57600080fd5b6114d8856124e3565b15156114e357600080fd5b6114f36114ee610d54565b612da7565b90506114ff8133612eaa565b60408051602080825281018590523391879184917f72220b25ff596f7113b4015af206e306c4964f58f99f01d3f439dd35575f998f9189918991908190810184848082843760405192018290039550909350505050a4949350505050565b600080600080600061156d611d55565b600160a060020a031663facd743b336040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b1580156115c757600080fd5b505af11580156115db573d6000803e3d6000fd5b505050506040513d60208110156115f157600080fd5b505115156115fe57600080fd5b61166889898080601f0160208091040260200160405190810160405280939291908181526020018383808284375050604080516020601f8f018190048102820181019092528d815294508d93508c925082915084018382808284375060019450612f989350505050565b600160a060020a0316331461167c57600080fd5b8686604051602001808383808284378201915050925050506040516020818303038152906040526040518082805190602001908083835b602083106116d25780518252601f1990920191602091820191016116b3565b51815160209384036101000a600019018019909216911617905260408051929094018290038220336c0100000000000000000000000002838301526034808401829052855180850390910181526054909301948590528251909b509195509293508392850191508083835b6020831061175c5780518252601f19909201916020918201910161173d565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902093506117948561085b565b925061179f836125b5565b156117a957600080fd5b6001928301928311156117ce576117bf84611cba565b156117c957600080fd5b611808565b6118088588888080601f01602080910402602001604051908101604052809392919081815260200183838082843750613097945050505050565b61181384600161316e565b8461182584600163ffffffff6131f116565b604080516020808201949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b602083106118795780518252601f19909201916020918201910161185a565b51815160209384036101000a600019018019909216911617905260408051929094018290038220601f8f018290048202830182019094528d82529296506118da9450869350918d91508c908190840183828082843750613203945050505050565b6118e48584613286565b60408051868152905133917fbf06885f40778f5ccfb64497d3f92ce568ddaedb7e2fb4487f72690418cf8e4c919081900360200190a2611922611beb565b905080831061197e5761193d8561193885612774565b613286565b604080513381526020810187905280820183905290517f415557404d88a0c0b8e3b16967cafffc511213fd9c465c16832ee17ed57d72379181900360600190a15b505050505050505050565b7fe34bb2103dc34f2c144cc216c132d6ffb55dac57575c22e089161bbe650833045490565b30600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156119ec57600080fd5b505af1158015611a00573d6000803e3d6000fd5b505050506040513d6020811015611a1657600080fd5b5051600160a060020a03163314611a2c57600080fd5b6113ab8282613308565b60008060008360405160200180807f6e756d41666669726d6174696f6e735369676e656400000000000000000000008152506015018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106108df5780518252601f1990920191602091820191016108c0565b6000600460008360405160200180807f61666669726d6174696f6e735369676e6564000000000000000000000000000081525060120182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310611b3e5780518252601f199092019160209182019101611b1f565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205460ff1695945050505050565b611b8a611c63565b600160a060020a03163314611b9e57600080fd5b7f2670ecc91ec356e32067fd27b36614132d727b84a1e03e08f412a4f2cf07597460009081526020527f3d7fe2ee9790702383ef0118b516833ef2542132d3ca4ac6c77f62f1230fa61055565b6000611bf5611d55565b600160a060020a0316638d0680436040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015611c3257600080fd5b505af1158015611c46573d6000803e3d6000fd5b505050506040513d6020811015611c5c57600080fd5b5051905090565b7f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c060005260026020527fb7802e97e87ef2842a6cce7da7ffaeaedaa2f61a6a7870b23d9d01fc9b73712e54600160a060020a031690565b6000600460008360405160200180807f6d657373616765735369676e6564000000000000000000000000000000000000815250600e01826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310611b3e5780518252601f199092019160209182019101611b1f565b6000611d4d8484846080613346565b949350505050565b7f5a74bb7e202fb8e4bf311841c7d64ec19df195fee77d7e7ae749b27921b6ddfe60005260026020527fab54f3fbbe62c59b7876a9bf9bd5e0c22dbae93f4d8ee0438f7ce62b198eb0e054600160a060020a031690565b7fb120ceec05576ad0c710bc6e85f1768535e27554458f05dcbb5c65b8c7a749b060009081526020527fe66bef0282a446f9848e2903380099bb6e431483ee78778868f33b4a154c818b5490565b600660026000909192565b7f7f0fcd9e49860f055dd0c1682d635d309ecb5e3011654c716d9eb59a7ddec7d25490565b611e32611c63565b600160a060020a03163314611e4657600080fd5b611e4f81612a7e565b50565b7fbbd454018e72a3f6c02bbd785bacc49e46292744f3f6761276723823aa33232060009081526020527f242329173dfc316001df0a0c3d5a8f58a7ffb1a8b7d99c268303b9a741bacdf95490565b611ea8611c63565b600160a060020a03163314611ebc57600080fd5b611e4f816129f8565b611ecd611c63565b600160a060020a03163314611ee157600080fd5b7fffa3a5a0e192028fc343362a39c5688e5a60819a4dc5ab3ee70c25bc25b78dd660005260046020527f265a43ea29ede07170a30cb6d77d0ab5810eee752b72432f7be348bde74aa08f805460ff1916911515919091179055565b611f44611c63565b600160a060020a03163314611f5857600080fd5b80600460008460405160200180807f656e61626c655265717565737453656c6563746f72000000000000000000000081525060150182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310611fdc5780518252601f199092019160209182019101611fbd565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528581019690965250928301600020805460ff191695151595909517909455508051841515815290518593507f0c6e335700063e42c344f1ce5a16fdc748318fa807af05984827f33946d93c4e929181900390910190a25050565b6000600460008360405160200180807f6d65737361676543616c6c537461747573000000000000000000000000000000815250601101826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310611b3e5780518252601f199092019160209182019101611b1f565b7f7b58b2a669d8e0992eae9eaef641092c0f686fd31070e7236865557fa1571b5b5490565b7f1e8ecaafaddea96ed9ac6d2642dcdfe1bebe58a930b1085842d8fc122b371ee560009081526020527fd5c78dd9468716ca9bb96be25d56436811b20aab3523a9904b12deef1cab239d5490565b6000611d4d8484846000613346565b60008060008360405160200180807f6661696c65644d657373616765446174614861736800000000000000000000008152506015018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106108df5780518252601f1990920191602091820191016108c0565b7f2670ecc91ec356e32067fd27b36614132d727b84a1e03e08f412a4f2cf07597460009081526020527f3d7fe2ee9790702383ef0118b516833ef2542132d3ca4ac6c77f62f1230fa6105490565b6000806000612244611d55565b600160a060020a031663facd743b336040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b15801561229e57600080fd5b505af11580156122b2573d6000803e3d6000fd5b505050506040513d60208110156122c857600080fd5b505115156122d557600080fd5b8484604051602001808383808284378201915050925050506040516020818303038152906040526040518082805190602001908083835b6020831061232b5780518252601f19909201916020918201910161230c565b51815160209384036101000a600019018019909216911617905260408051929094018290038220336c01000000000000000000000000028383015260348084018290528551808503909101815260549093019485905282519099509195509293508392850191508083835b602083106123b55780518252601f199092019160209182019101612396565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902091506123ed82611ab9565b156123f757600080fd5b6124028260016125dd565b61240b83611a36565b9050612416816125b5565b1561242057600080fd5b60010161242d83826126af565b60408051848152905133917f5df9cc3eb93d8a9a481857a3b70a8ca966e6b80b25cf0ee2cce180ec5afa80a1919081900360200190a261246b611beb565b81106124b75761247e83610b8983612774565b6124b785858080601f016020809104026020016040519081016040528093929190818152602001838380828437506134cc945050505050565b5050505050565b6124c6611c63565b600160a060020a031633146124da57600080fd5b611e4f81612b11565b6000600460008360405160200180807f656e61626c655265717565737453656c6563746f720000000000000000000000815250601501826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310611b3e5780518252601f199092019160209182019101611b1f565b7f55b3774520b5993024893d303890baa4e84b1244a43c60034d1ced2d3cf2b04b60009081526020527ff7d5eefab3776d7f0450bd0193564bcb4f832ce313ff2836c450fc63a4b944195490565b7f80000000000000000000000000000000000000000000000000000000000000009081161490565b80600460008460405160200180807f61666669726d6174696f6e735369676e6564000000000000000000000000000081525060120182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106126615780518252601f199092019160209182019101612642565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805460ff1916941515949094179093555050505050565b806000808460405160200180807f6e756d41666669726d6174696f6e735369676e6564000000000000000000000081525060150182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106127325780518252601f199092019160209182019101612713565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020939093555050505050565b7f80000000000000000000000000000000000000000000000000000000000000001790565b60008060008360405160200180807f6173796e6353656e646572000000000000000000000000000000000000000000815250600b0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b6020831061281d5780518252601f1990920191602091820191016127fe565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120600081815260029092529290205491955050600160a060020a03169250505080151561287057600080fd5b600091825260026020526040909120805473ffffffffffffffffffffffffffffffffffffffff1916905592915050565b6000903b1190565b6000806000806000861180156128be5750600085115b15156128c957600080fd5b858514156128d657600080fd5b506000925082915060ff905060015b8315806128f0575082155b156129385783158015612904575085828716145b1561290d578093505b8215801561291c575084828616145b15612925578092505b6101009190910260ff17906001016128e5565b5050600060208190527ff6c66672b1a9fe5622677597b0da8fd180a2c85696efbcf7fe4b1e0f4f0f6108949094557f2f30286a16f86ee067618e1a246990e40c07b7749418a6dd3133f9cfb7e814cc919091557f242329173dfc316001df0a0c3d5a8f58a7ffb1a8b7d99c268303b9a741bacdf9919091557ffb792ae4ad11102b93f26a51b3749c2b3667f8b561566a4806d49896928115949091527f7b62b32ff48350e85ce95b571fde6f8b1096bc44a26db769ad6d0b3a26bf1c6d55565b7f55b3774520b5993024893d303890baa4e84b1244a43c60034d1ced2d3cf2b04b600090815260209081527ff7d5eefab3776d7f0450bd0193564bcb4f832ce313ff2836c450fc63a4b944198290556040805183815290517f52264b89e0fceafb26e79fd49ef8a366eb6297483bf4035b027f0c99a7ad512e929181900390910190a150565b60008111612a8b57600080fd5b7f916daedf6915000ff68ced2f0b6773fe6f2582237f92c3c95bb4d79407230071600090815260209081527fd2ea0feb732edb0ffe32efd33a6b9d24d46b16eb34a4d07ce256537b6f131e428290556040805183815290517f4fb76205cd57c896b21511d2114137d8e901b4ccd659e1a0f97d6306795264fb929181900390910190a150565b600160a060020a0381161515612b2657600080fd5b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0612b4f611c63565b60408051600160a060020a03928316815291841660208301528051918290030190a17f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c060005260026020527fb7802e97e87ef2842a6cce7da7ffaeaedaa2f61a6a7870b23d9d01fc9b73712e805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b7f0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba60005260046020527f078d888f9b66f3f8bfa10909e31f1e16240db73449f0500afdbbe3a70da457cc805460ff19166001179055565b6060600360008360405160200180807f6d6573736167657300000000000000000000000000000000000000000000000081525060080182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310612cc45780518252601f199092019160209182019101612ca5565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020600019166000191681526020019081526020016000208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015612d9b5780601f10612d7057610100808354040283529160200191612d9b565b820191906000526020600020905b815481529060010190602001808311612d7e57829003601f168201915b50505050509050919050565b6000806000612db461354b565b9150612dc282600101613599565b6040805160208082018790526c0100000000000000000000000030028284015282516034818403018152605490920192839052815191929182918401908083835b60208310612e225780518252601f199092019160209182019101612e03565b5181516000196020949094036101000a93909301928316921916919091179052604051920182900390912067ffffffffffffffff86167bffffffffffffffffffffffffffffffffffffffff00000000000000009091169081177e0500000000000000000000000000000000000000000000000000000000000017965093505050505050919050565b80600260008460405160200180807f6173796e6353656e646572000000000000000000000000000000000000000000815250600b0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310612f2e5780518252601f199092019160209182019101612f0f565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0395909516949094179093555050505050565b60008060008086516041141515612fae57600080fd5b505050602084015160408501516060860151601b60ff60f860020a8304161480612fe15750601c60ff60f860020a830416145b1515612fec57600080fd5b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a082111561301957600080fd5b600161302587876135f0565b60408051600080825260208083018085529490945260ff60f860020a870416828401526060820188905260808201879052915160a08083019493601f198301938390039091019190865af1158015613081573d6000803e3d6000fd5b5050604051601f19015198975050505050505050565b80600360008460405160200180807f6d6573736167657300000000000000000000000000000000000000000000000081525060080182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b6020831061311b5780518252601f1990920191602091820191016130fc565b51815160001960209485036101000a01908116901991909116179052604080519490920184900390932086528583019690965250929093016000208451613169959194509201919050614244565b505050565b80600460008460405160200180807f6d657373616765735369676e6564000000000000000000000000000000000000815250600e018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106126615780518252601f199092019160209182019101612642565b6000828211156131fd57fe5b50900390565b80600360008460405160200180807f7369676e61747572657300000000000000000000000000000000000000000000815250600a0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083836020831061311b5780518252601f1990920191602091820191016130fc565b806000808460405160200180807f6e756d4d657373616765735369676e65640000000000000000000000000000008152506011018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106127325780518252601f199092019160209182019101612713565b80600160a060020a038116151561331e57600080fd5b600160a060020a038316151561333c576133378261380a565b613169565b6131698383613816565b6000808060608082613356611989565b14806133655750613365611444565b151561337057600080fd5b6064871015801561338857506133846121e9565b8711155b151561339357600080fd5b63ffffffff60048901511693508363a9059cbb141580156133b857508363095ea7b314155b80156133c85750836323b872dd14155b80156133d8575083634000aea014155b80156133e857508363cae9ca5114155b15156133f357600080fd5b6133fe8988886138c9565b9250925081886040516020018083805190602001908083835b602083106134365780518252601f199092019160209182019101613417565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b6020831061347e5780518252601f19909201916020918201910161345f565b6001836020036101000a0380198251168184511680821785525050505050509050019250505060405160208183030381529060405290506134bf838261397f565b5090979650505050505050565b60008060008060006134dc6142c2565b60606134e788613a1c565b959c50939a50919850965094509250905061350187613afc565b151561350c57600080fd5b602082015161351a90613b42565b151561352557600080fd5b61354186868963ffffffff881687876000602002015187613b54565b5050505050505050565b7f7ab1577440dd7bedf920cb6de2f9fc6bf7ba98c78c85a3fa1f8311aac95e175960009081526020527fa9b0f75b23e377b9b22d27feaca5d8a12329c0049ebce1dc695b905f3aa4cd005490565b7f7ab1577440dd7bedf920cb6de2f9fc6bf7ba98c78c85a3fa1f8311aac95e1759600090815260205267ffffffffffffffff167fa9b0f75b23e377b9b22d27feaca5d8a12329c0049ebce1dc695b905f3aa4cd0055565b60408051808201909152601a81527f19457468657265756d205369676e6564204d6573736167653a0a000000000000602082015260009060608315613796578161363a8651613ba1565b866040516020018084805190602001908083835b6020831061366d5780518252601f19909201916020918201910161364e565b51815160209384036101000a600019018019909216911617905286519190930192860191508083835b602083106136b55780518252601f199092019160209182019101613696565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b602083106136fd5780518252601f1990920191602091820191016136de565b6001836020036101000a03801982511681845116808217855250505050505090500193505050506040516020818303038152906040526040518082805190602001908083835b602083106137625780518252601f199092019160209182019101613743565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209250613802565b6040805190810160405280600381526020017f313034000000000000000000000000000000000000000000000000000000000081525090508181866040516020018084805190602001908083836020831061366d5780518252601f19909201916020918201910161364e565b505092915050565b30316113ab8282613cac565b604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290518391600091600160a060020a038416916370a0823191602480830192602092919082900301818787803b15801561387b57600080fd5b505af115801561388f573d6000803e3d6000fd5b505050506040513d60208110156138a557600080fd5b505190506138c3600160a060020a038516848363ffffffff613d0d16565b50505050565b600060606000806000806138db610d54565b93506138e5613da2565b92506138ef611e52565b91506138f9613df0565b905061390484612da7565b95508083604f01016040519080825280601f01601f191660200182016040528015613939578160200160208202803883390190505b50945084518501828152848282035287604f87015281604e87015283604d87015288604c8701528960488701523360348701528660208701525050505050935093915050565b604080516020808252835181830152835185937f520d2afde79cbd5db58755ac9480f81bc658e5c517fcae7365a3d832590b01839386939092839283019185019080838360005b838110156139de5781810151838201526020016139c6565b50505050905090810190601f168015613a0b5780820380516001836020036101000a031916815260200191505b509250505060405180910390a25050565b6000806000806000613a2c6142c2565b6060600080604f915060208a01519850600160a060020a0360348b015116975060548a01518060601c975063ffffffff8160401c16965080601a1a95508060181a6001808260031b1b03818501945080858e01511687528260191a91506001808360031b1b039050818501945080858e0151166020880152848d51039350505050806040519080825280601f01601f191660200182016040528015613adb578160200160208202803883390190505b50925060248201915080826004350160208501375050919395979092949650565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1981167e0500000000000000000000000000000000000000000000000000000000000014919050565b6000613b4c610d54565b909114919050565b6000613b64888884888a88613e3e565b9050613b708682613f34565b801515613b9557613b818683613fb7565b613b8b8688614084565b613b958689614107565b6135418888888461418a565b60606000808281851515613bea5760408051808201909152600181527f300000000000000000000000000000000000000000000000000000000000000060208201529450613ca3565b8593505b8315613c0557600190920191600a84049350613bee565b826040519080825280601f01601f191660200182016040528015613c33578160200160208202803883390190505b5091505060001982015b8515613c9f57815160001982019160f860020a6030600a8a060102918491908110613c6457fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a86049550613c3d565b8194505b50505050919050565b604051600160a060020a0383169082156108fc029083906000818181858888f1935050505015156113ab578082613ce16142dd565b600160a060020a039091168152604051908190036020019082f0801580156124b7573d6000803e3d6000fd5b82600160a060020a031663a9059cbb83836040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050600060405180830381600087803b158015613d7057600080fd5b505af1158015613d84573d6000803e3d6000fd5b505050503d156131695760206000803e600051151561316957600080fd5b7fe504ae1fd6471eea80f18b8532a61a9bb91fba4f5b837f80a1cfb6752350af4460009081526020527f2f30286a16f86ee067618e1a246990e40c07b7749418a6dd3133f9cfb7e814cc5490565b7ffb792ae4ad11102b93f26a51b3749c2b3667f8b561566a4806d498969281159460009081526020527f7b62b32ff48350e85ce95b571fde6f8b1096bc44a26db769ad6d0b3a26bf1c6d5490565b600080613e4a886141d8565b613e53846141fc565b613e5c83614220565b8463ffffffff1480613e7c57508460405a603f02811515613e7957fe5b04115b1515613e8757600080fd5b86600160a060020a0316858760405180828051906020019080838360005b83811015613ebd578181015183820152602001613ea5565b50505050905090810190601f168015613eea5780820380516001836020036101000a031916815260200191505b5091505060006040518083038160008787f1925050509050613f0b81611e4f565b613f1560006141d8565b613f1f60006141fc565b613f296000614220565b979650505050505050565b80600460008460405160200180807f6d65737361676543616c6c5374617475730000000000000000000000000000008152506011018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106126615780518252601f199092019160209182019101612642565b806040518082805190602001908083835b60208310613fe75780518252601f199092019160209182019101613fc8565b51815160001960209485036101000a01908116901991909116179052604080519490920184900384207f6661696c65644d657373616765446174614861736800000000000000000000008583015260358086018a905283518087039091018152605590950192839052845190965060009550859493508291840190808383602083106127325780518252601f199092019160209182019101612713565b80600260008460405160200180807f6661696c65644d65737361676552656365697665720000000000000000000000815250601501826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310612f2e5780518252601f199092019160209182019101612f0f565b80600260008460405160200180807f6661696c65644d65737361676553656e64657200000000000000000000000000815250601301826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310612f2e5780518252601f199092019160209182019101612f0f565b60408051821515815290518391600160a060020a0380871692908816917fe194ef610f9150a2db4110b3db5116fd623175dca3528d7ae7046a1042f84fe7919081900360200190a450505050565b7f7b58b2a669d8e0992eae9eaef641092c0f686fd31070e7236865557fa1571b5b55565b7fe34bb2103dc34f2c144cc216c132d6ffb55dac57575c22e089161bbe6508330455565b7f7f0fcd9e49860f055dd0c1682d635d309ecb5e3011654c716d9eb59a7ddec7d255565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061428557805160ff19168380011785556142b2565b828001600101855582156142b2579182015b828111156142b2578251825591602001919060010190614297565b506142be9291506142ec565b5090565b60408051808201825290600290829080388339509192915050565b60405160218061430783390190565b61085891905b808211156142be57600081556001016142f25600608060405260405160208060218339810160405251600160a060020a038116ff00a165627a7a7230582088546466020cde1eea56aa2dab894f14190a6ac4b036c0a93b12eb6aae8851610029
Deployed ByteCode
0x60806040526004361061020b5763ffffffff60e060020a6000350416630ac1c31381146102105780630cbf0601146102375780630f08d4d01461024f5780631544298e1461027b5780631812d9961461029057806325fbf4ee14610320578063392e53cd1461036d5780633f0a9f65146103825780633f9a8e7e14610397578063437764df146103cb578063467ad35a14610412578063490a32c61461042d5780634a610b04146104455780634d4cb7a21461045d578063525ea93714610472578063630cea8e14610496578063669f618b146104c257806369ffa08a146104d75780636ae1a976146104fe5780637698da24146105165780637bac29c71461052e5780638d068043146105465780638da5cb5b1461055b5780638f4b4b981461057057806394643f711461058857806399439089146105f15780639a454b99146106065780639cb7595a1461061b5780639e307dff1461065c578063acf5c68914610671578063b075061114610689578063bf1fe4201461069e578063c2231ad2146106b6578063c29b1e8a146106d0578063cb08a10c146106ed578063d67bdd2514610705578063dae5f0fd1461071a578063dc8601b31461072f578063e37c328914610798578063e5789d03146107b0578063e7a2c01f146107c5578063f2fde38b146107e5578063fb67e77914610806578063fe173b971461081e578063ffd19e8c14610833575b600080fd5b34801561021c57600080fd5b5061022561084b565b60408051918252519081900360200190f35b34801561024357600080fd5b5061022560043561085b565b34801561025b57600080fd5b50610279600480359060248035151591604435918201910135610920565b005b34801561028757600080fd5b50610225610d54565b34801561029c57600080fd5b506102ab600435602435610da2565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102e55781810151838201526020016102cd565b50505050905090810190601f1680156103125780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561032c57600080fd5b50610359600435602435600160a060020a03604435811690606435906084359060a4359060c43516610f7f565b604080519115158252519081900360200190f35b34801561037957600080fd5b506103596111f3565b34801561038e57600080fd5b50610225611244565b3480156103a357600080fd5b506103af600435611292565b60408051600160a060020a039092168252519081900360200190f35b3480156103d757600080fd5b506103e0611361565b604080517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff199092168252519081900360200190f35b34801561041e57600080fd5b50610279600435602435611385565b34801561043957600080fd5b506102ab6004356113af565b34801561045157600080fd5b506103af6004356113c0565b34801561046957600080fd5b50610359611444565b34801561047e57600080fd5b50610225600480359060248035908101910135611495565b3480156104a257600080fd5b50610279602460048035828101929082013591813591820191013561155d565b3480156104ce57600080fd5b50610225611989565b3480156104e357600080fd5b50610279600160a060020a03600435811690602435166119ae565b34801561050a57600080fd5b50610225600435611a36565b34801561052257600080fd5b50610359600435611ab9565b34801561053a57600080fd5b50610279600435611b82565b34801561055257600080fd5b50610225611beb565b34801561056757600080fd5b506103af611c63565b34801561057c57600080fd5b50610359600435611cba565b34801561059457600080fd5b5060408051602060046024803582810135601f8101859004850286018501909652858552610225958335600160a060020a03169536956044949193909101919081908401838280828437509497505093359450611d3e9350505050565b3480156105fd57600080fd5b506103af611d55565b34801561061257600080fd5b50610225611dac565b34801561062757600080fd5b50610630611dfa565b6040805167ffffffffffffffff9485168152928416602084015292168183015290519081900360600190f35b34801561066857600080fd5b50610225611e05565b34801561067d57600080fd5b50610279600435611e2a565b34801561069557600080fd5b50610225611e52565b3480156106aa57600080fd5b50610279600435611ea0565b3480156106c257600080fd5b506102796004351515611ec5565b3480156106dc57600080fd5b506102796004356024351515611f3c565b3480156106f957600080fd5b50610359600435612060565b34801561071157600080fd5b506103af6120e4565b34801561072657600080fd5b50610225612109565b34801561073b57600080fd5b5060408051602060046024803582810135601f8101859004850286018501909652858552610225958335600160a060020a031695369560449491939091019190819084018382808284375094975050933594506121579350505050565b3480156107a457600080fd5b50610225600435612166565b3480156107bc57600080fd5b506102256121e9565b3480156107d157600080fd5b506102796004803560248101910135612237565b3480156107f157600080fd5b50610279600160a060020a03600435166124be565b34801561081257600080fd5b506103596004356124e3565b34801561082a57600080fd5b50610225612567565b34801561083f57600080fd5b506103596004356125b5565b6000610855611989565b90505b90565b60008060008360405160200180807f6e756d4d657373616765735369676e656400000000000000000000000000000081525060110182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106108df5780518252601f1990920191602091820191016108c0565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205495945050505050565b6000806000806060600080610933611d55565b600160a060020a031663facd743b336040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b15801561098d57600080fd5b505af11580156109a1573d6000803e3d6000fd5b505050506040513d60208110156109b757600080fd5b505115156109c457600080fd5b8a8a8a8a604051602001808560001916600019168152602001841515151560f860020a02815260010183838082843782019150509450505050506040516020818303038152906040526040518082805190602001908083835b60208310610a3c5780518252601f199092019160209182019101610a1d565b51815160209384036101000a600019018019909216911617905260408051929094018290038220336c0100000000000000000000000002838301526034808401829052855180850390910181526054909301948590528251909d509195509293508392850191508083835b60208310610ac65780518252601f199092019160209182019101610aa7565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209550610afe86611ab9565b15610b0857600080fd5b610b138660016125dd565b610b1c87611a36565b9450610b27856125b5565b15610b3157600080fd5b846001019450610b4187866126af565b6040518b9033907fa8430f88dd0556970a712fd927c7d52ff7ed1256e9c8ee3aa291cd3d6eb8205f90600090a3610b76611beb565b8510610d4757610b8e87610b8987612774565b6126af565b610b978b612799565b604051602481018d81528c15156044830152606060648301908152608483018c90529296507ff534de5b00000000000000000000000000000000000000000000000000000000928e928e928e928e9260a401848480828437820191505095505050505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509250610c626121e9565b91508160405a603f02811515610c7457fe5b0411610c7f57600080fd5b83600160a060020a0316828460405180828051906020019080838360005b83811015610cb5578181015183820152602001610c9d565b50505050905090810190601f168015610ce25780820380516001836020036101000a031916815260200191505b5091505060006040518083038160008787f19250505090508a600019167f11c068ae71d815e1839c207016edea79bf33158bd1f50d34e79b0c5aaf52367b8b836040518083151515158152602001821515151581526020019250505060405180910390a25b5050505050505050505050565b7f67d6f42a1ed69c62022f2d160ddc6f2f0acd37ad1db0c24f4702d7d3343a4add60009081526020527ff6c66672b1a9fe5622677597b0da8fd180a2c85696efbcf7fe4b1e0f4f0f61085490565b604080516020808201859052818301849052825180830384018152606092830193849052805192936000939192909182918401908083835b60208310610df95780518252601f199092019160209182019101610dda565b51815160209384036101000a6000190180199092169116179052604080519290940182900382207f7369676e6174757265730000000000000000000000000000000000000000000083830152602a80840182905285518085039091018152604a9093019485905282519097506003965060009550919392508291908401908083835b60208310610e9a5780518252601f199092019160209182019101610e7b565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020600019166000191681526020019081526020016000208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610f715780601f10610f4657610100808354040283529160200191610f71565b820191906000526020600020905b815481529060010190602001808311610f5457829003601f168201915b505050505091505092915050565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f6fde8202000000000000000000000000000000000000000000000000000000001781529151815160009330939291829190808383895b83811015611000578181015183820152602001610fe8565b50505050905090810190601f16801561102d5780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af191505015806110bf575030600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561108757600080fd5b505af115801561109b573d6000803e3d6000fd5b505050506040513d60208110156110b157600080fd5b5051600160a060020a031633145b806110c957503330145b15156110d457600080fd5b6110dc6111f3565b156110e657600080fd5b6110ef866128a0565b15156110fa57600080fd5b61110488886128a8565b7fab54f3fbbe62c59b7876a9bf9bd5e0c22dbae93f4d8ee0438f7ce62b198eb0e0805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03881617905560006020819052437fe66bef0282a446f9848e2903380099bb6e431483ee78778868f33b4a154c818b557f2670ecc91ec356e32067fd27b36614132d727b84a1e03e08f412a4f2cf07597490527f3d7fe2ee9790702383ef0118b516833ef2542132d3ca4ac6c77f62f1230fa6108590556111c5846129f8565b6111ce83612a7e565b6111d782612b11565b6111df612be8565b6111e76111f3565b98975050505050505050565b7f0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba60005260046020527f078d888f9b66f3f8bfa10909e31f1e16240db73449f0500afdbbe3a70da457cc5460ff1690565b7f916daedf6915000ff68ced2f0b6773fe6f2582237f92c3c95bb4d7940723007160009081526020527fd2ea0feb732edb0ffe32efd33a6b9d24d46b16eb34a4d07ce256537b6f131e425490565b6000600260008360405160200180807f6661696c65644d6573736167655265636569766572000000000000000000000081525060150182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106113175780518252601f1990920191602091820191016112f8565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002054600160a060020a031695945050505050565b7f2544fbb90000000000000000000000000000000000000000000000000000000090565b61138d611c63565b600160a060020a031633146113a157600080fd5b6113ab82826128a8565b5050565b60606113ba82612c3f565b92915050565b6000600260008360405160200180807f6661696c65644d65737361676553656e646572000000000000000000000000008152506013018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106113175780518252601f1990920191602091820191016112f8565b7fffa3a5a0e192028fc343362a39c5688e5a60819a4dc5ab3ee70c25bc25b78dd660005260046020527f265a43ea29ede07170a30cb6d77d0ab5810eee752b72432f7be348bde74aa08f5460ff1690565b600080806114a1611989565b14806114b057506114b0611444565b15156114bb57600080fd5b6114c4336128a0565b15156114cf57600080fd5b6114d8856124e3565b15156114e357600080fd5b6114f36114ee610d54565b612da7565b90506114ff8133612eaa565b60408051602080825281018590523391879184917f72220b25ff596f7113b4015af206e306c4964f58f99f01d3f439dd35575f998f9189918991908190810184848082843760405192018290039550909350505050a4949350505050565b600080600080600061156d611d55565b600160a060020a031663facd743b336040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b1580156115c757600080fd5b505af11580156115db573d6000803e3d6000fd5b505050506040513d60208110156115f157600080fd5b505115156115fe57600080fd5b61166889898080601f0160208091040260200160405190810160405280939291908181526020018383808284375050604080516020601f8f018190048102820181019092528d815294508d93508c925082915084018382808284375060019450612f989350505050565b600160a060020a0316331461167c57600080fd5b8686604051602001808383808284378201915050925050506040516020818303038152906040526040518082805190602001908083835b602083106116d25780518252601f1990920191602091820191016116b3565b51815160209384036101000a600019018019909216911617905260408051929094018290038220336c0100000000000000000000000002838301526034808401829052855180850390910181526054909301948590528251909b509195509293508392850191508083835b6020831061175c5780518252601f19909201916020918201910161173d565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902093506117948561085b565b925061179f836125b5565b156117a957600080fd5b6001928301928311156117ce576117bf84611cba565b156117c957600080fd5b611808565b6118088588888080601f01602080910402602001604051908101604052809392919081815260200183838082843750613097945050505050565b61181384600161316e565b8461182584600163ffffffff6131f116565b604080516020808201949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b602083106118795780518252601f19909201916020918201910161185a565b51815160209384036101000a600019018019909216911617905260408051929094018290038220601f8f018290048202830182019094528d82529296506118da9450869350918d91508c908190840183828082843750613203945050505050565b6118e48584613286565b60408051868152905133917fbf06885f40778f5ccfb64497d3f92ce568ddaedb7e2fb4487f72690418cf8e4c919081900360200190a2611922611beb565b905080831061197e5761193d8561193885612774565b613286565b604080513381526020810187905280820183905290517f415557404d88a0c0b8e3b16967cafffc511213fd9c465c16832ee17ed57d72379181900360600190a15b505050505050505050565b7fe34bb2103dc34f2c144cc216c132d6ffb55dac57575c22e089161bbe650833045490565b30600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156119ec57600080fd5b505af1158015611a00573d6000803e3d6000fd5b505050506040513d6020811015611a1657600080fd5b5051600160a060020a03163314611a2c57600080fd5b6113ab8282613308565b60008060008360405160200180807f6e756d41666669726d6174696f6e735369676e656400000000000000000000008152506015018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106108df5780518252601f1990920191602091820191016108c0565b6000600460008360405160200180807f61666669726d6174696f6e735369676e6564000000000000000000000000000081525060120182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310611b3e5780518252601f199092019160209182019101611b1f565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205460ff1695945050505050565b611b8a611c63565b600160a060020a03163314611b9e57600080fd5b7f2670ecc91ec356e32067fd27b36614132d727b84a1e03e08f412a4f2cf07597460009081526020527f3d7fe2ee9790702383ef0118b516833ef2542132d3ca4ac6c77f62f1230fa61055565b6000611bf5611d55565b600160a060020a0316638d0680436040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015611c3257600080fd5b505af1158015611c46573d6000803e3d6000fd5b505050506040513d6020811015611c5c57600080fd5b5051905090565b7f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c060005260026020527fb7802e97e87ef2842a6cce7da7ffaeaedaa2f61a6a7870b23d9d01fc9b73712e54600160a060020a031690565b6000600460008360405160200180807f6d657373616765735369676e6564000000000000000000000000000000000000815250600e01826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310611b3e5780518252601f199092019160209182019101611b1f565b6000611d4d8484846080613346565b949350505050565b7f5a74bb7e202fb8e4bf311841c7d64ec19df195fee77d7e7ae749b27921b6ddfe60005260026020527fab54f3fbbe62c59b7876a9bf9bd5e0c22dbae93f4d8ee0438f7ce62b198eb0e054600160a060020a031690565b7fb120ceec05576ad0c710bc6e85f1768535e27554458f05dcbb5c65b8c7a749b060009081526020527fe66bef0282a446f9848e2903380099bb6e431483ee78778868f33b4a154c818b5490565b600660026000909192565b7f7f0fcd9e49860f055dd0c1682d635d309ecb5e3011654c716d9eb59a7ddec7d25490565b611e32611c63565b600160a060020a03163314611e4657600080fd5b611e4f81612a7e565b50565b7fbbd454018e72a3f6c02bbd785bacc49e46292744f3f6761276723823aa33232060009081526020527f242329173dfc316001df0a0c3d5a8f58a7ffb1a8b7d99c268303b9a741bacdf95490565b611ea8611c63565b600160a060020a03163314611ebc57600080fd5b611e4f816129f8565b611ecd611c63565b600160a060020a03163314611ee157600080fd5b7fffa3a5a0e192028fc343362a39c5688e5a60819a4dc5ab3ee70c25bc25b78dd660005260046020527f265a43ea29ede07170a30cb6d77d0ab5810eee752b72432f7be348bde74aa08f805460ff1916911515919091179055565b611f44611c63565b600160a060020a03163314611f5857600080fd5b80600460008460405160200180807f656e61626c655265717565737453656c6563746f72000000000000000000000081525060150182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310611fdc5780518252601f199092019160209182019101611fbd565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528581019690965250928301600020805460ff191695151595909517909455508051841515815290518593507f0c6e335700063e42c344f1ce5a16fdc748318fa807af05984827f33946d93c4e929181900390910190a25050565b6000600460008360405160200180807f6d65737361676543616c6c537461747573000000000000000000000000000000815250601101826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310611b3e5780518252601f199092019160209182019101611b1f565b7f7b58b2a669d8e0992eae9eaef641092c0f686fd31070e7236865557fa1571b5b5490565b7f1e8ecaafaddea96ed9ac6d2642dcdfe1bebe58a930b1085842d8fc122b371ee560009081526020527fd5c78dd9468716ca9bb96be25d56436811b20aab3523a9904b12deef1cab239d5490565b6000611d4d8484846000613346565b60008060008360405160200180807f6661696c65644d657373616765446174614861736800000000000000000000008152506015018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106108df5780518252601f1990920191602091820191016108c0565b7f2670ecc91ec356e32067fd27b36614132d727b84a1e03e08f412a4f2cf07597460009081526020527f3d7fe2ee9790702383ef0118b516833ef2542132d3ca4ac6c77f62f1230fa6105490565b6000806000612244611d55565b600160a060020a031663facd743b336040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b15801561229e57600080fd5b505af11580156122b2573d6000803e3d6000fd5b505050506040513d60208110156122c857600080fd5b505115156122d557600080fd5b8484604051602001808383808284378201915050925050506040516020818303038152906040526040518082805190602001908083835b6020831061232b5780518252601f19909201916020918201910161230c565b51815160209384036101000a600019018019909216911617905260408051929094018290038220336c01000000000000000000000000028383015260348084018290528551808503909101815260549093019485905282519099509195509293508392850191508083835b602083106123b55780518252601f199092019160209182019101612396565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902091506123ed82611ab9565b156123f757600080fd5b6124028260016125dd565b61240b83611a36565b9050612416816125b5565b1561242057600080fd5b60010161242d83826126af565b60408051848152905133917f5df9cc3eb93d8a9a481857a3b70a8ca966e6b80b25cf0ee2cce180ec5afa80a1919081900360200190a261246b611beb565b81106124b75761247e83610b8983612774565b6124b785858080601f016020809104026020016040519081016040528093929190818152602001838380828437506134cc945050505050565b5050505050565b6124c6611c63565b600160a060020a031633146124da57600080fd5b611e4f81612b11565b6000600460008360405160200180807f656e61626c655265717565737453656c6563746f720000000000000000000000815250601501826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310611b3e5780518252601f199092019160209182019101611b1f565b7f55b3774520b5993024893d303890baa4e84b1244a43c60034d1ced2d3cf2b04b60009081526020527ff7d5eefab3776d7f0450bd0193564bcb4f832ce313ff2836c450fc63a4b944195490565b7f80000000000000000000000000000000000000000000000000000000000000009081161490565b80600460008460405160200180807f61666669726d6174696f6e735369676e6564000000000000000000000000000081525060120182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106126615780518252601f199092019160209182019101612642565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805460ff1916941515949094179093555050505050565b806000808460405160200180807f6e756d41666669726d6174696f6e735369676e6564000000000000000000000081525060150182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106127325780518252601f199092019160209182019101612713565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020939093555050505050565b7f80000000000000000000000000000000000000000000000000000000000000001790565b60008060008360405160200180807f6173796e6353656e646572000000000000000000000000000000000000000000815250600b0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b6020831061281d5780518252601f1990920191602091820191016127fe565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120600081815260029092529290205491955050600160a060020a03169250505080151561287057600080fd5b600091825260026020526040909120805473ffffffffffffffffffffffffffffffffffffffff1916905592915050565b6000903b1190565b6000806000806000861180156128be5750600085115b15156128c957600080fd5b858514156128d657600080fd5b506000925082915060ff905060015b8315806128f0575082155b156129385783158015612904575085828716145b1561290d578093505b8215801561291c575084828616145b15612925578092505b6101009190910260ff17906001016128e5565b5050600060208190527ff6c66672b1a9fe5622677597b0da8fd180a2c85696efbcf7fe4b1e0f4f0f6108949094557f2f30286a16f86ee067618e1a246990e40c07b7749418a6dd3133f9cfb7e814cc919091557f242329173dfc316001df0a0c3d5a8f58a7ffb1a8b7d99c268303b9a741bacdf9919091557ffb792ae4ad11102b93f26a51b3749c2b3667f8b561566a4806d49896928115949091527f7b62b32ff48350e85ce95b571fde6f8b1096bc44a26db769ad6d0b3a26bf1c6d55565b7f55b3774520b5993024893d303890baa4e84b1244a43c60034d1ced2d3cf2b04b600090815260209081527ff7d5eefab3776d7f0450bd0193564bcb4f832ce313ff2836c450fc63a4b944198290556040805183815290517f52264b89e0fceafb26e79fd49ef8a366eb6297483bf4035b027f0c99a7ad512e929181900390910190a150565b60008111612a8b57600080fd5b7f916daedf6915000ff68ced2f0b6773fe6f2582237f92c3c95bb4d79407230071600090815260209081527fd2ea0feb732edb0ffe32efd33a6b9d24d46b16eb34a4d07ce256537b6f131e428290556040805183815290517f4fb76205cd57c896b21511d2114137d8e901b4ccd659e1a0f97d6306795264fb929181900390910190a150565b600160a060020a0381161515612b2657600080fd5b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0612b4f611c63565b60408051600160a060020a03928316815291841660208301528051918290030190a17f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c060005260026020527fb7802e97e87ef2842a6cce7da7ffaeaedaa2f61a6a7870b23d9d01fc9b73712e805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b7f0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba60005260046020527f078d888f9b66f3f8bfa10909e31f1e16240db73449f0500afdbbe3a70da457cc805460ff19166001179055565b6060600360008360405160200180807f6d6573736167657300000000000000000000000000000000000000000000000081525060080182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310612cc45780518252601f199092019160209182019101612ca5565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020600019166000191681526020019081526020016000208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015612d9b5780601f10612d7057610100808354040283529160200191612d9b565b820191906000526020600020905b815481529060010190602001808311612d7e57829003601f168201915b50505050509050919050565b6000806000612db461354b565b9150612dc282600101613599565b6040805160208082018790526c0100000000000000000000000030028284015282516034818403018152605490920192839052815191929182918401908083835b60208310612e225780518252601f199092019160209182019101612e03565b5181516000196020949094036101000a93909301928316921916919091179052604051920182900390912067ffffffffffffffff86167bffffffffffffffffffffffffffffffffffffffff00000000000000009091169081177e0500000000000000000000000000000000000000000000000000000000000017965093505050505050919050565b80600260008460405160200180807f6173796e6353656e646572000000000000000000000000000000000000000000815250600b0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310612f2e5780518252601f199092019160209182019101612f0f565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0395909516949094179093555050505050565b60008060008086516041141515612fae57600080fd5b505050602084015160408501516060860151601b60ff60f860020a8304161480612fe15750601c60ff60f860020a830416145b1515612fec57600080fd5b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a082111561301957600080fd5b600161302587876135f0565b60408051600080825260208083018085529490945260ff60f860020a870416828401526060820188905260808201879052915160a08083019493601f198301938390039091019190865af1158015613081573d6000803e3d6000fd5b5050604051601f19015198975050505050505050565b80600360008460405160200180807f6d6573736167657300000000000000000000000000000000000000000000000081525060080182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b6020831061311b5780518252601f1990920191602091820191016130fc565b51815160001960209485036101000a01908116901991909116179052604080519490920184900390932086528583019690965250929093016000208451613169959194509201919050614244565b505050565b80600460008460405160200180807f6d657373616765735369676e6564000000000000000000000000000000000000815250600e018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106126615780518252601f199092019160209182019101612642565b6000828211156131fd57fe5b50900390565b80600360008460405160200180807f7369676e61747572657300000000000000000000000000000000000000000000815250600a0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083836020831061311b5780518252601f1990920191602091820191016130fc565b806000808460405160200180807f6e756d4d657373616765735369676e65640000000000000000000000000000008152506011018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106127325780518252601f199092019160209182019101612713565b80600160a060020a038116151561331e57600080fd5b600160a060020a038316151561333c576133378261380a565b613169565b6131698383613816565b6000808060608082613356611989565b14806133655750613365611444565b151561337057600080fd5b6064871015801561338857506133846121e9565b8711155b151561339357600080fd5b63ffffffff60048901511693508363a9059cbb141580156133b857508363095ea7b314155b80156133c85750836323b872dd14155b80156133d8575083634000aea014155b80156133e857508363cae9ca5114155b15156133f357600080fd5b6133fe8988886138c9565b9250925081886040516020018083805190602001908083835b602083106134365780518252601f199092019160209182019101613417565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b6020831061347e5780518252601f19909201916020918201910161345f565b6001836020036101000a0380198251168184511680821785525050505050509050019250505060405160208183030381529060405290506134bf838261397f565b5090979650505050505050565b60008060008060006134dc6142c2565b60606134e788613a1c565b959c50939a50919850965094509250905061350187613afc565b151561350c57600080fd5b602082015161351a90613b42565b151561352557600080fd5b61354186868963ffffffff881687876000602002015187613b54565b5050505050505050565b7f7ab1577440dd7bedf920cb6de2f9fc6bf7ba98c78c85a3fa1f8311aac95e175960009081526020527fa9b0f75b23e377b9b22d27feaca5d8a12329c0049ebce1dc695b905f3aa4cd005490565b7f7ab1577440dd7bedf920cb6de2f9fc6bf7ba98c78c85a3fa1f8311aac95e1759600090815260205267ffffffffffffffff167fa9b0f75b23e377b9b22d27feaca5d8a12329c0049ebce1dc695b905f3aa4cd0055565b60408051808201909152601a81527f19457468657265756d205369676e6564204d6573736167653a0a000000000000602082015260009060608315613796578161363a8651613ba1565b866040516020018084805190602001908083835b6020831061366d5780518252601f19909201916020918201910161364e565b51815160209384036101000a600019018019909216911617905286519190930192860191508083835b602083106136b55780518252601f199092019160209182019101613696565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b602083106136fd5780518252601f1990920191602091820191016136de565b6001836020036101000a03801982511681845116808217855250505050505090500193505050506040516020818303038152906040526040518082805190602001908083835b602083106137625780518252601f199092019160209182019101613743565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209250613802565b6040805190810160405280600381526020017f313034000000000000000000000000000000000000000000000000000000000081525090508181866040516020018084805190602001908083836020831061366d5780518252601f19909201916020918201910161364e565b505092915050565b30316113ab8282613cac565b604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290518391600091600160a060020a038416916370a0823191602480830192602092919082900301818787803b15801561387b57600080fd5b505af115801561388f573d6000803e3d6000fd5b505050506040513d60208110156138a557600080fd5b505190506138c3600160a060020a038516848363ffffffff613d0d16565b50505050565b600060606000806000806138db610d54565b93506138e5613da2565b92506138ef611e52565b91506138f9613df0565b905061390484612da7565b95508083604f01016040519080825280601f01601f191660200182016040528015613939578160200160208202803883390190505b50945084518501828152848282035287604f87015281604e87015283604d87015288604c8701528960488701523360348701528660208701525050505050935093915050565b604080516020808252835181830152835185937f520d2afde79cbd5db58755ac9480f81bc658e5c517fcae7365a3d832590b01839386939092839283019185019080838360005b838110156139de5781810151838201526020016139c6565b50505050905090810190601f168015613a0b5780820380516001836020036101000a031916815260200191505b509250505060405180910390a25050565b6000806000806000613a2c6142c2565b6060600080604f915060208a01519850600160a060020a0360348b015116975060548a01518060601c975063ffffffff8160401c16965080601a1a95508060181a6001808260031b1b03818501945080858e01511687528260191a91506001808360031b1b039050818501945080858e0151166020880152848d51039350505050806040519080825280601f01601f191660200182016040528015613adb578160200160208202803883390190505b50925060248201915080826004350160208501375050919395979092949650565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1981167e0500000000000000000000000000000000000000000000000000000000000014919050565b6000613b4c610d54565b909114919050565b6000613b64888884888a88613e3e565b9050613b708682613f34565b801515613b9557613b818683613fb7565b613b8b8688614084565b613b958689614107565b6135418888888461418a565b60606000808281851515613bea5760408051808201909152600181527f300000000000000000000000000000000000000000000000000000000000000060208201529450613ca3565b8593505b8315613c0557600190920191600a84049350613bee565b826040519080825280601f01601f191660200182016040528015613c33578160200160208202803883390190505b5091505060001982015b8515613c9f57815160001982019160f860020a6030600a8a060102918491908110613c6457fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a86049550613c3d565b8194505b50505050919050565b604051600160a060020a0383169082156108fc029083906000818181858888f1935050505015156113ab578082613ce16142dd565b600160a060020a039091168152604051908190036020019082f0801580156124b7573d6000803e3d6000fd5b82600160a060020a031663a9059cbb83836040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050600060405180830381600087803b158015613d7057600080fd5b505af1158015613d84573d6000803e3d6000fd5b505050503d156131695760206000803e600051151561316957600080fd5b7fe504ae1fd6471eea80f18b8532a61a9bb91fba4f5b837f80a1cfb6752350af4460009081526020527f2f30286a16f86ee067618e1a246990e40c07b7749418a6dd3133f9cfb7e814cc5490565b7ffb792ae4ad11102b93f26a51b3749c2b3667f8b561566a4806d498969281159460009081526020527f7b62b32ff48350e85ce95b571fde6f8b1096bc44a26db769ad6d0b3a26bf1c6d5490565b600080613e4a886141d8565b613e53846141fc565b613e5c83614220565b8463ffffffff1480613e7c57508460405a603f02811515613e7957fe5b04115b1515613e8757600080fd5b86600160a060020a0316858760405180828051906020019080838360005b83811015613ebd578181015183820152602001613ea5565b50505050905090810190601f168015613eea5780820380516001836020036101000a031916815260200191505b5091505060006040518083038160008787f1925050509050613f0b81611e4f565b613f1560006141d8565b613f1f60006141fc565b613f296000614220565b979650505050505050565b80600460008460405160200180807f6d65737361676543616c6c5374617475730000000000000000000000000000008152506011018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106126615780518252601f199092019160209182019101612642565b806040518082805190602001908083835b60208310613fe75780518252601f199092019160209182019101613fc8565b51815160001960209485036101000a01908116901991909116179052604080519490920184900384207f6661696c65644d657373616765446174614861736800000000000000000000008583015260358086018a905283518087039091018152605590950192839052845190965060009550859493508291840190808383602083106127325780518252601f199092019160209182019101612713565b80600260008460405160200180807f6661696c65644d65737361676552656365697665720000000000000000000000815250601501826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310612f2e5780518252601f199092019160209182019101612f0f565b80600260008460405160200180807f6661696c65644d65737361676553656e64657200000000000000000000000000815250601301826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310612f2e5780518252601f199092019160209182019101612f0f565b60408051821515815290518391600160a060020a0380871692908816917fe194ef610f9150a2db4110b3db5116fd623175dca3528d7ae7046a1042f84fe7919081900360200190a450505050565b7f7b58b2a669d8e0992eae9eaef641092c0f686fd31070e7236865557fa1571b5b55565b7fe34bb2103dc34f2c144cc216c132d6ffb55dac57575c22e089161bbe6508330455565b7f7f0fcd9e49860f055dd0c1682d635d309ecb5e3011654c716d9eb59a7ddec7d255565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061428557805160ff19168380011785556142b2565b828001600101855582156142b2579182015b828111156142b2578251825591602001919060010190614297565b506142be9291506142ec565b5090565b60408051808201825290600290829080388339509192915050565b60405160218061430783390190565b61085891905b808211156142be57600081556001016142f25600608060405260405160208060218339810160405251600160a060020a038116ff00a165627a7a7230582088546466020cde1eea56aa2dab894f14190a6ac4b036c0a93b12eb6aae8851610029