The Gnosis Chain (formerly xDai Chain) journey begins! STAKE to GNO swap application now live on Ethereum and Gnosis Chain. Swap now. Learn about the benefits of GNO token.

Contract Address Details
contract

0x3b3887242f423C472044246BC06b55e4dC632aAE

Contract Name
HomeBridgeErcToNative
Creator
0xbf3d6f–442b53 at 0xd58eea–dba0f6
Balance
0 xDAI ( )
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
0 Transfers
Gas Used
Fetching gas used...
Last Balance Update
20161935
Contract name:
HomeBridgeErcToNative




Optimization enabled
true
Compiler version
v0.4.24+commit.e67f0147




Optimization runs
200
EVM Version
default




Verified at
2021-10-05 14:52:23.310815Z

Contract source code

// 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/upgradeability/EternalStorage.sol
pragma solidity 0.4.24;
/**
* @title EternalStorage
* @dev This contract holds all the necessary state variables to carry out the storage of any contract.
*/
contract EternalStorage {
mapping(bytes32 => uint256) internal uintStorage;
mapping(bytes32 => string) internal stringStorage;
mapping(bytes32 => address) internal addressStorage;
mapping(bytes32 => bytes) internal bytesStorage;
mapping(bytes32 => bool) internal boolStorage;
mapping(bytes32 => int256) internal intStorage;
}
// File: contracts/interfaces/IBlockReward.sol
pragma solidity 0.4.24;
interface IBlockReward {
function addExtraReceiver(uint256 _amount, address _receiver) external;
function mintedTotally() external view returns (uint256);
function mintedTotallyByBridge(address _bridge) external view returns (uint256);
function bridgesAllowedLength() external view returns (uint256);
function addBridgeTokenRewardReceivers(uint256 _amount) external;
function addBridgeNativeRewardReceivers(uint256 _amount) external;
function blockRewardContractId() external pure returns (bytes4);
}
// 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/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/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/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/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: 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/BasicTokenBridge.sol
pragma solidity 0.4.24;
contract BasicTokenBridge is EternalStorage, Ownable, DecimalShiftBridge {
using SafeMath for uint256;
event DailyLimitChanged(uint256 newLimit);
event ExecutionDailyLimitChanged(uint256 newLimit);
bytes32 internal constant MIN_PER_TX = 0xbbb088c505d18e049d114c7c91f11724e69c55ad6c5397e2b929e68b41fa05d1; // keccak256(abi.encodePacked("minPerTx"))
bytes32 internal constant MAX_PER_TX = 0x0f8803acad17c63ee38bf2de71e1888bc7a079a6f73658e274b08018bea4e29c; // keccak256(abi.encodePacked("maxPerTx"))
bytes32 internal constant DAILY_LIMIT = 0x4a6a899679f26b73530d8cf1001e83b6f7702e04b6fdb98f3c62dc7e47e041a5; // keccak256(abi.encodePacked("dailyLimit"))
bytes32 internal constant EXECUTION_MAX_PER_TX = 0xc0ed44c192c86d1cc1ba51340b032c2766b4a2b0041031de13c46dd7104888d5; // keccak256(abi.encodePacked("executionMaxPerTx"))
bytes32 internal constant EXECUTION_DAILY_LIMIT = 0x21dbcab260e413c20dc13c28b7db95e2b423d1135f42bb8b7d5214a92270d237; // keccak256(abi.encodePacked("executionDailyLimit"))
function totalSpentPerDay(uint256 _day) public view returns (uint256) {
return uintStorage[keccak256(abi.encodePacked("totalSpentPerDay", _day))];
}
function totalExecutedPerDay(uint256 _day) public view returns (uint256) {
return uintStorage[keccak256(abi.encodePacked("totalExecutedPerDay", _day))];
}
function dailyLimit() public view returns (uint256) {
return uintStorage[DAILY_LIMIT];
}
function executionDailyLimit() public view returns (uint256) {
return uintStorage[EXECUTION_DAILY_LIMIT];
}
function maxPerTx() public view returns (uint256) {
return uintStorage[MAX_PER_TX];
}
function executionMaxPerTx() public view returns (uint256) {
return uintStorage[EXECUTION_MAX_PER_TX];
}
function minPerTx() public view returns (uint256) {
return uintStorage[MIN_PER_TX];
}
function withinLimit(uint256 _amount) public view returns (bool) {
uint256 nextLimit = totalSpentPerDay(getCurrentDay()).add(_amount);
return dailyLimit() >= nextLimit && _amount <= maxPerTx() && _amount >= minPerTx();
}
function withinExecutionLimit(uint256 _amount) public view returns (bool) {
uint256 nextLimit = totalExecutedPerDay(getCurrentDay()).add(_amount);
return executionDailyLimit() >= nextLimit && _amount <= executionMaxPerTx();
}
function getCurrentDay() public view returns (uint256) {
return now / 1 days;
}
function addTotalSpentPerDay(uint256 _day, uint256 _value) internal {
uintStorage[keccak256(abi.encodePacked("totalSpentPerDay", _day))] = totalSpentPerDay(_day).add(_value);
}
function addTotalExecutedPerDay(uint256 _day, uint256 _value) internal {
uintStorage[keccak256(abi.encodePacked("totalExecutedPerDay", _day))] = totalExecutedPerDay(_day).add(_value);
}
function setDailyLimit(uint256 _dailyLimit) external onlyOwner {
require(_dailyLimit > maxPerTx() || _dailyLimit == 0);
uintStorage[DAILY_LIMIT] = _dailyLimit;
emit DailyLimitChanged(_dailyLimit);
}
function setExecutionDailyLimit(uint256 _dailyLimit) external onlyOwner {
require(_dailyLimit > executionMaxPerTx() || _dailyLimit == 0);
uintStorage[EXECUTION_DAILY_LIMIT] = _dailyLimit;
emit ExecutionDailyLimitChanged(_dailyLimit);
}
function setExecutionMaxPerTx(uint256 _maxPerTx) external onlyOwner {
require(_maxPerTx < executionDailyLimit());
uintStorage[EXECUTION_MAX_PER_TX] = _maxPerTx;
}
function setMaxPerTx(uint256 _maxPerTx) external onlyOwner {
require(_maxPerTx == 0 || (_maxPerTx > minPerTx() && _maxPerTx < dailyLimit()));
uintStorage[MAX_PER_TX] = _maxPerTx;
}
function setMinPerTx(uint256 _minPerTx) external onlyOwner {
require(_minPerTx > 0 && _minPerTx < dailyLimit() && _minPerTx < maxPerTx());
uintStorage[MIN_PER_TX] = _minPerTx;
}
/**
* @dev Retrieves maximum available bridge amount per one transaction taking into account maxPerTx() and dailyLimit() parameters.
* @return minimum of maxPerTx parameter and remaining daily quota.
*/
function maxAvailablePerTx() public view returns (uint256) {
uint256 _maxPerTx = maxPerTx();
uint256 _dailyLimit = dailyLimit();
uint256 _spent = totalSpentPerDay(getCurrentDay());
uint256 _remainingOutOfDaily = _dailyLimit > _spent ? _dailyLimit - _spent : 0;
return _maxPerTx < _remainingOutOfDaily ? _maxPerTx : _remainingOutOfDaily;
}
function _setLimits(uint256[3] _limits) internal {
require(
_limits[2] > 0 && // minPerTx > 0
_limits[1] > _limits[2] && // maxPerTx > minPerTx
_limits[0] > _limits[1] // dailyLimit > maxPerTx
);
uintStorage[DAILY_LIMIT] = _limits[0];
uintStorage[MAX_PER_TX] = _limits[1];
uintStorage[MIN_PER_TX] = _limits[2];
emit DailyLimitChanged(_limits[0]);
}
function _setExecutionLimits(uint256[2] _limits) internal {
require(_limits[1] < _limits[0]); // foreignMaxPerTx < foreignDailyLimit
uintStorage[EXECUTION_DAILY_LIMIT] = _limits[0];
uintStorage[EXECUTION_MAX_PER_TX] = _limits[1];
emit ExecutionDailyLimitChanged(_limits[0]);
}
}
// File: contracts/upgradeable_contracts/BasicHomeBridge.sol
pragma solidity 0.4.24;
/**
* @title BasicHomeBridge
* @dev This contract implements common functionality for all vanilla bridge modes on the Home side.
*/
contract BasicHomeBridge is EternalStorage, Validatable, BasicBridge, BasicTokenBridge {
using SafeMath for uint256;
event UserRequestForSignature(address recipient, uint256 value);
event AffirmationCompleted(address recipient, uint256 value, bytes32 transactionHash);
event SignedForUserRequest(address indexed signer, bytes32 messageHash);
event SignedForAffirmation(address indexed signer, bytes32 transactionHash);
event CollectedSignatures(
address authorityResponsibleForRelay,
bytes32 messageHash,
uint256 NumberOfCollectedSignatures
);
/**
* @dev Executes a message affirmation for some Foreign side event.
* Can be called only by a current bridge validator.
* @param recipient tokens/coins of receiver address, where the assets should be unlocked/minted.
* @param value amount of assets to unlock/mint.
* @param transactionHash reference event transaction hash on the Foreign side of the bridge.
*/
function executeAffirmation(address recipient, uint256 value, bytes32 transactionHash) external onlyValidator {
bytes32 hashMsg = keccak256(abi.encodePacked(recipient, value, transactionHash));
if (withinExecutionLimit(value)) {
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, transactionHash);
if (signed >= requiredSignatures()) {
// If the bridge contract does not own enough tokens to transfer
// it will couse funds lock on the home side of the bridge
setNumAffirmationsSigned(hashMsg, markAsProcessed(signed));
if (value > 0) {
require(onExecuteAffirmation(recipient, value, transactionHash, hashMsg));
}
emit AffirmationCompleted(recipient, value, transactionHash);
}
} else {
onFailedAffirmation(recipient, value, transactionHash, hashMsg);
}
}
function submitSignature(bytes signature, bytes message) external onlyValidator {
// ensure that `signature` is really `message` signed by `msg.sender`
require(Message.isMessageValid(message));
require(msg.sender == Message.recoverAddressFromSignedMessage(signature, message, false));
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 - 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);
onSignaturesCollected(message);
}
}
function setMessagesSigned(bytes32 _hash, bool _status) internal {
boolStorage[keccak256(abi.encodePacked("messagesSigned", _hash))] = _status;
}
/* solcov ignore next */
function onExecuteAffirmation(address, uint256, bytes32, bytes32) internal returns (bool);
/* solcov ignore next */
function onFailedAffirmation(address, uint256, bytes32, bytes32) internal;
/* solcov ignore next */
function onSignaturesCollected(bytes) internal;
function numAffirmationsSigned(bytes32 _withdrawal) public view returns (uint256) {
return uintStorage[keccak256(abi.encodePacked("numAffirmationsSigned", _withdrawal))];
}
function setAffirmationsSigned(bytes32 _withdrawal, bool _status) internal {
boolStorage[keccak256(abi.encodePacked("affirmationsSigned", _withdrawal))] = _status;
}
function setNumAffirmationsSigned(bytes32 _withdrawal, uint256 _number) internal {
uintStorage[keccak256(abi.encodePacked("numAffirmationsSigned", _withdrawal))] = _number;
}
function affirmationsSigned(bytes32 _withdrawal) public view returns (bool) {
return boolStorage[keccak256(abi.encodePacked("affirmationsSigned", _withdrawal))];
}
function signature(bytes32 _hash, uint256 _index) external 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 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 message(bytes32 _hash) external view returns (bytes) {
return bytesStorage[keccak256(abi.encodePacked("messages", _hash))];
}
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 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 requiredMessageLength() public pure returns (uint256) {
return Message.requiredMessageLength();
}
}
// File: contracts/upgradeable_contracts/FeeTypes.sol
pragma solidity 0.4.24;
contract FeeTypes {
bytes32 internal constant HOME_FEE = 0x89d93e5e92f7e37e490c25f0e50f7f4aad7cc94b308a566553280967be38bcf1; // keccak256(abi.encodePacked("home-fee"))
bytes32 internal constant FOREIGN_FEE = 0xdeb7f3adca07d6d1f708c1774389db532a2b2f18fd05a62b957e4089f4696ed5; // keccak256(abi.encodePacked("foreign-fee"))
/**
* @dev Throws if given fee type is unknown.
*/
modifier validFeeType(bytes32 _feeType) {
require(_feeType == HOME_FEE || _feeType == FOREIGN_FEE);
/* solcov ignore next */
_;
}
}
// File: contracts/upgradeable_contracts/RewardableBridge.sol
pragma solidity 0.4.24;
/**
* @title RewardableBridge
* @dev Common functionality for fee management logic delegation to the separate fee management contract.
*/
contract RewardableBridge is Ownable, FeeTypes {
event FeeDistributedFromAffirmation(uint256 feeAmount, bytes32 indexed transactionHash);
event FeeDistributedFromSignatures(uint256 feeAmount, bytes32 indexed transactionHash);
bytes32 internal constant FEE_MANAGER_CONTRACT = 0x779a349c5bee7817f04c960f525ee3e2f2516078c38c68a3149787976ee837e5; // keccak256(abi.encodePacked("feeManagerContract"))
bytes4 internal constant GET_HOME_FEE = 0x94da17cd; // getHomeFee()
bytes4 internal constant GET_FOREIGN_FEE = 0xffd66196; // getForeignFee()
bytes4 internal constant GET_FEE_MANAGER_MODE = 0xf2ba9561; // getFeeManagerMode()
bytes4 internal constant SET_HOME_FEE = 0x34a9e148; // setHomeFee(uint256)
bytes4 internal constant SET_FOREIGN_FEE = 0x286c4066; // setForeignFee(uint256)
bytes4 internal constant CALCULATE_FEE = 0x9862f26f; // calculateFee(uint256,bool,bytes32)
bytes4 internal constant DISTRIBUTE_FEE_FROM_SIGNATURES = 0x59d78464; // distributeFeeFromSignatures(uint256)
bytes4 internal constant DISTRIBUTE_FEE_FROM_AFFIRMATION = 0x054d46ec; // distributeFeeFromAffirmation(uint256)
/**
* @dev Internal function for reading the fee value from the fee manager.
* @param _feeType type of the fee, should be either HOME_FEE of FOREIGN_FEE.
* @return retrieved fee percentage.
*/
function _getFee(bytes32 _feeType) internal view validFeeType(_feeType) returns (uint256 fee) {
address feeManager = feeManagerContract();
bytes4 method = _feeType == HOME_FEE ? GET_HOME_FEE : GET_FOREIGN_FEE;
bytes memory callData = abi.encodeWithSelector(method);
assembly {
let result := callcode(gas, feeManager, 0x0, add(callData, 0x20), mload(callData), 0, 32)
if and(eq(returndatasize, 32), result) {
fee := mload(0)
}
}
}
/**
* @dev Retrieves the mode of the used fee manager.
* @return manager mode identifier, or zero bytes otherwise.
*/
function getFeeManagerMode() external view returns (bytes4 mode) {
bytes memory callData = abi.encodeWithSelector(GET_FEE_MANAGER_MODE);
address feeManager = feeManagerContract();
assembly {
let result := callcode(gas, feeManager, 0x0, add(callData, 0x20), mload(callData), 0, 4)
if and(eq(returndatasize, 32), result) {
mode := mload(0)
}
}
}
/**
* @dev Retrieves the address of the fee manager contract used.
* @return address of the fee manager contract.
*/
function feeManagerContract() public view returns (address) {
return addressStorage[FEE_MANAGER_CONTRACT];
}
/**
* @dev Updates the address of the used fee manager contract.
* Only contract owner can call this method.
* If during this operation, home fee is changed, it is highly recommended to stop the bridge operations first.
* Otherwise, pending signature requests can become a reason for imbalance between two bridge sides.
* @param _feeManager address of the new fee manager contract, or zero address to disable fee collection.
*/
function setFeeManagerContract(address _feeManager) external onlyOwner {
require(_feeManager == address(0) || AddressUtils.isContract(_feeManager));
addressStorage[FEE_MANAGER_CONTRACT] = _feeManager;
}
/**
* @dev Internal function for setting the fee value by using the fee manager.
* @param _feeManager address of the fee manager contract.
* @param _fee new value for fee percentage amount.
* @param _feeType type of the fee, should be either HOME_FEE of FOREIGN_FEE.
*/
function _setFee(address _feeManager, uint256 _fee, bytes32 _feeType) internal validFeeType(_feeType) {
bytes4 method = _feeType == HOME_FEE ? SET_HOME_FEE : SET_FOREIGN_FEE;
require(_feeManager.delegatecall(abi.encodeWithSelector(method, _fee)));
}
/**
* @dev Calculates the exact fee amount by using the fee manager.
* @param _value transferred value for which fee should be calculated.
* @param _recover true, if the fee was already subtracted from the given _value and needs to be restored.
* @param _impl address of the fee manager contract.
* @param _feeType type of the fee, should be either HOME_FEE of FOREIGN_FEE.
* @return calculated fee amount.
*/
function calculateFee(uint256 _value, bool _recover, address _impl, bytes32 _feeType)
internal
view
returns (uint256 fee)
{
bytes memory callData = abi.encodeWithSelector(CALCULATE_FEE, _value, _recover, _feeType);
assembly {
let result := callcode(gas, _impl, 0x0, add(callData, 0x20), mload(callData), 0, 32)
switch and(eq(returndatasize, 32), result)
case 1 {
fee := mload(0)
}
default {
revert(0, 0)
}
}
}
/**
* @dev Internal function for distributing the fee for collecting sufficient amount of signatures.
* @param _fee amount of fee to distribute.
* @param _feeManager address of the fee manager contract.
* @param _txHash reference transaction hash where the original bridge request happened.
*/
function distributeFeeFromSignatures(uint256 _fee, address _feeManager, bytes32 _txHash) internal {
if (_fee > 0) {
require(_feeManager.delegatecall(abi.encodeWithSelector(DISTRIBUTE_FEE_FROM_SIGNATURES, _fee)));
emit FeeDistributedFromSignatures(_fee, _txHash);
}
}
/**
* @dev Internal function for distributing the fee for collecting sufficient amount of affirmations.
* @param _fee amount of fee to distribute.
* @param _feeManager address of the fee manager contract.
* @param _txHash reference transaction hash where the original bridge request happened.
*/
function distributeFeeFromAffirmation(uint256 _fee, address _feeManager, bytes32 _txHash) internal {
if (_fee > 0) {
require(_feeManager.delegatecall(abi.encodeWithSelector(DISTRIBUTE_FEE_FROM_AFFIRMATION, _fee)));
emit FeeDistributedFromAffirmation(_fee, _txHash);
}
}
}
// File: contracts/upgradeable_contracts/BaseOverdrawManagement.sol
pragma solidity 0.4.24;
/**
* @title BaseOverdrawManagement
* @dev This contract implements basic functionality for tracking execution bridge operations that are out of limits.
*/
contract BaseOverdrawManagement is EternalStorage {
event MediatorAmountLimitExceeded(address recipient, uint256 value, bytes32 indexed messageId);
event AmountLimitExceeded(address recipient, uint256 value, bytes32 indexed transactionHash, bytes32 messageId);
event AssetAboveLimitsFixed(bytes32 indexed messageId, uint256 value, uint256 remaining);
bytes32 internal constant OUT_OF_LIMIT_AMOUNT = 0x145286dc85799b6fb9fe322391ba2d95683077b2adf34dd576dedc437e537ba7; // keccak256(abi.encodePacked("outOfLimitAmount"))
/**
* @dev Total amount coins/tokens that were bridged from the other side and are out of execution limits.
* @return total amount of all bridge operations above limits.
*/
function outOfLimitAmount() public view returns (uint256) {
return uintStorage[OUT_OF_LIMIT_AMOUNT];
}
/**
* @dev Internal function for updating a total amount that is out of execution limits.
* @param _value new value for the total amount of bridge operations above limits.
*/
function setOutOfLimitAmount(uint256 _value) internal {
uintStorage[OUT_OF_LIMIT_AMOUNT] = _value;
}
/**
* @dev Internal function for retrieving information about out-of-limits bridge operation.
* @param _messageId id of the message that cause above-limits error.
* @return (address of the receiver, amount of coins/tokens in the bridge operation)
*/
function txAboveLimits(bytes32 _messageId) internal view returns (address recipient, uint256 value) {
recipient = addressStorage[keccak256(abi.encodePacked("txOutOfLimitRecipient", _messageId))];
value = uintStorage[keccak256(abi.encodePacked("txOutOfLimitValue", _messageId))];
}
/**
* @dev Internal function for updating information about tbe out-of-limits bridge operation.
* @param _recipient receiver specified in the bridge operation.
* @param _value amount of coins/tokens inside the bridge operation.
* @param _messageId id of the message that cause above-limits error.
*/
function setTxAboveLimits(address _recipient, uint256 _value, bytes32 _messageId) internal {
addressStorage[keccak256(abi.encodePacked("txOutOfLimitRecipient", _messageId))] = _recipient;
setTxAboveLimitsValue(_value, _messageId);
}
/**
* @dev Internal function for updating information about the remaining value of out-of-limits bridge operation.
* @param _value amount of coins/tokens inside the bridge operation.
* @param _messageId id of the message that cause above-limits error.
*/
function setTxAboveLimitsValue(uint256 _value, bytes32 _messageId) internal {
uintStorage[keccak256(abi.encodePacked("txOutOfLimitValue", _messageId))] = _value;
}
/* solcov ignore next */
function fixAssetsAboveLimits(bytes32 messageId, bool unlockOnForeign, uint256 valueToUnlock) external;
}
// File: contracts/upgradeable_contracts/HomeOverdrawManagement.sol
pragma solidity 0.4.24;
/**
* @title HomeOverdrawManagement
* @dev This contract implements functionality for recovering from out-of-limits executions in Home side vanilla bridges.
*/
contract HomeOverdrawManagement is BaseOverdrawManagement, RewardableBridge, Upgradeable, BasicHomeBridge {
using SafeMath for uint256;
/**
* @dev Fixes locked tokens, that were out of execution limits during the call to executeAffirmation.
* @param hashMsg reference for bridge operation that was out of execution limits.
* @param unlockOnForeign true if fixed tokens should be unlocked to the other side of the bridge.
* @param valueToUnlock unlocked amount of tokens, should be less than txAboveLimitsValue.
* Should be less than maxPerTx(), if tokens need to be unlocked on the other side.
*/
function fixAssetsAboveLimits(bytes32 hashMsg, bool unlockOnForeign, uint256 valueToUnlock)
external
onlyIfUpgradeabilityOwner
{
uint256 signed = numAffirmationsSigned(hashMsg);
require(!isAlreadyProcessed(signed));
(address recipient, uint256 value) = txAboveLimits(hashMsg);
require(recipient != address(0) && value > 0 && value >= valueToUnlock);
setOutOfLimitAmount(outOfLimitAmount().sub(valueToUnlock));
uint256 pendingValue = value.sub(valueToUnlock);
setTxAboveLimitsValue(pendingValue, hashMsg);
emit AssetAboveLimitsFixed(hashMsg, valueToUnlock, pendingValue);
if (unlockOnForeign) {
require(valueToUnlock <= maxPerTx());
address feeManager = feeManagerContract();
uint256 eventValue = valueToUnlock;
if (feeManager != address(0)) {
uint256 fee = calculateFee(valueToUnlock, false, feeManager, HOME_FEE);
eventValue = valueToUnlock.sub(fee);
}
emit UserRequestForSignature(recipient, eventValue);
}
}
/**
* @dev Internal function for clearing above limits markers for some failed transfer.
* Useful when transfer is being reprocessed on a new day or after limits were updated.
* It is required that fixAssetsAboveLimits was not called on the failed transfer before prior to this function.
* @param _hashMsg hash of the message, works as a unique indentifier.
* @param _value transferred amount of tokens/coins in the fixed message.
*/
function _clearAboveLimitsMarker(bytes32 _hashMsg, uint256 _value) internal {
(address aboveLimitsRecipient, uint256 aboveLimitsValue) = txAboveLimits(_hashMsg);
// check if transfer was marked as out of limits
if (aboveLimitsRecipient != address(0)) {
// revert if a given transaction hash was already processed by the call to fixAssetsAboveLimits
require(aboveLimitsValue == _value);
setTxAboveLimits(address(0), 0, _hashMsg);
setOutOfLimitAmount(outOfLimitAmount().sub(_value));
}
}
}
// File: contracts/upgradeable_contracts/erc20_to_native/RewardableHomeBridgeErcToNative.sol
pragma solidity 0.4.24;
contract RewardableHomeBridgeErcToNative is RewardableBridge {
bytes4 internal constant GET_AMOUNT_TO_BURN = 0x916850e9; // getAmountToBurn(uint256)
/**
* @dev Updates the fee percentage for home->foreign bridge operations.
* Only owner is allowed to call this method.
* If during this operation, home fee is changed, it is highly recommended to stop the bridge operations first.
* Otherwise, pending signature requests can become a reason for imbalance between two bridge sides.
* @param _fee new value for fee percentage.
*/
function setHomeFee(uint256 _fee) external onlyOwner {
_setFee(feeManagerContract(), _fee, HOME_FEE);
}
/**
* @dev Updates the fee percentage for foreign->home bridge operations.
* Only owner is allowed to call this method.
* @param _fee new value for fee percentage.
*/
function setForeignFee(uint256 _fee) external onlyOwner {
_setFee(feeManagerContract(), _fee, FOREIGN_FEE);
}
function getHomeFee() public view returns (uint256) {
return _getFee(HOME_FEE);
}
function getForeignFee() public view returns (uint256) {
return _getFee(FOREIGN_FEE);
}
function getAmountToBurn(uint256 _value) public view returns (uint256 amount) {
bytes memory callData = abi.encodeWithSelector(GET_AMOUNT_TO_BURN, _value);
address feeManager = feeManagerContract();
assembly {
let result := callcode(gas, feeManager, 0x0, add(callData, 0x20), mload(callData), 0, 32)
switch and(eq(returndatasize, 32), result)
case 1 {
amount := mload(0)
}
default {
revert(0, 0)
}
}
}
}
// File: contracts/upgradeable_contracts/BlockRewardBridge.sol
pragma solidity 0.4.24;
contract BlockRewardBridge is EternalStorage {
bytes32 internal constant BLOCK_REWARD_CONTRACT = 0x20ae0b8a761b32f3124efb075f427dd6ca669e88ae7747fec9fd1ad688699f32; // keccak256(abi.encodePacked("blockRewardContract"))
bytes4 internal constant BLOCK_REWARD_CONTRACT_ID = 0x2ee57f8d; // blockRewardContractId()
bytes4 internal constant BRIDGES_ALLOWED_LENGTH = 0x10f2ee7c; // bridgesAllowedLength()
function _blockRewardContract() internal view returns (IBlockReward) {
return IBlockReward(addressStorage[BLOCK_REWARD_CONTRACT]);
}
function _setBlockRewardContract(address _blockReward) internal {
require(AddressUtils.isContract(_blockReward));
// Before store the contract we need to make sure that it is the block reward contract in actual fact,
// call a specific method from the contract that should return a specific value
bool isBlockRewardContract = false;
if (_blockReward.call(BLOCK_REWARD_CONTRACT_ID)) {
isBlockRewardContract =
IBlockReward(_blockReward).blockRewardContractId() == bytes4(keccak256("blockReward"));
} else if (_blockReward.call(BRIDGES_ALLOWED_LENGTH)) {
isBlockRewardContract = IBlockReward(_blockReward).bridgesAllowedLength() != 0;
}
require(isBlockRewardContract);
addressStorage[BLOCK_REWARD_CONTRACT] = _blockReward;
}
}
// File: contracts/upgradeable_contracts/erc20_to_native/HomeBridgeErcToNative.sol
pragma solidity 0.4.24;
/**
* @title HomeBridgeErcToNative
* @dev This contract Home side logic for the erc-to-native vanilla bridge mode.
* It is designed to be used as an implementation contract of EternalStorageProxy contract.
*/
contract HomeBridgeErcToNative is
EternalStorage,
BasicHomeBridge,
HomeOverdrawManagement,
RewardableHomeBridgeErcToNative,
BlockRewardBridge
{
bytes32 internal constant TOTAL_BURNT_COINS = 0x17f187b2e5d1f8770602b32c1159b85c9600859277fae1eaa9982e9bcf63384c; // keccak256(abi.encodePacked("totalBurntCoins"))
function() public payable {
require(msg.data.length == 0);
nativeTransfer(msg.sender);
}
function nativeTransfer(address _receiver) internal {
require(msg.value > 0);
require(withinLimit(msg.value));
IBlockReward blockReward = blockRewardContract();
uint256 totalMinted = blockReward.mintedTotallyByBridge(address(this));
uint256 totalBurnt = totalBurntCoins();
require(msg.value <= totalMinted.sub(totalBurnt));
addTotalSpentPerDay(getCurrentDay(), msg.value);
uint256 valueToTransfer = msg.value;
address feeManager = feeManagerContract();
uint256 valueToBurn = msg.value;
if (feeManager != address(0)) {
uint256 fee = calculateFee(valueToTransfer, false, feeManager, HOME_FEE);
valueToTransfer = valueToTransfer.sub(fee);
valueToBurn = getAmountToBurn(valueToBurn);
}
setTotalBurntCoins(totalBurnt.add(valueToBurn));
address(0).transfer(valueToBurn);
emit UserRequestForSignature(_receiver, valueToTransfer);
}
function relayTokens(address _receiver) external payable {
nativeTransfer(_receiver);
}
function initialize(
address _validatorContract,
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
uint256 _homeGasPrice,
uint256 _requiredBlockConfirmations,
address _blockReward,
uint256[2] _foreignDailyLimitForeignMaxPerTxArray, // [ 0 = _foreignDailyLimit, 1 = _foreignMaxPerTx ]
address _owner,
int256 _decimalShift
) external onlyRelevantSender returns (bool) {
_initialize(
_validatorContract,
_dailyLimitMaxPerTxMinPerTxArray,
_homeGasPrice,
_requiredBlockConfirmations,
_blockReward,
_foreignDailyLimitForeignMaxPerTxArray,
_owner,
_decimalShift
);
setInitialize();
return isInitialized();
}
function rewardableInitialize(
address _validatorContract,
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
uint256 _homeGasPrice,
uint256 _requiredBlockConfirmations,
address _blockReward,
uint256[2] _foreignDailyLimitForeignMaxPerTxArray, // [ 0 = _foreignDailyLimit, 1 = _foreignMaxPerTx ]
address _owner,
address _feeManager,
uint256[2] _homeFeeForeignFeeArray, // [ 0 = _homeFee, 1 = _foreignFee ]
int256 _decimalShift
) external onlyRelevantSender returns (bool) {
_initialize(
_validatorContract,
_dailyLimitMaxPerTxMinPerTxArray,
_homeGasPrice,
_requiredBlockConfirmations,
_blockReward,
_foreignDailyLimitForeignMaxPerTxArray,
_owner,
_decimalShift
);
require(AddressUtils.isContract(_feeManager));
addressStorage[FEE_MANAGER_CONTRACT] = _feeManager;
_setFee(_feeManager, _homeFeeForeignFeeArray[0], HOME_FEE);
_setFee(_feeManager, _homeFeeForeignFeeArray[1], FOREIGN_FEE);
setInitialize();
return isInitialized();
}
function getBridgeMode() external pure returns (bytes4 _data) {
return 0x18762d46; // bytes4(keccak256(abi.encodePacked("erc-to-native-core")))
}
function blockRewardContract() public view returns (IBlockReward) {
return _blockRewardContract();
}
function totalBurntCoins() public view returns (uint256) {
return uintStorage[TOTAL_BURNT_COINS];
}
function setBlockRewardContract(address _blockReward) external onlyOwner {
_setBlockRewardContract(_blockReward);
}
/**
* @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 {
// Since native coins are being minted by the blockReward contract and burned by sending them to the address(0),
// they are not locked at the contract during the normal operation. However, they can be still forced into this contract
// by using a selfdestruct opcode, or by using this contract address as a coinbase account.
// In this case it is necessary to allow claiming native coins back.
// Any other erc20 token can be safely claimed as well.
claimValues(_token, _to);
}
function _initialize(
address _validatorContract,
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
uint256 _homeGasPrice,
uint256 _requiredBlockConfirmations,
address _blockReward,
uint256[2] _foreignDailyLimitForeignMaxPerTxArray, // [ 0 = _foreignDailyLimit, 1 = _foreignMaxPerTx ]
address _owner,
int256 _decimalShift
) internal {
require(!isInitialized());
require(AddressUtils.isContract(_validatorContract));
require(_blockReward == address(0) || AddressUtils.isContract(_blockReward));
addressStorage[VALIDATOR_CONTRACT] = _validatorContract;
uintStorage[DEPLOYED_AT_BLOCK] = block.number;
_setLimits(_dailyLimitMaxPerTxMinPerTxArray);
_setGasPrice(_homeGasPrice);
_setRequiredBlockConfirmations(_requiredBlockConfirmations);
addressStorage[BLOCK_REWARD_CONTRACT] = _blockReward;
_setExecutionLimits(_foreignDailyLimitForeignMaxPerTxArray);
_setDecimalShift(_decimalShift);
_setOwner(_owner);
}
/**
* @dev Internal callback to be called on successfull message execution.
* Should be called only after enough affirmations from the validators are already collected.
* @param _recipient address of the receiver where the new coins should be minted.
* @param _value amount of coins to mint.
* @param _txHash reference transaction hash on the Foreign side of the bridge which cause this operation.
* @param _hashMsg unique identifier of the particular bridge operation.
* @return true, if execution completed successfully.
*/
function onExecuteAffirmation(address _recipient, uint256 _value, bytes32 _txHash, bytes32 _hashMsg)
internal
returns (bool)
{
_clearAboveLimitsMarker(_hashMsg, _value);
addTotalExecutedPerDay(getCurrentDay(), _value);
IBlockReward blockReward = blockRewardContract();
require(blockReward != address(0));
uint256 valueToMint = _shiftValue(_value);
address feeManager = feeManagerContract();
if (feeManager != address(0)) {
uint256 fee = calculateFee(valueToMint, false, feeManager, FOREIGN_FEE);
distributeFeeFromAffirmation(fee, feeManager, _txHash);
valueToMint = valueToMint.sub(fee);
}
blockReward.addExtraReceiver(valueToMint, _recipient);
return true;
}
/**
* @dev Internal function to be called when enough signatures are collected.
* Distributed the fee for collecting signatures.
* @param _message encoded message signed by the validators.
*/
function onSignaturesCollected(bytes _message) internal {
address feeManager = feeManagerContract();
if (feeManager != address(0)) {
(, uint256 amount, bytes32 txHash, ) = Message.parseMessage(_message);
uint256 fee = calculateFee(amount, true, feeManager, HOME_FEE);
distributeFeeFromSignatures(fee, feeManager, txHash);
}
}
function setTotalBurntCoins(uint256 _amount) internal {
uintStorage[TOTAL_BURNT_COINS] = _amount;
}
/**
* @dev Internal callback to be called on failed message execution due to the out-of-limits error.
* This function saves the bridge operation information for further processing.
* @param _recipient address of the receiver where the new coins should be minted.
* @param _value amount of coins to mint.
* @param _txHash reference transaction hash on the Foreign side of the bridge which cause this operation.
* @param _hashMsg unique identifier of the particular bridge operation.
*/
function onFailedAffirmation(address _recipient, uint256 _value, bytes32 _txHash, bytes32 _hashMsg) internal {
(address recipient, uint256 value) = txAboveLimits(_hashMsg);
require(recipient == address(0) && value == 0);
setOutOfLimitAmount(outOfLimitAmount().add(_value));
setTxAboveLimits(_recipient, _value, _hashMsg);
emit AmountLimitExceeded(_recipient, _value, _txHash, _hashMsg);
}
}

Contract ABI

[{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"numMessagesSigned","inputs":[{"type":"bytes32","name":"_message"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"totalBurntCoins","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":[],"name":"setBlockRewardContract","inputs":[{"type":"address","name":"_blockReward"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setForeignFee","inputs":[{"type":"uint256","name":"_fee"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"totalSpentPerDay","inputs":[{"type":"uint256","name":"_day"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setHomeFee","inputs":[{"type":"uint256","name":"_fee"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isInitialized","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setExecutionDailyLimit","inputs":[{"type":"uint256","name":"_dailyLimit"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getCurrentDay","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"requiredBlockConfirmations","inputs":[],"constant":true},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"requiredMessageLength","inputs":[],"constant":true},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"bytes4","name":"_data"}],"name":"getBridgeMode","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"executionDailyLimit","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes","name":""}],"name":"message","inputs":[{"type":"bytes32","name":"_hash"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"totalExecutedPerDay","inputs":[{"type":"uint256","name":"_day"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"blockRewardContract","inputs":[],"constant":true},{"type":"function","stateMutability":"payable","payable":true,"outputs":[],"name":"relayTokens","inputs":[{"type":"address","name":"_receiver"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setFeeManagerContract","inputs":[{"type":"address","name":"_feeManager"}],"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":"uint256","name":""}],"name":"dailyLimit","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"claimTokens","inputs":[{"type":"address","name":"_token"},{"type":"address","name":"_to"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"numAffirmationsSigned","inputs":[{"type":"bytes32","name":"_withdrawal"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"affirmationsSigned","inputs":[{"type":"bytes32","name":"_withdrawal"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"initialize","inputs":[{"type":"address","name":"_validatorContract"},{"type":"uint256[3]","name":"_dailyLimitMaxPerTxMinPerTxArray"},{"type":"uint256","name":"_homeGasPrice"},{"type":"uint256","name":"_requiredBlockConfirmations"},{"type":"address","name":"_blockReward"},{"type":"uint256[2]","name":"_foreignDailyLimitForeignMaxPerTxArray"},{"type":"address","name":"_owner"},{"type":"int256","name":"_decimalShift"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"withinExecutionLimit","inputs":[{"type":"uint256","name":"_amount"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"executionMaxPerTx","inputs":[],"constant":true},{"type":"function","stateMutability":"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":"view","payable":false,"outputs":[{"type":"uint256","name":"amount"}],"name":"getAmountToBurn","inputs":[{"type":"uint256","name":"_value"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getHomeFee","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"maxAvailablePerTx","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"validatorContract","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"executeAffirmation","inputs":[{"type":"address","name":"recipient"},{"type":"uint256","name":"value"},{"type":"bytes32","name":"transactionHash"}],"constant":false},{"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":""}],"name":"outOfLimitAmount","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setMinPerTx","inputs":[{"type":"uint256","name":"_minPerTx"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"fixAssetsAboveLimits","inputs":[{"type":"bytes32","name":"hashMsg"},{"type":"bool","name":"unlockOnForeign"},{"type":"uint256","name":"valueToUnlock"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setRequiredBlockConfirmations","inputs":[{"type":"uint256","name":"_blockConfirmations"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setDailyLimit","inputs":[{"type":"uint256","name":"_dailyLimit"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setGasPrice","inputs":[{"type":"uint256","name":"_gasPrice"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setMaxPerTx","inputs":[{"type":"uint256","name":"_maxPerTx"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"int256","name":""}],"name":"decimalShift","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"feeManagerContract","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"minPerTx","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"rewardableInitialize","inputs":[{"type":"address","name":"_validatorContract"},{"type":"uint256[3]","name":"_dailyLimitMaxPerTxMinPerTxArray"},{"type":"uint256","name":"_homeGasPrice"},{"type":"uint256","name":"_requiredBlockConfirmations"},{"type":"address","name":"_blockReward"},{"type":"uint256[2]","name":"_foreignDailyLimitForeignMaxPerTxArray"},{"type":"address","name":"_owner"},{"type":"address","name":"_feeManager"},{"type":"uint256[2]","name":"_homeFeeForeignFeeArray"},{"type":"int256","name":"_decimalShift"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"withinLimit","inputs":[{"type":"uint256","name":"_amount"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setExecutionMaxPerTx","inputs":[{"type":"uint256","name":"_maxPerTx"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes4","name":"mode"}],"name":"getFeeManagerMode","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"maxPerTx","inputs":[],"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":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getForeignFee","inputs":[],"constant":true},{"type":"fallback","stateMutability":"payable","payable":true},{"type":"event","name":"UserRequestForSignature","inputs":[{"type":"address","name":"recipient","indexed":false},{"type":"uint256","name":"value","indexed":false}],"anonymous":false},{"type":"event","name":"AffirmationCompleted","inputs":[{"type":"address","name":"recipient","indexed":false},{"type":"uint256","name":"value","indexed":false},{"type":"bytes32","name":"transactionHash","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":"transactionHash","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":"DailyLimitChanged","inputs":[{"type":"uint256","name":"newLimit","indexed":false}],"anonymous":false},{"type":"event","name":"ExecutionDailyLimitChanged","inputs":[{"type":"uint256","name":"newLimit","indexed":false}],"anonymous":false},{"type":"event","name":"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":"FeeDistributedFromAffirmation","inputs":[{"type":"uint256","name":"feeAmount","indexed":false},{"type":"bytes32","name":"transactionHash","indexed":true}],"anonymous":false},{"type":"event","name":"FeeDistributedFromSignatures","inputs":[{"type":"uint256","name":"feeAmount","indexed":false},{"type":"bytes32","name":"transactionHash","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":false},{"type":"address","name":"newOwner","indexed":false}],"anonymous":false},{"type":"event","name":"MediatorAmountLimitExceeded","inputs":[{"type":"address","name":"recipient","indexed":false},{"type":"uint256","name":"value","indexed":false},{"type":"bytes32","name":"messageId","indexed":true}],"anonymous":false},{"type":"event","name":"AmountLimitExceeded","inputs":[{"type":"address","name":"recipient","indexed":false},{"type":"uint256","name":"value","indexed":false},{"type":"bytes32","name":"transactionHash","indexed":true},{"type":"bytes32","name":"messageId","indexed":false}],"anonymous":false},{"type":"event","name":"AssetAboveLimitsFixed","inputs":[{"type":"bytes32","name":"messageId","indexed":true},{"type":"uint256","name":"value","indexed":false},{"type":"uint256","name":"remaining","indexed":false}],"anonymous":false}]
            

Deployed ByteCode

0x6080604052600436106102845763ffffffff60e060020a6000350416630cbf0601811461029a5780630e8162ba146102c45780631812d996146102d957806327a3e16b14610369578063286c40661461038a5780632bd0bb05146103a257806334a9e148146103ba578063392e53cd146103d25780633dd95d1b146103fb5780633e6968b6146104135780633f0a9f6514610428578063408fef2e1461043d578063437764df1461045257806343b37dd314610484578063490a32c6146104995780634fb3fef7146104b157806356b54bae146104c95780635d1e9307146104fa57806360756f7c1461050e578063630cea8e1461052f57806367eeba0c1461055b57806369ffa08a146105705780636ae1a976146105975780637698da24146105af578063865c8028146105c7578063879ce676146106075780638aa1949a1461061f5780638d068043146106345780638da5cb5b146106495780638f4b4b981461065e578063916850e91461067657806394da17cd1461068e57806395e54a17146106a357806399439089146106b8578063995b2cff146106cd5780639a454b99146106f45780639cb7595a14610709578063a01893451461074a578063a2a6ca271461075f578063a7444c0d14610777578063acf5c68914610797578063b20d30a9146107af578063bf1fe420146107c7578063c6f6f216146107df578063dae5f0fd146107f7578063dbe03a8b1461080c578063df25f3f014610821578063e13d3c7914610836578063ea9f496814610880578063f20151e114610898578063f2ba9561146108b0578063f2fde38b146108c5578063f968adbe146108e6578063fe173b97146108fb578063ffd19e8c14610910578063ffd6619614610928575b361561028f57600080fd5b6102983361093d565b005b3480156102a657600080fd5b506102b2600435610b25565b60408051918252519081900360200190f35b3480156102d057600080fd5b506102b2610bea565b3480156102e557600080fd5b506102f4600435602435610c39565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561032e578181015183820152602001610316565b50505050905090810190601f16801561035b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561037557600080fd5b50610298600160a060020a0360043516610e16565b34801561039657600080fd5b50610298600435610e3e565b3480156103ae57600080fd5b506102b2600435610e7a565b3480156103c657600080fd5b50610298600435610ef5565b3480156103de57600080fd5b506103e7610f31565b604080519115158252519081900360200190f35b34801561040757600080fd5b50610298600435610f82565b34801561041f57600080fd5b506102b2611042565b34801561043457600080fd5b506102b261104b565b34801561044957600080fd5b506102b2611099565b34801561045e57600080fd5b506104676110a8565b60408051600160e060020a03199092168252519081900360200190f35b34801561049057600080fd5b506102b26110cc565b3480156104a557600080fd5b506102f460043561111a565b3480156104bd57600080fd5b506102b2600435611282565b3480156104d557600080fd5b506104de6112fd565b60408051600160a060020a039092168252519081900360200190f35b610298600160a060020a0360043516611307565b34801561051a57600080fd5b50610298600160a060020a0360043516611310565b34801561053b57600080fd5b5061029860246004803582810192908201359181359182019101356113bb565b34801561056757600080fd5b506102b2611851565b34801561057c57600080fd5b50610298600160a060020a036004358116906024351661189f565b3480156105a357600080fd5b506102b260043561192b565b3480156105bb57600080fd5b506103e76004356119ae565b3480156105d357600080fd5b506103e7600160a060020a036004358116906024906084359060a4359060c43581169060e490610124351661014435611a77565b34801561061357600080fd5b506103e7600435611c27565b34801561062b57600080fd5b506102b2611c71565b34801561064057600080fd5b506102b2611cbf565b34801561065557600080fd5b506104de611d37565b34801561066a57600080fd5b506103e7600435611d8e565b34801561068257600080fd5b506102b2600435611e12565b34801561069a57600080fd5b506102b2611ea2565b3480156106af57600080fd5b506102b2611ebb565b3480156106c457600080fd5b506104de611f15565b3480156106d957600080fd5b50610298600160a060020a0360043516602435604435611f6c565b34801561070057600080fd5b506102b2612272565b34801561071557600080fd5b5061071e6122c0565b6040805167ffffffffffffffff9485168152928416602084015292168183015290519081900360600190f35b34801561075657600080fd5b506102b26122cb565b34801561076b57600080fd5b50610298600435612319565b34801561078357600080fd5b5061029860043560243515156044356123b5565b3480156107a357600080fd5b506102986004356125c6565b3480156107bb57600080fd5b506102986004356125eb565b3480156107d357600080fd5b506102986004356126ab565b3480156107eb57600080fd5b506102986004356126d0565b34801561080357600080fd5b506102b2612768565b34801561081857600080fd5b506104de6127b6565b34801561082d57600080fd5b506102b261280d565b34801561084257600080fd5b506103e7600160a060020a036004358116906024906084359060a4359060c43581169060e4906101243581169061014435166101646101a43561285b565b34801561088c57600080fd5b506103e7600435612ac2565b3480156108a457600080fd5b50610298600435612b0d565b3480156108bc57600080fd5b50610467612b89565b3480156108d157600080fd5b50610298600160a060020a0360043516612bff565b3480156108f257600080fd5b506102b2612c24565b34801561090757600080fd5b506102b2612c72565b34801561091c57600080fd5b506103e7600435612cc0565b34801561093457600080fd5b506102b2612ce8565b600080808080808034811061095157600080fd5b61095a34612ac2565b151561096557600080fd5b61096d6112fd565b604080517fb4a523e80000000000000000000000000000000000000000000000000000000081523060048201529051919850600160a060020a0389169163b4a523e8916024808201926020929091908290030181600087803b1580156109d257600080fd5b505af11580156109e6573d6000803e3d6000fd5b505050506040513d60208110156109fc57600080fd5b50519550610a08610bea565b9450610a1a868663ffffffff612d0116565b341115610a2657600080fd5b610a37610a31611042565b34612d18565b349350610a426127b6565b9250349150600160a060020a03831615610a9157610a7184600085600080516020614e20833981519152612de1565b9050610a83848263ffffffff612d0116565b9350610a8e82611e12565b91505b610aa9610aa4868463ffffffff612e7216565b612e7f565b60405160009083156108fc0290849083818181858288f19350505050158015610ad6573d6000803e3d6000fd5b5060408051600160a060020a038a1681526020810186905281517f127650bcfb0ba017401abe4931453a405140a8fd36fece67bae2db174d3fdd63929181900390910190a15050505050505050565b60008060008360405160200180807f6e756d4d657373616765735369676e656400000000000000000000000000000081525060110182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310610ba95780518252601f199092019160209182019101610b8a565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205495945050505050565b7f17f187b2e5d1f8770602b32c1159b85c9600859277fae1eaa9982e9bcf63384c60009081526020527fdb09a09557fcb6a80beaaeeb5e8935e3bc5b43e4685b36cbc7f7f31d3b0a9763545b90565b604080516020808201859052818301849052825180830384018152606092830193849052805192936000939192909182918401908083835b60208310610c905780518252601f199092019160209182019101610c71565b51815160209384036101000a6000190180199092169116179052604080519290940182900382207f7369676e6174757265730000000000000000000000000000000000000000000083830152602a80840182905285518085039091018152604a9093019485905282519097506003965060009550919392508291908401908083835b60208310610d315780518252601f199092019160209182019101610d12565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020600019166000191681526020019081526020016000208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610e085780601f10610ddd57610100808354040283529160200191610e08565b820191906000526020600020905b815481529060010190602001808311610deb57829003601f168201915b505050505091505092915050565b610e1e611d37565b600160a060020a03163314610e3257600080fd5b610e3b81612ecc565b50565b610e46611d37565b600160a060020a03163314610e5a57600080fd5b610e3b610e656127b6565b82600080516020614e00833981519152613118565b60008060008360405160200180807f746f74616c5370656e745065724461790000000000000000000000000000000081525060100182815260200191505060405160208183030381529060405260405180828051906020019080838360208310610ba95780518252601f199092019160209182019101610b8a565b610efd611d37565b600160a060020a03163314610f1157600080fd5b610e3b610f1c6127b6565b82600080516020614e20833981519152613118565b7f0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba60005260046020527f078d888f9b66f3f8bfa10909e31f1e16240db73449f0500afdbbe3a70da457cc5460ff1690565b610f8a611d37565b600160a060020a03163314610f9e57600080fd5b610fa6611c71565b811180610fb1575080155b1515610fbc57600080fd5b7f21dbcab260e413c20dc13c28b7db95e2b423d1135f42bb8b7d5214a92270d237600090815260209081527fadd938dbd083a16bae12238cd914fca0afc7a30edb55b1cd5c7f1823f1b0e4218290556040805183815290517f9bebf928b90863f24cc31f726a3a7545efd409f1dcf552301b1ee3710da70d3b929181900390910190a150565b62015180420490565b7f916daedf6915000ff68ced2f0b6773fe6f2582237f92c3c95bb4d7940723007160009081526020527fd2ea0feb732edb0ffe32efd33a6b9d24d46b16eb34a4d07ce256537b6f131e425490565b60006110a361326f565b905090565b7f18762d460000000000000000000000000000000000000000000000000000000090565b7f21dbcab260e413c20dc13c28b7db95e2b423d1135f42bb8b7d5214a92270d23760009081526020527fadd938dbd083a16bae12238cd914fca0afc7a30edb55b1cd5c7f1823f1b0e4215490565b6060600360008360405160200180807f6d6573736167657300000000000000000000000000000000000000000000000081525060080182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b6020831061119f5780518252601f199092019160209182019101611180565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020600019166000191681526020019081526020016000208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156112765780601f1061124b57610100808354040283529160200191611276565b820191906000526020600020905b81548152906001019060200180831161125957829003601f168201915b50505050509050919050565b60008060008360405160200180807f746f74616c45786563757465645065724461790000000000000000000000000081525060130182815260200191505060405160208183030381529060405260405180828051906020019080838360208310610ba95780518252601f199092019160209182019101610b8a565b60006110a3613274565b610e3b8161093d565b611318611d37565b600160a060020a0316331461132c57600080fd5b600160a060020a03811615806113465750611346816132cb565b151561135157600080fd5b7f779a349c5bee7817f04c960f525ee3e2f2516078c38c68a3149787976ee837e560005260026020527fc155b21a14c4592b97825e495fbe0d2705fb46420018cac5bfa7a09c43fae5178054600160a060020a031916600160a060020a0392909216919091179055565b60008060008060006113cb611f15565b600160a060020a031663facd743b336040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b15801561142557600080fd5b505af1158015611439573d6000803e3d6000fd5b505050506040513d602081101561144f57600080fd5b5051151561145c57600080fd5b61149587878080601f016020809104026020016040519081016040528093929190818152602001838380828437506132d3945050505050565b15156114a057600080fd5b61150a89898080601f0160208091040260200160405190810160405280939291908181526020018383808284375050604080516020601f8f018190048102820181019092528d815294508d93508c9250829150840183828082843750600094506132e79350505050565b600160a060020a0316331461151e57600080fd5b8686604051602001808383808284378201915050925050506040516020818303038152906040526040518082805190602001908083835b602083106115745780518252601f199092019160209182019101611555565b51815160209384036101000a600019018019909216911617905260408051929094018290038220336c0100000000000000000000000002838301526034808401829052855180850390910181526054909301948590528251909b509195509293508392850191508083835b602083106115fe5780518252601f1990920191602091820191016115df565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020935061163685610b25565b925061164183612cc0565b1561164b57600080fd5b6001928301928311156116705761166184611d8e565b1561166b57600080fd5b6116aa565b6116aa8588888080601f016020809104026020016040519081016040528093929190818152602001838380828437506133e6945050505050565b6116b58460016134bd565b604080516020808201889052600019860182840152825180830384018152606090920192839052815191929182918401908083835b602083106117095780518252601f1990920191602091820191016116ea565b51815160209384036101000a600019018019909216911617905260408051929094018290038220601f8f018290048202830182019094528d825292965061176a9450869350918d91508c90819084018382808284375061358f945050505050565b6117748584613612565b60408051868152905133917fbf06885f40778f5ccfb64497d3f92ce568ddaedb7e2fb4487f72690418cf8e4c919081900360200190a26117b2611cbf565b9050808310611846576117cd856117c885613694565b613612565b604080513381526020810187905280820183905290517f415557404d88a0c0b8e3b16967cafffc511213fd9c465c16832ee17ed57d72379181900360600190a161184687878080601f016020809104026020016040519081016040528093929190818152602001838380828437506136b9945050505050565b505050505050505050565b7f4a6a899679f26b73530d8cf1001e83b6f7702e04b6fdb98f3c62dc7e47e041a560009081526020527f1ab29a5cca988aee50edccdd61c5bcaa7ad4b29a03b7ee50f298ceccfe14cc4e5490565b30600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156118dd57600080fd5b505af11580156118f1573d6000803e3d6000fd5b505050506040513d602081101561190757600080fd5b5051600160a060020a0316331461191d57600080fd5b6119278282613712565b5050565b60008060008360405160200180807f6e756d41666669726d6174696f6e735369676e65640000000000000000000000815250601501826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310610ba95780518252601f199092019160209182019101610b8a565b6000600460008360405160200180807f61666669726d6174696f6e735369676e6564000000000000000000000000000081525060120182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310611a335780518252601f199092019160209182019101611a14565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205460ff1695945050505050565b6040805160048152602481018252602081018051600160e060020a03167f6fde8202000000000000000000000000000000000000000000000000000000001781529151815160009330939291829190808383895b83811015611ae3578181015183820152602001611acb565b50505050905090810190601f168015611b105780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af19150501580611ba2575030600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015611b6a57600080fd5b505af1158015611b7e573d6000803e3d6000fd5b505050506040513d6020811015611b9457600080fd5b5051600160a060020a031633145b80611bac57503330145b1515611bb757600080fd5b611c0a8989600380602002604051908101604052809291908260036020028082843750506040805180820182528e94508d93508c9250908b90600290839083908082843782019150505050508989613750565b611c126138c4565b611c1a610f31565b9998505050505050505050565b600080611c4a83611c3e611c39611042565b611282565b9063ffffffff612e7216565b905080611c556110cc565b10158015611c6a5750611c66611c71565b8311155b9392505050565b7fc0ed44c192c86d1cc1ba51340b032c2766b4a2b0041031de13c46dd7104888d560009081526020527ff8e983ee86e5e377e9e34c9131b266382c3f04113d20de077f9e12663c7a646b5490565b6000611cc9611f15565b600160a060020a0316638d0680436040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015611d0657600080fd5b505af1158015611d1a573d6000803e3d6000fd5b505050506040513d6020811015611d3057600080fd5b5051905090565b7f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c060005260026020527fb7802e97e87ef2842a6cce7da7ffaeaedaa2f61a6a7870b23d9d01fc9b73712e54600160a060020a031690565b6000600460008360405160200180807f6d657373616765735369676e6564000000000000000000000000000000000000815250600e01826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310611a335780518252601f199092019160209182019101611a14565b604080516024808201849052825180830390910181526044909101909152602081018051600160e060020a03167f916850e90000000000000000000000000000000000000000000000000000000017905260009081611e6f6127b6565b9050602060008351602085016000855af28060203d141660018114611e9357600080fd5b60005194505b50505050919050565b60006110a3600080516020614e2083398151915261391b565b6000806000806000611ecb612c24565b9350611ed5611851565b9250611ee7611ee2611042565b610e7a565b9150818311611ef7576000611efb565b8183035b9050808410611f0a5780611f0c565b835b94505050505090565b7f5a74bb7e202fb8e4bf311841c7d64ec19df195fee77d7e7ae749b27921b6ddfe60005260026020527fab54f3fbbe62c59b7876a9bf9bd5e0c22dbae93f4d8ee0438f7ce62b198eb0e054600160a060020a031690565b6000806000611f79611f15565b600160a060020a031663facd743b336040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b158015611fd357600080fd5b505af1158015611fe7573d6000803e3d6000fd5b505050506040513d6020811015611ffd57600080fd5b5051151561200a57600080fd5b604080516c01000000000000000000000000600160a060020a0389160260208083019190915260348201889052605480830188905283518084039091018152607490920192839052815191929182918401908083835b6020831061207f5780518252601f199092019160209182019101612060565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902092506120b785611c27565b1561225e57604080516c010000000000000000000000003302602080830191909152603480830187905283518084039091018152605490920192839052815191929182918401908083835b602083106121215780518252601f199092019160209182019101612102565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209150612159826119ae565b1561216357600080fd5b61216e826001613a15565b6121778361192b565b905061218281612cc0565b1561218c57600080fd5b6001016121998382613a98565b60408051858152905133917f5df9cc3eb93d8a9a481857a3b70a8ca966e6b80b25cf0ee2cce180ec5afa80a1919081900360200190a26121d7611cbf565b8110612259576121ef836121ea83613694565b613a98565b600085111561220f5761220486868686613b1a565b151561220f57600080fd5b60408051600160a060020a03881681526020810187905280820186905290517f6fc115a803b8703117d9a3956c5a15401cb42401f91630f015eb6b043fa762539181900360600190a15b61226a565b61226a86868686613c45565b505050505050565b7fb120ceec05576ad0c710bc6e85f1768535e27554458f05dcbb5c65b8c7a749b060009081526020527fe66bef0282a446f9848e2903380099bb6e431483ee78778868f33b4a154c818b5490565b600660016000909192565b7f145286dc85799b6fb9fe322391ba2d95683077b2adf34dd576dedc437e537ba760009081526020527fba10c7a68bf463c41368d64adcf7df23c0de931ea3b09f061e2dfec302fef95f5490565b612321611d37565b600160a060020a0316331461233557600080fd5b60008111801561234b5750612348611851565b81105b801561235d575061235a612c24565b81105b151561236857600080fd5b7fbbb088c505d18e049d114c7c91f11724e69c55ad6c5397e2b929e68b41fa05d160009081526020527f8df5c48c6b6e11d97548adc824ba0c99103ec09830fa5d53a179984085e6eaa055565b600080600080600080600030600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156123fe57600080fd5b505af1158015612412573d6000803e3d6000fd5b505050506040513d602081101561242857600080fd5b5051600160a060020a0316331461243e57600080fd5b6124478a61192b565b965061245287612cc0565b1561245c57600080fd5b6124658a613ce4565b9096509450600160a060020a038616158015906124825750600085115b801561248e5750878510155b151561249957600080fd5b6124b96124b4896124a86122cb565b9063ffffffff612d0116565b613e6b565b6124c9858963ffffffff612d0116565b93506124d5848b613eb8565b604080518981526020810186905281518c927f5bcec6564fe8d2cbb4e4eb8237510ceb6b291a5c2ee2e429948d25e9c924c1fa928290030190a288156125ba5761251d612c24565b88111561252957600080fd5b6125316127b6565b9250879150600160a060020a038316156125755761256088600085600080516020614e20833981519152612de1565b9050612572888263ffffffff612d0116565b91505b60408051600160a060020a03881681526020810184905281517f127650bcfb0ba017401abe4931453a405140a8fd36fece67bae2db174d3fdd63929181900390910190a15b50505050505050505050565b6125ce611d37565b600160a060020a031633146125e257600080fd5b610e3b81613f3a565b6125f3611d37565b600160a060020a0316331461260757600080fd5b61260f612c24565b81118061261a575080155b151561262557600080fd5b7f4a6a899679f26b73530d8cf1001e83b6f7702e04b6fdb98f3c62dc7e47e041a5600090815260209081527f1ab29a5cca988aee50edccdd61c5bcaa7ad4b29a03b7ee50f298ceccfe14cc4e8290556040805183815290517fad4123ae17c414d9c6d2fec478b402e6b01856cc250fd01fbfd252fda0089d3c929181900390910190a150565b6126b3611d37565b600160a060020a031633146126c757600080fd5b610e3b81613fcd565b6126d8611d37565b600160a060020a031633146126ec57600080fd5b80158061271057506126fc61280d565b81118015612710575061270d611851565b81105b151561271b57600080fd5b7f0f8803acad17c63ee38bf2de71e1888bc7a079a6f73658e274b08018bea4e29c60009081526020527f9de0f81379b4d8e60fe509315d071b56e7b732abaf193e74e0d15808b0951d0955565b7f1e8ecaafaddea96ed9ac6d2642dcdfe1bebe58a930b1085842d8fc122b371ee560009081526020527fd5c78dd9468716ca9bb96be25d56436811b20aab3523a9904b12deef1cab239d5490565b7f779a349c5bee7817f04c960f525ee3e2f2516078c38c68a3149787976ee837e560005260026020527fc155b21a14c4592b97825e495fbe0d2705fb46420018cac5bfa7a09c43fae51754600160a060020a031690565b7fbbb088c505d18e049d114c7c91f11724e69c55ad6c5397e2b929e68b41fa05d160009081526020527f8df5c48c6b6e11d97548adc824ba0c99103ec09830fa5d53a179984085e6eaa05490565b6040805160048152602481018252602081018051600160e060020a03167f6fde8202000000000000000000000000000000000000000000000000000000001781529151815160009330939291829190808383895b838110156128c75781810151838201526020016128af565b50505050905090810190601f1680156128f45780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af19150501580612986575030600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561294e57600080fd5b505af1158015612962573d6000803e3d6000fd5b505050506040513d602081101561297857600080fd5b5051600160a060020a031633145b8061299057503330145b151561299b57600080fd5b6129f58b8b600380602002604051908101604052809291908260036020028082843782019150505050508b8b8b8b600280602002604051908101604052809291908260026020028082843782019150505050508b89613750565b6129fe846132cb565b1515612a0957600080fd5b7f779a349c5bee7817f04c960f525ee3e2f2516078c38c68a3149787976ee837e560005260026020527fc155b21a14c4592b97825e495fbe0d2705fb46420018cac5bfa7a09c43fae5178054600160a060020a031916600160a060020a038616179055612a86848435600080516020614e20833981519152613118565b612aa3846020850135600080516020614e00833981519152613118565b612aab6138c4565b612ab3610f31565b9b9a5050505050505050505050565b600080612ad483611c3e611ee2611042565b905080612adf611851565b10158015612af45750612af0612c24565b8311155b8015611c6a5750612b0361280d565b9092101592915050565b612b15611d37565b600160a060020a03163314612b2957600080fd5b612b316110cc565b8110612b3c57600080fd5b7fc0ed44c192c86d1cc1ba51340b032c2766b4a2b0041031de13c46dd7104888d560009081526020527ff8e983ee86e5e377e9e34c9131b266382c3f04113d20de077f9e12663c7a646b55565b604080516004815260248101909152602081018051600160e060020a03167ff2ba95610000000000000000000000000000000000000000000000000000000017905260009081612bd76127b6565b9050600460008351602085016000855af28060203d141615612bf95760005193505b50505090565b612c07611d37565b600160a060020a03163314612c1b57600080fd5b610e3b81614053565b7f0f8803acad17c63ee38bf2de71e1888bc7a079a6f73658e274b08018bea4e29c60009081526020527f9de0f81379b4d8e60fe509315d071b56e7b732abaf193e74e0d15808b0951d095490565b7f55b3774520b5993024893d303890baa4e84b1244a43c60034d1ced2d3cf2b04b60009081526020527ff7d5eefab3776d7f0450bd0193564bcb4f832ce313ff2836c450fc63a4b944195490565b7f80000000000000000000000000000000000000000000000000000000000000009081161490565b60006110a3600080516020614e0083398151915261391b565b600082821115612d0d57fe5b508082035b92915050565b612d2581611c3e84610e7a565b6000808460405160200180807f746f74616c5370656e74506572446179000000000000000000000000000000008152506010018281526020019150506040516020818303038152906040526040518082805190602001908083835b60208310612d9f5780518252601f199092019160209182019101612d80565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020939093555050505050565b60408051602481018690528415156044820152606480820184905282518083039091018152608490910190915260208181018051600160e060020a03167f9862f26f000000000000000000000000000000000000000000000000000000001781528251600093929184919082885af28060203d141660018114612e6357600080fd5b50506000519695505050505050565b81810182811015612d1257fe5b7f17f187b2e5d1f8770602b32c1159b85c9600859277fae1eaa9982e9bcf63384c60009081526020527fdb09a09557fcb6a80beaaeeb5e8935e3bc5b43e4685b36cbc7f7f31d3b0a976355565b6000612ed7826132cb565b1515612ee257600080fd5b6000905081600160a060020a0316632ee57f8d60e060020a0260e060020a90046040518163ffffffff1660e060020a0281526004016000604051808303816000875af19250505015612fea5760405180807f626c6f636b526577617264000000000000000000000000000000000000000000815250600b0190506040518091039020600160e060020a03191682600160a060020a0316632ee57f8d6040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015612fac57600080fd5b505af1158015612fc0573d6000803e3d6000fd5b505050506040513d6020811015612fd657600080fd5b5051600160e060020a0319161490506130a1565b81600160a060020a03166310f2ee7c60e060020a0260e060020a90046040518163ffffffff1660e060020a0281526004016000604051808303816000875af192505050156130a15781600160a060020a03166310f2ee7c6040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561307057600080fd5b505af1158015613084573d6000803e3d6000fd5b505050506040513d602081101561309a57600080fd5b5051151590505b8015156130ad57600080fd5b507f20ae0b8a761b32f3124efb075f427dd6ca669e88ae7747fec9fd1ad688699f3260005260026020527fd76793c705b076d97d490f0c1e5a620caae2c4973213dc37ef69a1be2a5ec0708054600160a060020a031916600160a060020a0392909216919091179055565b600081600080516020614e208339815191528114806131445750600080516020614e0083398151915281145b151561314f57600080fd5b600080516020614e20833981519152831461318a577f286c4066000000000000000000000000000000000000000000000000000000006131ac565b7f34a9e148000000000000000000000000000000000000000000000000000000005b6040805160248082018890528251808303909101815260449091018252602081018051600160e060020a0316600160e060020a0319851617815291518151939550600160a060020a038916939192909182919080838360005b8381101561321d578181015183820152602001613205565b50505050905090810190601f16801561324a5780820380516001836020036101000a031916815260200191505b50915050600060405180830381855af4915050151561326857600080fd5b5050505050565b606890565b7f20ae0b8a761b32f3124efb075f427dd6ca669e88ae7747fec9fd1ad688699f3260005260026020527fd76793c705b076d97d490f0c1e5a620caae2c4973213dc37ef69a1be2a5ec07054600160a060020a031690565b6000903b1190565b60006132dd61326f565b8251149050919050565b600080600080865160411415156132fd57600080fd5b505050602084015160408501516060860151601b60ff60f860020a83041614806133305750601c60ff60f860020a830416145b151561333b57600080fd5b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a082111561336857600080fd5b6001613374878761411d565b60408051600080825260208083018085529490945260ff60f860020a870416828401526060820188905260808201879052915160a08083019493601f198301938390039091019190865af11580156133d0573d6000803e3d6000fd5b5050604051601f19015198975050505050505050565b80600360008460405160200180807f6d6573736167657300000000000000000000000000000000000000000000000081525060080182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b6020831061346a5780518252601f19909201916020918201910161344b565b51815160001960209485036101000a019081169019919091161790526040805194909201849003909320865285830196909652509290930160002084516134b8959194509201919050614d37565b505050565b80600460008460405160200180807f6d657373616765735369676e6564000000000000000000000000000000000000815250600e0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106135415780518252601f199092019160209182019101613522565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805460ff1916941515949094179093555050505050565b80600360008460405160200180807f7369676e61747572657300000000000000000000000000000000000000000000815250600a0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083836020831061346a5780518252601f19909201916020918201910161344b565b806000808460405160200180807f6e756d4d657373616765735369676e6564000000000000000000000000000000815250601101826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310612d9f5780518252601f199092019160209182019101612d80565b7f80000000000000000000000000000000000000000000000000000000000000001790565b6000806000806136c76127b6565b9350600160a060020a03841615613268576136e185614337565b50935093505061370583600186600080516020614e20833981519152600102612de1565b9050613268818584614372565b80600160a060020a038116151561372857600080fd5b600160a060020a03831615156137465761374182614480565b6134b8565b6134b8838361448c565b613758610f31565b1561376257600080fd5b61376b886132cb565b151561377657600080fd5b600160a060020a03841615806137905750613790846132cb565b151561379b57600080fd5b7fab54f3fbbe62c59b7876a9bf9bd5e0c22dbae93f4d8ee0438f7ce62b198eb0e08054600160a060020a031916600160a060020a038a161790557fb120ceec05576ad0c710bc6e85f1768535e27554458f05dcbb5c65b8c7a749b06000908152602052437fe66bef0282a446f9848e2903380099bb6e431483ee78778868f33b4a154c818b5561382a8761453f565b61383386613fcd565b61383c85613f3a565b7f20ae0b8a761b32f3124efb075f427dd6ca669e88ae7747fec9fd1ad688699f3260005260026020527fd76793c705b076d97d490f0c1e5a620caae2c4973213dc37ef69a1be2a5ec0708054600160a060020a031916600160a060020a0386161790556138a88361469c565b6138b181614771565b6138ba82614053565b5050505050505050565b7f0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba60005260046020527f078d888f9b66f3f8bfa10909e31f1e16240db73449f0500afdbbe3a70da457cc805460ff19166001179055565b60008080606084600080516020614e2083398151915281148061394b5750600080516020614e0083398151915281145b151561395657600080fd5b61395e6127b6565b9350600080516020614e20833981519152861461399b577fffd66196000000000000000000000000000000000000000000000000000000006139bd565b7f94da17cd000000000000000000000000000000000000000000000000000000005b60408051600481526024810190915260208082018051600160e060020a0316600160e060020a0319851617815282519396509194509160009182885af28060203d141615613a0b5760005195505b5050505050919050565b80600460008460405160200180807f61666669726d6174696f6e735369676e656400000000000000000000000000008152506012018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106135415780518252601f199092019160209182019101613522565b806000808460405160200180807f6e756d41666669726d6174696f6e735369676e65640000000000000000000000815250601501826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310612d9f5780518252601f199092019160209182019101612d80565b6000806000806000613b2c86896147da565b613b3d613b37611042565b89614821565b613b456112fd565b9350600160a060020a0384161515613b5c57600080fd5b613b65886148a7565b9250613b6f6127b6565b9150600160a060020a03821615613bbb57613b9b83600084600080516020614e00833981519152612de1565b9050613ba88183896148ba565b613bb8838263ffffffff612d0116565b92505b83600160a060020a031663aa9fa274848b6040518363ffffffff1660e060020a0281526004018083815260200182600160a060020a0316600160a060020a0316815260200192505050600060405180830381600087803b158015613c1e57600080fd5b505af1158015613c32573d6000803e3d6000fd5b5060019c9b505050505050505050505050565b600080613c5183613ce4565b9092509050600160a060020a038216158015613c6b575080155b1515613c7657600080fd5b613c856124b486611c3e6122cb565b613c908686856149c8565b60408051600160a060020a038816815260208101879052808201859052905185917f26c0a209907d8e06e55b84dfc43d1429e22a3bab2b4f9cfd49d5f7f447a42c4f919081900360600190a2505050505050565b600080600260008460405160200180807f74784f75744f664c696d6974526563697069656e74000000000000000000000081525060150182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310613d6a5780518252601f199092019160209182019101613d4b565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652858101969096525092830160009081205484517f74784f75744f664c696d697456616c75650000000000000000000000000000008188015260318082018b9052865180830390910181526051909101958690528051600160a060020a0390921698509195869592945091925082918401908083835b60208310613e285780518252601f199092019160209182019101613e09565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002054949694955050505050565b7f145286dc85799b6fb9fe322391ba2d95683077b2adf34dd576dedc437e537ba760009081526020527fba10c7a68bf463c41368d64adcf7df23c0de931ea3b09f061e2dfec302fef95f55565b816000808360405160200180807f74784f75744f664c696d697456616c7565000000000000000000000000000000815250601101826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310612d9f5780518252601f199092019160209182019101612d80565b60008111613f4757600080fd5b7f916daedf6915000ff68ced2f0b6773fe6f2582237f92c3c95bb4d79407230071600090815260209081527fd2ea0feb732edb0ffe32efd33a6b9d24d46b16eb34a4d07ce256537b6f131e428290556040805183815290517f4fb76205cd57c896b21511d2114137d8e901b4ccd659e1a0f97d6306795264fb929181900390910190a150565b7f55b3774520b5993024893d303890baa4e84b1244a43c60034d1ced2d3cf2b04b600090815260209081527ff7d5eefab3776d7f0450bd0193564bcb4f832ce313ff2836c450fc63a4b944198290556040805183815290517f52264b89e0fceafb26e79fd49ef8a366eb6297483bf4035b027f0c99a7ad512e929181900390910190a150565b600160a060020a038116151561406857600080fd5b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0614091611d37565b60408051600160a060020a03928316815291841660208301528051918290030190a17f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c060005260026020527fb7802e97e87ef2842a6cce7da7ffaeaedaa2f61a6a7870b23d9d01fc9b73712e8054600160a060020a031916600160a060020a0392909216919091179055565b60408051808201909152601a81527f19457468657265756d205369676e6564204d6573736167653a0a0000000000006020820152600090606083156142c357816141678651614ab1565b866040516020018084805190602001908083835b6020831061419a5780518252601f19909201916020918201910161417b565b51815160209384036101000a600019018019909216911617905286519190930192860191508083835b602083106141e25780518252601f1990920191602091820191016141c3565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b6020831061422a5780518252601f19909201916020918201910161420b565b6001836020036101000a03801982511681845116808217855250505050505090500193505050506040516020818303038152906040526040518082805190602001908083835b6020831061428f5780518252601f199092019160209182019101614270565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020925061432f565b6040805190810160405280600381526020017f313034000000000000000000000000000000000000000000000000000000000081525090508181866040516020018084805190602001908083836020831061419a5780518252601f19909201916020918201910161417b565b505092915050565b600080600080614346856132d3565b151561435157600080fd5b50505050601481015160348201516054830151606890930151919390929190565b60008311156134b8576040805160248082018690528251808303909101815260449091018252602081018051600160e060020a03167f59d784640000000000000000000000000000000000000000000000000000000017815291518151600160a060020a03861693829180838360005b838110156143fa5781810151838201526020016143e2565b50505050905090810190601f1680156144275780820380516001836020036101000a031916815260200191505b50915050600060405180830381855af4915050151561444557600080fd5b60408051848152905182917f858abdcd5efcaebb936e8e8516f0cfe9a0ef5157ff99d16cdabb6db625be90d0919081900360200190a2505050565b30316119278282614bb8565b604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290518391600091600160a060020a038416916370a0823191602480830192602092919082900301818787803b1580156144f157600080fd5b505af1158015614505573d6000803e3d6000fd5b505050506040513d602081101561451b57600080fd5b50519050614539600160a060020a038516848363ffffffff614c1916565b50505050565b6040810151600010801561455a575060408101516020820151115b801561456a575060208101518151115b151561457557600080fd5b80517f4a6a899679f26b73530d8cf1001e83b6f7702e04b6fdb98f3c62dc7e47e041a5600090815260208181527f1ab29a5cca988aee50edccdd61c5bcaa7ad4b29a03b7ee50f298ceccfe14cc4e92909255908201517f0f8803acad17c63ee38bf2de71e1888bc7a079a6f73658e274b08018bea4e29c82527f9de0f81379b4d8e60fe509315d071b56e7b732abaf193e74e0d15808b0951d095560408201517fbbb088c505d18e049d114c7c91f11724e69c55ad6c5397e2b929e68b41fa05d182527f8df5c48c6b6e11d97548adc824ba0c99103ec09830fa5d53a179984085e6eaa0557fad4123ae17c414d9c6d2fec478b402e6b01856cc250fd01fbfd252fda0089d3c9082905b60200201516040518082815260200191505060405180910390a150565b80516020820151106146ad57600080fd5b80517f21dbcab260e413c20dc13c28b7db95e2b423d1135f42bb8b7d5214a92270d237600090815260208181527fadd938dbd083a16bae12238cd914fca0afc7a30edb55b1cd5c7f1823f1b0e42192909255908201517fc0ed44c192c86d1cc1ba51340b032c2766b4a2b0041031de13c46dd7104888d582527ff8e983ee86e5e377e9e34c9131b266382c3f04113d20de077f9e12663c7a646b557f9bebf928b90863f24cc31f726a3a7545efd409f1dcf552301b1ee3710da70d3b90829061467f565b604c19811380156147825750604d81125b151561478d57600080fd5b7f1e8ecaafaddea96ed9ac6d2642dcdfe1bebe58a930b1085842d8fc122b371ee560009081526020527fd5c78dd9468716ca9bb96be25d56436811b20aab3523a9904b12deef1cab239d55565b6000806147e684613ce4565b9092509050600160a060020a038216156145395780831461480657600080fd5b614812600080866149c8565b6145396124b4846124a86122cb565b61482e81611c3e84611282565b6000808460405160200180807f746f74616c45786563757465645065724461790000000000000000000000000081525060130182815260200191505060405160208183030381529060405260405180828051906020019080838360208310612d9f5780518252601f199092019160209182019101612d80565b6000612d12826148b5612768565b614cae565b60008311156134b8576040805160248082018690528251808303909101815260449091018252602081018051600160e060020a03167f054d46ec0000000000000000000000000000000000000000000000000000000017815291518151600160a060020a03861693829180838360005b8381101561494257818101518382015260200161492a565b50505050905090810190601f16801561496f5780820380516001836020036101000a031916815260200191505b50915050600060405180830381855af4915050151561498d57600080fd5b60408051848152905182917fa52d3c9cbc541772e4edd92e2e4e2a3865ab73630f25deed8a6c8de41ff0f65c919081900360200190a2505050565b82600260008360405160200180807f74784f75744f664c696d6974526563697069656e74000000000000000000000081525060150182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310614a4c5780518252601f199092019160209182019101614a2d565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000208054600160a060020a031916600160a060020a039590951694909417909355506134b8915083905082613eb8565b60606000808281851515614afa5760408051808201909152600181527f300000000000000000000000000000000000000000000000000000000000000060208201529450611e99565b8593505b8315614b1557600190920191600a84049350614afe565b826040519080825280601f01601f191660200182016040528015614b43578160200160208202803883390190505b5091505060001982015b8515614baf57815160001982019160f860020a6030600a8a060102918491908110614b7457fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a86049550614b4d565b50949350505050565b604051600160a060020a0383169082156108fc029083906000818181858888f193505050501515611927578082614bed614db5565b600160a060020a039091168152604051908190036020019082f080158015613268573d6000803e3d6000fd5b82600160a060020a031663a9059cbb83836040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050600060405180830381600087803b158015614c7c57600080fd5b505af1158015614c90573d6000803e3d6000fd5b505050503d156134b85760206000803e60005115156134b857600080fd5b6000811515614cbe575081612d12565b6000821315614ce257614cdb83600a84900a63ffffffff614cf916565b9050612d12565b611c6a836000849003600a0a63ffffffff614d2216565b6000821515614d0a57506000612d12565b50818102818382811515614d1a57fe5b0414612d1257fe5b60008183811515614d2f57fe5b049392505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10614d7857805160ff1916838001178555614da5565b82800160010185558215614da5579182015b82811115614da5578251825591602001919060010190614d8a565b50614db1929150614dc4565b5090565b604051602180614ddf83390190565b610c3691905b80821115614db15760008155600101614dca5600608060405260405160208060218339810160405251600160a060020a038116ff00deb7f3adca07d6d1f708c1774389db532a2b2f18fd05a62b957e4089f4696ed589d93e5e92f7e37e490c25f0e50f7f4aad7cc94b308a566553280967be38bcf1a165627a7a723058208cd9ace7fe6c4a258ec475186c02c9b7111859e3e9ea33d210a0705f9f8adcf20029