- Contract name:
- HomeBridgeNativeToErc
- Optimization enabled
- true
- Compiler version
- v0.4.24+commit.e67f0147
- Optimization runs
- 200
- EVM Version
- byzantium
- Verified at
- 2021-09-03T23:31:05.109724Z
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 104: 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: 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 (5, 2, 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) {
// solhint-disable-next-line not-rely-on-time
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/native_to_erc20/RewardableHomeBridgeNativeToErc.sol
pragma solidity 0.4.24;
contract RewardableHomeBridgeNativeToErc is RewardableBridge {
/**
* @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 getForeignFee() public view returns (uint256) {
return _getFee(FOREIGN_FEE);
}
function getHomeFee() public view returns (uint256) {
return _getFee(HOME_FEE);
}
}
// File: contracts/upgradeable_contracts/native_to_erc20/HomeBridgeNativeToErc.sol
pragma solidity 0.4.24;
/**
* @title HomeBridgeNativeToErc
* @dev This contract Home side logic for the native-to-erc vanilla bridge mode.
* It is designed to be used as an implementation contract of EternalStorageProxy contract.
*/
contract HomeBridgeNativeToErc is EternalStorage, BasicHomeBridge, RewardableHomeBridgeNativeToErc {
function() public payable {
require(msg.data.length == 0);
nativeTransfer(msg.sender);
}
function nativeTransfer(address _receiver) internal {
require(msg.value > 0);
require(withinLimit(msg.value));
addTotalSpentPerDay(getCurrentDay(), msg.value);
uint256 valueToTransfer = msg.value;
address feeManager = feeManagerContract();
if (feeManager != address(0)) {
uint256 fee = calculateFee(valueToTransfer, false, feeManager, HOME_FEE);
valueToTransfer = valueToTransfer.sub(fee);
}
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,
uint256[2] _foreignDailyLimitForeignMaxPerTxArray, // [ 0 = _foreignDailyLimit, 1 = _foreignMaxPerTx ]
address _owner,
int256 _decimalShift
) external onlyRelevantSender returns (bool) {
_initialize(
_validatorContract,
_dailyLimitMaxPerTxMinPerTxArray,
_homeGasPrice,
_requiredBlockConfirmations,
_foreignDailyLimitForeignMaxPerTxArray,
_owner,
_decimalShift
);
setInitialize();
return isInitialized();
}
function rewardableInitialize(
address _validatorContract,
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
uint256 _homeGasPrice,
uint256 _requiredBlockConfirmations,
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,
_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 0x92a8d7fe; // bytes4(keccak256(abi.encodePacked("native-to-erc-core")))
}
/**
* @dev Allows to transfer any locked token on this contract that is not part of the bridge operations.
* Native tokens are not allowed to be claimed.
* @param _token address of the token.
* @param _to address that will receive the locked tokens on this contract.
*/
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
// Since bridged coins are locked at this contract, it is not allowed to claim them with the use of claimTokens function
require(_token != address(0));
claimValues(_token, _to);
}
function _initialize(
address _validatorContract,
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
uint256 _homeGasPrice,
uint256 _requiredBlockConfirmations,
uint256[2] _foreignDailyLimitForeignMaxPerTxArray, // [ 0 = _foreignDailyLimit, 1 = _foreignMaxPerTx ]
address _owner,
int256 _decimalShift
) internal {
require(!isInitialized());
require(AddressUtils.isContract(_validatorContract));
addressStorage[VALIDATOR_CONTRACT] = _validatorContract;
uintStorage[DEPLOYED_AT_BLOCK] = block.number;
_setLimits(_dailyLimitMaxPerTxMinPerTxArray);
_setGasPrice(_homeGasPrice);
_setRequiredBlockConfirmations(_requiredBlockConfirmations);
_setExecutionLimits(_foreignDailyLimitForeignMaxPerTxArray);
_setDecimalShift(_decimalShift);
_setOwner(_owner);
}
/**
* @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);
}
}
/**
* @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 unlocked.
* @param _value amount of coins to unlock.
* @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.
* Not used in this bridge mode, but required for interface unification with other bridge modes.
* @return true, if execution completed successfully.
*/
function onExecuteAffirmation(address _recipient, uint256 _value, bytes32 _txHash, bytes32 _hashMsg)
internal
returns (bool)
{
addTotalExecutedPerDay(getCurrentDay(), _value);
uint256 valueToTransfer = _shiftValue(_value);
address feeManager = feeManagerContract();
if (feeManager != address(0)) {
uint256 fee = calculateFee(valueToTransfer, false, feeManager, FOREIGN_FEE);
distributeFeeFromAffirmation(fee, feeManager, _txHash);
valueToTransfer = valueToTransfer.sub(fee);
}
Address.safeSendValue(_recipient, valueToTransfer);
return true;
}
/**
* @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 unlocked.
* @param _value amount of coins to unlock.
* @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 {
// solhint-disable-previous-line no-unused-vars
revert();
}
/**
* @dev Internal function for updating fallback gas price value.
* @param _gasPrice new value for the gas price, zero gas price is not allowed.
*/
function _setGasPrice(uint256 _gasPrice) internal {
require(_gasPrice > 0);
super._setGasPrice(_gasPrice);
}
}
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":"bytes","name":""}],"name":"signature","inputs":[{"type":"bytes32","name":"_hash"},{"type":"uint256","name":"_index"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"rewardableInitialize","inputs":[{"type":"address","name":"_validatorContract"},{"type":"uint256[3]","name":"_dailyLimitMaxPerTxMinPerTxArray"},{"type":"uint256","name":"_homeGasPrice"},{"type":"uint256","name":"_requiredBlockConfirmations"},{"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":"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":[{"type":"bool","name":""}],"name":"initialize","inputs":[{"type":"address","name":"_validatorContract"},{"type":"uint256[3]","name":"_dailyLimitMaxPerTxMinPerTxArray"},{"type":"uint256","name":"_homeGasPrice"},{"type":"uint256","name":"_requiredBlockConfirmations"},{"type":"uint256[2]","name":"_foreignDailyLimitForeignMaxPerTxArray"},{"type":"address","name":"_owner"},{"type":"int256","name":"_decimalShift"}],"constant":false},{"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":"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":"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":""}],"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":"nonpayable","payable":false,"outputs":[],"name":"setMinPerTx","inputs":[{"type":"uint256","name":"_minPerTx"}],"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":"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":"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":"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":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":false},{"type":"address","name":"newOwner","indexed":false}],"anonymous":false}]
Deployed ByteCode
0x6080604052600436106102425763ffffffff60e060020a6000350416630cbf060181146102585780631812d9961461028257806323589d5014610312578063286c40661461036a5780632bd0bb051461038257806333ddcd691461039a57806334a9e148146103d4578063392e53cd146103ec5780633dd95d1b146104015780633e6968b6146104195780633f0a9f651461042e578063408fef2e14610443578063437764df1461045857806343b37dd31461049f578063490a32c6146104b45780634fb3fef7146104cc5780635d1e9307146104e457806360756f7c146104f8578063630cea8e1461051957806367eeba0c1461054557806369ffa08a1461055a5780636ae1a976146105815780637698da2414610599578063879ce676146105b15780638aa1949a146105c95780638d068043146105de5780638da5cb5b146105f35780638f4b4b981461062457806394da17cd1461063c57806395e54a17146106515780639943908914610666578063995b2cff1461067b5780639a454b99146106a25780639cb7595a146106b7578063a2a6ca27146106f8578063acf5c68914610710578063b20d30a914610728578063bf1fe42014610740578063c6f6f21614610758578063dae5f0fd14610770578063dbe03a8b14610785578063df25f3f01461079a578063ea9f4968146107af578063f20151e1146107c7578063f2ba9561146107df578063f2fde38b146107f4578063f968adbe14610815578063fe173b971461082a578063ffd19e8c1461083f578063ffd6619614610857575b361561024d57600080fd5b6102563361086c565b005b34801561026457600080fd5b50610270600435610937565b60408051918252519081900360200190f35b34801561028e57600080fd5b5061029d6004356024356109fc565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102d75781810151838201526020016102bf565b50505050905090810190601f1680156103045780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561031e57600080fd5b50610356600160a060020a036004358116906024906084359060a4359060c49061010435811690610124351661014461018435610bd9565b604080519115158252519081900360200190f35b34801561037657600080fd5b50610256600435610e43565b34801561038e57600080fd5b50610270600435610e82565b3480156103a657600080fd5b50610356600160a060020a036004358116906024906084359060a4359060c490610104351661012435610efd565b3480156103e057600080fd5b506102566004356110aa565b3480156103f857600080fd5b506103566110e6565b34801561040d57600080fd5b50610256600435611138565b34801561042557600080fd5b506102706111f8565b34801561043a57600080fd5b50610270611201565b34801561044f57600080fd5b5061027061124f565b34801561046457600080fd5b5061046d61125e565b604080517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff199092168252519081900360200190f35b3480156104ab57600080fd5b50610270611282565b3480156104c057600080fd5b5061029d6004356112d0565b3480156104d857600080fd5b50610270600435611438565b610256600160a060020a03600435166114b3565b34801561050457600080fd5b50610256600160a060020a03600435166114bc565b34801561052557600080fd5b506102566024600480358281019290820135918135918201910135611574565b34801561055157600080fd5b50610270611a0a565b34801561056657600080fd5b50610256600160a060020a0360043581169060243516611a58565b34801561058d57600080fd5b50610270600435611af9565b3480156105a557600080fd5b50610356600435611b7c565b3480156105bd57600080fd5b50610356600435611c45565b3480156105d557600080fd5b50610270611c8f565b3480156105ea57600080fd5b50610270611cdd565b3480156105ff57600080fd5b50610608611d55565b60408051600160a060020a039092168252519081900360200190f35b34801561063057600080fd5b50610356600435611dac565b34801561064857600080fd5b50610270611e30565b34801561065d57600080fd5b50610270611e49565b34801561067257600080fd5b50610608611ea3565b34801561068757600080fd5b50610256600160a060020a0360043516602435604435611efa565b3480156106ae57600080fd5b50610270612200565b3480156106c357600080fd5b506106cc61224e565b6040805167ffffffffffffffff9485168152928416602084015292168183015290519081900360600190f35b34801561070457600080fd5b50610256600435612259565b34801561071c57600080fd5b506102566004356122f5565b34801561073457600080fd5b5061025660043561231a565b34801561074c57600080fd5b506102566004356123da565b34801561076457600080fd5b506102566004356123ff565b34801561077c57600080fd5b50610270612497565b34801561079157600080fd5b506106086124e5565b3480156107a657600080fd5b5061027061253c565b3480156107bb57600080fd5b5061035660043561258a565b3480156107d357600080fd5b506102566004356125d5565b3480156107eb57600080fd5b5061046d612651565b34801561080057600080fd5b50610256600160a060020a03600435166126c7565b34801561082157600080fd5b506102706126ec565b34801561083657600080fd5b5061027061273a565b34801561084b57600080fd5b50610356600435612788565b34801561086357600080fd5b506102706127b0565b6000808034811061087c57600080fd5b6108853461258a565b151561089057600080fd5b6108a161089b6111f8565b346127c9565b3492506108ac6124e5565b9150600160a060020a038216156108ed576108d883600084600080516020614110833981519152612892565b90506108ea838263ffffffff61292316565b92505b60408051600160a060020a03861681526020810185905281517f127650bcfb0ba017401abe4931453a405140a8fd36fece67bae2db174d3fdd63929181900390910190a150505050565b60008060008360405160200180807f6e756d4d657373616765735369676e656400000000000000000000000000000081525060110182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106109bb5780518252601f19909201916020918201910161099c565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205495945050505050565b604080516020808201859052818301849052825180830384018152606092830193849052805192936000939192909182918401908083835b60208310610a535780518252601f199092019160209182019101610a34565b51815160209384036101000a6000190180199092169116179052604080519290940182900382207f7369676e6174757265730000000000000000000000000000000000000000000083830152602a80840182905285518085039091018152604a9093019485905282519097506003965060009550919392508291908401908083835b60208310610af45780518252601f199092019160209182019101610ad5565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020600019166000191681526020019081526020016000208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610bcb5780601f10610ba057610100808354040283529160200191610bcb565b820191906000526020600020905b815481529060010190602001808311610bae57829003601f168201915b505050505091505092915050565b6040805160048152602481018252602081018051600160e060020a03167f6fde8202000000000000000000000000000000000000000000000000000000001781529151815160009330939291829190808383895b83811015610c45578181015183820152602001610c2d565b50505050905090810190601f168015610c725780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af19150501580610d04575030600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015610ccc57600080fd5b505af1158015610ce0573d6000803e3d6000fd5b505050506040513d6020811015610cf657600080fd5b5051600160a060020a031633145b80610d0e57503330145b1515610d1957600080fd5b610d6a8a8a600380602002604051908101604052809291908260036020028082843750506040805180820182528f94508e935091508c90600290839083908082843782019150505050508a8861293a565b610d7384612a32565b1515610d7e57600080fd5b7f779a349c5bee7817f04c960f525ee3e2f2516078c38c68a3149787976ee837e560005260026020527fc155b21a14c4592b97825e495fbe0d2705fb46420018cac5bfa7a09c43fae517805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a038616179055610e08848435600080516020614110833981519152612a3a565b610e258460208501356000805160206140f0833981519152612a3a565b610e2d612ba6565b610e356110e6565b9a9950505050505050505050565b610e4b611d55565b600160a060020a03163314610e5f57600080fd5b610e7f610e6a6124e5565b826000805160206140f0833981519152612a3a565b50565b60008060008360405160200180807f746f74616c5370656e7450657244617900000000000000000000000000000000815250601001828152602001915050604051602081830303815290604052604051808280519060200190808383602083106109bb5780518252601f19909201916020918201910161099c565b6040805160048152602481018252602081018051600160e060020a03167f6fde8202000000000000000000000000000000000000000000000000000000001781529151815160009330939291829190808383895b83811015610f69578181015183820152602001610f51565b50505050905090810190601f168015610f965780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af19150501580611028575030600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015610ff057600080fd5b505af1158015611004573d6000803e3d6000fd5b505050506040513d602081101561101a57600080fd5b5051600160a060020a031633145b8061103257503330145b151561103d57600080fd5b61108e8888600380602002604051908101604052809291908260036020028082843750506040805180820182528d94508c935091508a9060029083908390808284378201915050505050888861293a565b611096612ba6565b61109e6110e6565b98975050505050505050565b6110b2611d55565b600160a060020a031633146110c657600080fd5b610e7f6110d16124e5565b82600080516020614110833981519152612a3a565b7f0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba60005260046020527f078d888f9b66f3f8bfa10909e31f1e16240db73449f0500afdbbe3a70da457cc5460ff165b90565b611140611d55565b600160a060020a0316331461115457600080fd5b61115c611c8f565b811180611167575080155b151561117257600080fd5b7f21dbcab260e413c20dc13c28b7db95e2b423d1135f42bb8b7d5214a92270d237600090815260209081527fadd938dbd083a16bae12238cd914fca0afc7a30edb55b1cd5c7f1823f1b0e4218290556040805183815290517f9bebf928b90863f24cc31f726a3a7545efd409f1dcf552301b1ee3710da70d3b929181900390910190a150565b62015180420490565b7f916daedf6915000ff68ced2f0b6773fe6f2582237f92c3c95bb4d7940723007160009081526020527fd2ea0feb732edb0ffe32efd33a6b9d24d46b16eb34a4d07ce256537b6f131e425490565b6000611259612bfd565b905090565b7f92a8d7fe0000000000000000000000000000000000000000000000000000000090565b7f21dbcab260e413c20dc13c28b7db95e2b423d1135f42bb8b7d5214a92270d23760009081526020527fadd938dbd083a16bae12238cd914fca0afc7a30edb55b1cd5c7f1823f1b0e4215490565b6060600360008360405160200180807f6d6573736167657300000000000000000000000000000000000000000000000081525060080182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106113555780518252601f199092019160209182019101611336565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020600019166000191681526020019081526020016000208054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561142c5780601f106114015761010080835404028352916020019161142c565b820191906000526020600020905b81548152906001019060200180831161140f57829003601f168201915b50505050509050919050565b60008060008360405160200180807f746f74616c457865637574656450657244617900000000000000000000000000815250601301828152602001915050604051602081830303815290604052604051808280519060200190808383602083106109bb5780518252601f19909201916020918201910161099c565b610e7f8161086c565b6114c4611d55565b600160a060020a031633146114d857600080fd5b600160a060020a03811615806114f257506114f281612a32565b15156114fd57600080fd5b7f779a349c5bee7817f04c960f525ee3e2f2516078c38c68a3149787976ee837e560005260026020527fc155b21a14c4592b97825e495fbe0d2705fb46420018cac5bfa7a09c43fae517805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b6000806000806000611584611ea3565b600160a060020a031663facd743b336040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b1580156115de57600080fd5b505af11580156115f2573d6000803e3d6000fd5b505050506040513d602081101561160857600080fd5b5051151561161557600080fd5b61164e87878080601f01602080910402602001604051908101604052809392919081815260200183838082843750612c02945050505050565b151561165957600080fd5b6116c389898080601f0160208091040260200160405190810160405280939291908181526020018383808284375050604080516020601f8f018190048102820181019092528d815294508d93508c925082915084018382808284375060009450612c169350505050565b600160a060020a031633146116d757600080fd5b8686604051602001808383808284378201915050925050506040516020818303038152906040526040518082805190602001908083835b6020831061172d5780518252601f19909201916020918201910161170e565b51815160209384036101000a600019018019909216911617905260408051929094018290038220336c0100000000000000000000000002838301526034808401829052855180850390910181526054909301948590528251909b509195509293508392850191508083835b602083106117b75780518252601f199092019160209182019101611798565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902093506117ef85610937565b92506117fa83612788565b1561180457600080fd5b6001928301928311156118295761181a84611dac565b1561182457600080fd5b611863565b6118638588888080601f01602080910402602001604051908101604052809392919081815260200183838082843750612d15945050505050565b61186e846001612dec565b604080516020808201889052600019860182840152825180830384018152606090920192839052815191929182918401908083835b602083106118c25780518252601f1990920191602091820191016118a3565b51815160209384036101000a600019018019909216911617905260408051929094018290038220601f8f018290048202830182019094528d82529296506119239450869350918d91508c908190840183828082843750612ebe945050505050565b61192d8584612f41565b60408051868152905133917fbf06885f40778f5ccfb64497d3f92ce568ddaedb7e2fb4487f72690418cf8e4c919081900360200190a261196b611cdd565b90508083106119ff576119868561198185612fc3565b612f41565b604080513381526020810187905280820183905290517f415557404d88a0c0b8e3b16967cafffc511213fd9c465c16832ee17ed57d72379181900360600190a16119ff87878080601f01602080910402602001604051908101604052809392919081815260200183838082843750612fe8945050505050565b505050505050505050565b7f4a6a899679f26b73530d8cf1001e83b6f7702e04b6fdb98f3c62dc7e47e041a560009081526020527f1ab29a5cca988aee50edccdd61c5bcaa7ad4b29a03b7ee50f298ceccfe14cc4e5490565b30600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015611a9657600080fd5b505af1158015611aaa573d6000803e3d6000fd5b505050506040513d6020811015611ac057600080fd5b5051600160a060020a03163314611ad657600080fd5b600160a060020a0382161515611aeb57600080fd5b611af58282613041565b5050565b60008060008360405160200180807f6e756d41666669726d6174696f6e735369676e656400000000000000000000008152506015018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106109bb5780518252601f19909201916020918201910161099c565b6000600460008360405160200180807f61666669726d6174696f6e735369676e6564000000000000000000000000000081525060120182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310611c015780518252601f199092019160209182019101611be2565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205460ff1695945050505050565b600080611c6883611c5c611c576111f8565b611438565b9063ffffffff61307f16565b905080611c73611282565b10158015611c885750611c84611c8f565b8311155b9392505050565b7fc0ed44c192c86d1cc1ba51340b032c2766b4a2b0041031de13c46dd7104888d560009081526020527ff8e983ee86e5e377e9e34c9131b266382c3f04113d20de077f9e12663c7a646b5490565b6000611ce7611ea3565b600160a060020a0316638d0680436040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015611d2457600080fd5b505af1158015611d38573d6000803e3d6000fd5b505050506040513d6020811015611d4e57600080fd5b5051905090565b7f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c060005260026020527fb7802e97e87ef2842a6cce7da7ffaeaedaa2f61a6a7870b23d9d01fc9b73712e54600160a060020a031690565b6000600460008360405160200180807f6d657373616765735369676e6564000000000000000000000000000000000000815250600e01826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310611c015780518252601f199092019160209182019101611be2565b600061125960008051602061411083398151915261308c565b6000806000806000611e596126ec565b9350611e63611a0a565b9250611e75611e706111f8565b610e82565b9150818311611e85576000611e89565b8183035b9050808410611e985780611e9a565b835b94505050505090565b7f5a74bb7e202fb8e4bf311841c7d64ec19df195fee77d7e7ae749b27921b6ddfe60005260026020527fab54f3fbbe62c59b7876a9bf9bd5e0c22dbae93f4d8ee0438f7ce62b198eb0e054600160a060020a031690565b6000806000611f07611ea3565b600160a060020a031663facd743b336040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b158015611f6157600080fd5b505af1158015611f75573d6000803e3d6000fd5b505050506040513d6020811015611f8b57600080fd5b50511515611f9857600080fd5b604080516c01000000000000000000000000600160a060020a0389160260208083019190915260348201889052605480830188905283518084039091018152607490920192839052815191929182918401908083835b6020831061200d5780518252601f199092019160209182019101611fee565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020925061204585611c45565b156121ec57604080516c010000000000000000000000003302602080830191909152603480830187905283518084039091018152605490920192839052815191929182918401908083835b602083106120af5780518252601f199092019160209182019101612090565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902091506120e782611b7c565b156120f157600080fd5b6120fc82600161319b565b61210583611af9565b905061211081612788565b1561211a57600080fd5b600101612127838261321e565b60408051858152905133917f5df9cc3eb93d8a9a481857a3b70a8ca966e6b80b25cf0ee2cce180ec5afa80a1919081900360200190a2612165611cdd565b81106121e75761217d8361217883612fc3565b61321e565b600085111561219d57612192868686866132a0565b151561219d57600080fd5b60408051600160a060020a03881681526020810187905280820186905290517f6fc115a803b8703117d9a3956c5a15401cb42401f91630f015eb6b043fa762539181900360600190a15b6121f8565b6121f88686868661332e565b505050505050565b7fb120ceec05576ad0c710bc6e85f1768535e27554458f05dcbb5c65b8c7a749b060009081526020527fe66bef0282a446f9848e2903380099bb6e431483ee78778868f33b4a154c818b5490565b600560026000909192565b612261611d55565b600160a060020a0316331461227557600080fd5b60008111801561228b5750612288611a0a565b81105b801561229d575061229a6126ec565b81105b15156122a857600080fd5b7fbbb088c505d18e049d114c7c91f11724e69c55ad6c5397e2b929e68b41fa05d160009081526020527f8df5c48c6b6e11d97548adc824ba0c99103ec09830fa5d53a179984085e6eaa055565b6122fd611d55565b600160a060020a0316331461231157600080fd5b610e7f81613333565b612322611d55565b600160a060020a0316331461233657600080fd5b61233e6126ec565b811180612349575080155b151561235457600080fd5b7f4a6a899679f26b73530d8cf1001e83b6f7702e04b6fdb98f3c62dc7e47e041a5600090815260209081527f1ab29a5cca988aee50edccdd61c5bcaa7ad4b29a03b7ee50f298ceccfe14cc4e8290556040805183815290517fad4123ae17c414d9c6d2fec478b402e6b01856cc250fd01fbfd252fda0089d3c929181900390910190a150565b6123e2611d55565b600160a060020a031633146123f657600080fd5b610e7f816133c6565b612407611d55565b600160a060020a0316331461241b57600080fd5b80158061243f575061242b61253c565b8111801561243f575061243c611a0a565b81105b151561244a57600080fd5b7f0f8803acad17c63ee38bf2de71e1888bc7a079a6f73658e274b08018bea4e29c60009081526020527f9de0f81379b4d8e60fe509315d071b56e7b732abaf193e74e0d15808b0951d0955565b7f1e8ecaafaddea96ed9ac6d2642dcdfe1bebe58a930b1085842d8fc122b371ee560009081526020527fd5c78dd9468716ca9bb96be25d56436811b20aab3523a9904b12deef1cab239d5490565b7f779a349c5bee7817f04c960f525ee3e2f2516078c38c68a3149787976ee837e560005260026020527fc155b21a14c4592b97825e495fbe0d2705fb46420018cac5bfa7a09c43fae51754600160a060020a031690565b7fbbb088c505d18e049d114c7c91f11724e69c55ad6c5397e2b929e68b41fa05d160009081526020527f8df5c48c6b6e11d97548adc824ba0c99103ec09830fa5d53a179984085e6eaa05490565b60008061259c83611c5c611e706111f8565b9050806125a7611a0a565b101580156125bc57506125b86126ec565b8311155b8015611c8857506125cb61253c565b9092101592915050565b6125dd611d55565b600160a060020a031633146125f157600080fd5b6125f9611282565b811061260457600080fd5b7fc0ed44c192c86d1cc1ba51340b032c2766b4a2b0041031de13c46dd7104888d560009081526020527ff8e983ee86e5e377e9e34c9131b266382c3f04113d20de077f9e12663c7a646b55565b604080516004815260248101909152602081018051600160e060020a03167ff2ba9561000000000000000000000000000000000000000000000000000000001790526000908161269f6124e5565b9050600460008351602085016000855af28060203d1416156126c15760005193505b50505090565b6126cf611d55565b600160a060020a031633146126e357600080fd5b610e7f816133dc565b7f0f8803acad17c63ee38bf2de71e1888bc7a079a6f73658e274b08018bea4e29c60009081526020527f9de0f81379b4d8e60fe509315d071b56e7b732abaf193e74e0d15808b0951d095490565b7f55b3774520b5993024893d303890baa4e84b1244a43c60034d1ced2d3cf2b04b60009081526020527ff7d5eefab3776d7f0450bd0193564bcb4f832ce313ff2836c450fc63a4b944195490565b7f80000000000000000000000000000000000000000000000000000000000000009081161490565b60006112596000805160206140f083398151915261308c565b6127d681611c5c84610e82565b6000808460405160200180807f746f74616c5370656e74506572446179000000000000000000000000000000008152506010018281526020019150506040516020818303038152906040526040518082805190602001908083835b602083106128505780518252601f199092019160209182019101612831565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020939093555050505050565b60408051602481018690528415156044820152606480820184905282518083039091018152608490910190915260208181018051600160e060020a03167f9862f26f000000000000000000000000000000000000000000000000000000001781528251600093929184919082885af28060203d14166001811461291457600080fd5b50506000519695505050505050565b60008282111561292f57fe5b508082035b92915050565b6129426110e6565b1561294c57600080fd5b61295587612a32565b151561296057600080fd5b7fab54f3fbbe62c59b7876a9bf9bd5e0c22dbae93f4d8ee0438f7ce62b198eb0e0805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0389161790557fb120ceec05576ad0c710bc6e85f1768535e27554458f05dcbb5c65b8c7a749b06000908152602052437fe66bef0282a446f9848e2903380099bb6e431483ee78778868f33b4a154c818b556129fc866134b3565b612a05856133c6565b612a0e84613333565b612a1783613610565b612a20816136e5565b612a29826133dc565b50505050505050565b6000903b1190565b600081600080516020614110833981519152811480612a6657506000805160206140f083398151915281145b1515612a7157600080fd5b6000805160206141108339815191528314612aac577f286c406600000000000000000000000000000000000000000000000000000000612ace565b7f34a9e148000000000000000000000000000000000000000000000000000000005b6040805160248082018890528251808303909101815260449091018252602081018051600160e060020a03167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19851617815291518151939550600160a060020a038916939192909182919080838360005b83811015612b54578181015183820152602001612b3c565b50505050905090810190601f168015612b815780820380516001836020036101000a031916815260200191505b50915050600060405180830381855af49150501515612b9f57600080fd5b5050505050565b7f0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba60005260046020527f078d888f9b66f3f8bfa10909e31f1e16240db73449f0500afdbbe3a70da457cc805460ff19166001179055565b606890565b6000612c0c612bfd565b8251149050919050565b60008060008086516041141515612c2c57600080fd5b505050602084015160408501516060860151601b60ff60f860020a8304161480612c5f5750601c60ff60f860020a830416145b1515612c6a57600080fd5b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0821115612c9757600080fd5b6001612ca3878761374e565b60408051600080825260208083018085529490945260ff60f860020a870416828401526060820188905260808201879052915160a08083019493601f198301938390039091019190865af1158015612cff573d6000803e3d6000fd5b5050604051601f19015198975050505050505050565b80600360008460405160200180807f6d6573736167657300000000000000000000000000000000000000000000000081525060080182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310612d995780518252601f199092019160209182019101612d7a565b51815160001960209485036101000a01908116901991909116179052604080519490920184900390932086528583019690965250929093016000208451612de7959194509201919050614027565b505050565b80600460008460405160200180807f6d657373616765735369676e6564000000000000000000000000000000000000815250600e0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310612e705780518252601f199092019160209182019101612e51565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805460ff1916941515949094179093555050505050565b80600360008460405160200180807f7369676e61747572657300000000000000000000000000000000000000000000815250600a01826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310612d995780518252601f199092019160209182019101612d7a565b806000808460405160200180807f6e756d4d657373616765735369676e65640000000000000000000000000000008152506011018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106128505780518252601f199092019160209182019101612831565b7f80000000000000000000000000000000000000000000000000000000000000001790565b600080600080612ff66124e5565b9350600160a060020a03841615612b9f5761301085613968565b50935093505061303483600186600080516020614110833981519152600102612892565b9050612b9f8185846139a3565b80600160a060020a038116151561305757600080fd5b600160a060020a03831615156130755761307082613ab1565b612de7565b612de78383613abd565b8181018281101561293457fe5b600080806060846000805160206141108339815191528114806130bc57506000805160206140f083398151915281145b15156130c757600080fd5b6130cf6124e5565b9350600080516020614110833981519152861461310c577fffd661960000000000000000000000000000000000000000000000000000000061312e565b7f94da17cd000000000000000000000000000000000000000000000000000000005b60408051600481526024810190915260208082018051600160e060020a03167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19851617815282519396509194509160009182885af28060203d1416156131915760005195505b5050505050919050565b80600460008460405160200180807f61666669726d6174696f6e735369676e65640000000000000000000000000000815250601201826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310612e705780518252601f199092019160209182019101612e51565b806000808460405160200180807f6e756d41666669726d6174696f6e735369676e656400000000000000000000008152506015018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106128505780518252601f199092019160209182019101612831565b6000806000806132b76132b16111f8565b88613b70565b6132c087613bf6565b92506132ca6124e5565b9150600160a060020a03821615613316576132f6836000846000805160206140f0833981519152612892565b9050613303818388613c09565b613313838263ffffffff61292316565b92505b6133208884613d17565b506001979650505050505050565b600080fd5b6000811161334057600080fd5b7f916daedf6915000ff68ced2f0b6773fe6f2582237f92c3c95bb4d79407230071600090815260209081527fd2ea0feb732edb0ffe32efd33a6b9d24d46b16eb34a4d07ce256537b6f131e428290556040805183815290517f4fb76205cd57c896b21511d2114137d8e901b4ccd659e1a0f97d6306795264fb929181900390910190a150565b600081116133d357600080fd5b610e7f81613d78565b600160a060020a03811615156133f157600080fd5b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e061341a611d55565b60408051600160a060020a03928316815291841660208301528051918290030190a17f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c060005260026020527fb7802e97e87ef2842a6cce7da7ffaeaedaa2f61a6a7870b23d9d01fc9b73712e805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b604081015160001080156134ce575060408101516020820151115b80156134de575060208101518151115b15156134e957600080fd5b80517f4a6a899679f26b73530d8cf1001e83b6f7702e04b6fdb98f3c62dc7e47e041a5600090815260208181527f1ab29a5cca988aee50edccdd61c5bcaa7ad4b29a03b7ee50f298ceccfe14cc4e92909255908201517f0f8803acad17c63ee38bf2de71e1888bc7a079a6f73658e274b08018bea4e29c82527f9de0f81379b4d8e60fe509315d071b56e7b732abaf193e74e0d15808b0951d095560408201517fbbb088c505d18e049d114c7c91f11724e69c55ad6c5397e2b929e68b41fa05d182527f8df5c48c6b6e11d97548adc824ba0c99103ec09830fa5d53a179984085e6eaa0557fad4123ae17c414d9c6d2fec478b402e6b01856cc250fd01fbfd252fda0089d3c9082905b60200201516040518082815260200191505060405180910390a150565b805160208201511061362157600080fd5b80517f21dbcab260e413c20dc13c28b7db95e2b423d1135f42bb8b7d5214a92270d237600090815260208181527fadd938dbd083a16bae12238cd914fca0afc7a30edb55b1cd5c7f1823f1b0e42192909255908201517fc0ed44c192c86d1cc1ba51340b032c2766b4a2b0041031de13c46dd7104888d582527ff8e983ee86e5e377e9e34c9131b266382c3f04113d20de077f9e12663c7a646b557f9bebf928b90863f24cc31f726a3a7545efd409f1dcf552301b1ee3710da70d3b9082906135f3565b604c19811380156136f65750604d81125b151561370157600080fd5b7f1e8ecaafaddea96ed9ac6d2642dcdfe1bebe58a930b1085842d8fc122b371ee560009081526020527fd5c78dd9468716ca9bb96be25d56436811b20aab3523a9904b12deef1cab239d55565b60408051808201909152601a81527f19457468657265756d205369676e6564204d6573736167653a0a0000000000006020820152600090606083156138f457816137988651613dfe565b866040516020018084805190602001908083835b602083106137cb5780518252601f1990920191602091820191016137ac565b51815160209384036101000a600019018019909216911617905286519190930192860191508083835b602083106138135780518252601f1990920191602091820191016137f4565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b6020831061385b5780518252601f19909201916020918201910161383c565b6001836020036101000a03801982511681845116808217855250505050505090500193505050506040516020818303038152906040526040518082805190602001908083835b602083106138c05780518252601f1990920191602091820191016138a1565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209250613960565b6040805190810160405280600381526020017f31303400000000000000000000000000000000000000000000000000000000008152509050818186604051602001808480519060200190808383602083106137cb5780518252601f1990920191602091820191016137ac565b505092915050565b60008060008061397785612c02565b151561398257600080fd5b50505050601481015160348201516054830151606890930151919390929190565b6000831115612de7576040805160248082018690528251808303909101815260449091018252602081018051600160e060020a03167f59d784640000000000000000000000000000000000000000000000000000000017815291518151600160a060020a03861693829180838360005b83811015613a2b578181015183820152602001613a13565b50505050905090810190601f168015613a585780820380516001836020036101000a031916815260200191505b50915050600060405180830381855af49150501515613a7657600080fd5b60408051848152905182917f858abdcd5efcaebb936e8e8516f0cfe9a0ef5157ff99d16cdabb6db625be90d0919081900360200190a2505050565b3031611af58282613d17565b604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290518391600091600160a060020a038416916370a0823191602480830192602092919082900301818787803b158015613b2257600080fd5b505af1158015613b36573d6000803e3d6000fd5b505050506040513d6020811015613b4c57600080fd5b50519050613b6a600160a060020a038516848363ffffffff613f0916565b50505050565b613b7d81611c5c84611438565b6000808460405160200180807f746f74616c457865637574656450657244617900000000000000000000000000815250601301828152602001915050604051602081830303815290604052604051808280519060200190808383602083106128505780518252601f199092019160209182019101612831565b600061293482613c04612497565b613f9e565b6000831115612de7576040805160248082018690528251808303909101815260449091018252602081018051600160e060020a03167f054d46ec0000000000000000000000000000000000000000000000000000000017815291518151600160a060020a03861693829180838360005b83811015613c91578181015183820152602001613c79565b50505050905090810190601f168015613cbe5780820380516001836020036101000a031916815260200191505b50915050600060405180830381855af49150501515613cdc57600080fd5b60408051848152905182917fa52d3c9cbc541772e4edd92e2e4e2a3865ab73630f25deed8a6c8de41ff0f65c919081900360200190a2505050565b604051600160a060020a0383169082156108fc029083906000818181858888f193505050501515611af5578082613d4c6140a5565b600160a060020a039091168152604051908190036020019082f080158015612b9f573d6000803e3d6000fd5b7f55b3774520b5993024893d303890baa4e84b1244a43c60034d1ced2d3cf2b04b600090815260209081527ff7d5eefab3776d7f0450bd0193564bcb4f832ce313ff2836c450fc63a4b944198290556040805183815290517f52264b89e0fceafb26e79fd49ef8a366eb6297483bf4035b027f0c99a7ad512e929181900390910190a150565b60606000808281851515613e475760408051808201909152600181527f300000000000000000000000000000000000000000000000000000000000000060208201529450613f00565b8593505b8315613e6257600190920191600a84049350613e4b565b826040519080825280601f01601f191660200182016040528015613e90578160200160208202803883390190505b5091505060001982015b8515613efc57815160001982019160f860020a6030600a8a060102918491908110613ec157fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a86049550613e9a565b8194505b50505050919050565b82600160a060020a031663a9059cbb83836040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050600060405180830381600087803b158015613f6c57600080fd5b505af1158015613f80573d6000803e3d6000fd5b505050503d15612de75760206000803e6000511515612de757600080fd5b6000811515613fae575081612934565b6000821315613fd257613fcb83600a84900a63ffffffff613fe916565b9050612934565b611c88836000849003600a0a63ffffffff61401216565b6000821515613ffa57506000612934565b5081810281838281151561400a57fe5b041461293457fe5b6000818381151561401f57fe5b049392505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061406857805160ff1916838001178555614095565b82800160010185558215614095579182015b8281111561409557825182559160200191906001019061407a565b506140a19291506140b4565b5090565b6040516021806140cf83390190565b61113591905b808211156140a157600081556001016140ba5600608060405260405160208060218339810160405251600160a060020a038116ff00deb7f3adca07d6d1f708c1774389db532a2b2f18fd05a62b957e4089f4696ed589d93e5e92f7e37e490c25f0e50f7f4aad7cc94b308a566553280967be38bcf1a165627a7a72305820131d8c5c08c905b3331c5e776c883e7b020ebc54e495b3bf8d44e5cc1cb7ed900029