Skip to content

Instantly share code, notes, and snippets.

@habdelra
Created July 1, 2021 21:09
Show Gist options
  • Save habdelra/97d325aa04538d81b11a85fe809ea267 to your computer and use it in GitHub Desktop.
Save habdelra/97d325aa04538d81b11a85fe809ea267 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.4.24+commit.e67f0147.js&optimize=true&runs=10&gist=
REMIX EXAMPLE PROJECT
Remix example project is present when Remix loads very first time or there are no files existing in the File Explorer.
It contains 3 directories:
1. 'contracts': Holds three contracts with different complexity level, denoted with number prefix in file name.
2. 'scripts': Holds two scripts to deploy a contract. It is explained below.
3. 'tests': Contains one test file for 'Ballot' contract with unit tests in Solidity.
SCRIPTS
The 'scripts' folder contains example async/await scripts for deploying the 'Storage' contract.
For the deployment of any other contract, 'contractName' and 'constructorArgs' should be updated (along with other code if required).
Scripts have full access to the web3.js and ethers.js libraries.
To run a script, right click on file name in the file explorer and click 'Run'. Remember, Solidity file must already be compiled.
Output from script will appear in remix terminal.
pragma solidity 0.4.24;
import "openzeppelin-solidity/contracts/token/ERC20/BurnableToken.sol";
import "openzeppelin-solidity/contracts/token/ERC20/MintableToken.sol";
import "openzeppelin-solidity/contracts/token/ERC20/DetailedERC20.sol";
import "openzeppelin-solidity/contracts/AddressUtils.sol";
import "./interfaces/IBurnableMintableERC677Token.sol";
import "./upgradeable_contracts/Claimable.sol";
/**
* @title ERC677BridgeToken
* @dev The basic implementation of a bridgeable ERC677-compatible token
*/
contract ERC677BridgeToken is IBurnableMintableERC677Token, DetailedERC20, BurnableToken, MintableToken, Claimable {
bytes4 internal constant ON_TOKEN_TRANSFER = 0xa4c0ed36; // onTokenTransfer(address,uint256,bytes)
address internal bridgeContractAddr;
constructor(string _name, string _symbol, uint8 _decimals) public DetailedERC20(_name, _symbol, _decimals) {
// solhint-disable-previous-line no-empty-blocks
}
function bridgeContract() external view returns (address) {
return bridgeContractAddr;
}
function setBridgeContract(address _bridgeContract) external onlyOwner {
require(AddressUtils.isContract(_bridgeContract));
bridgeContractAddr = _bridgeContract;
}
modifier validRecipient(address _recipient) {
require(_recipient != address(0) && _recipient != address(this));
/* solcov ignore next */
_;
}
function transferAndCall(address _to, uint256 _value, bytes _data) external validRecipient(_to) returns (bool) {
require(superTransfer(_to, _value));
emit Transfer(msg.sender, _to, _value, _data);
if (AddressUtils.isContract(_to)) {
require(contractFallback(msg.sender, _to, _value, _data));
}
return true;
}
function getTokenInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) {
return (2, 4, 0);
}
function superTransfer(address _to, uint256 _value) internal returns (bool) {
return super.transfer(_to, _value);
}
function transfer(address _to, uint256 _value) public returns (bool) {
require(superTransfer(_to, _value));
callAfterTransfer(msg.sender, _to, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
require(super.transferFrom(_from, _to, _value));
callAfterTransfer(_from, _to, _value);
return true;
}
/**
* @dev Internal function that calls onTokenTransfer callback on the receiver after the successful transfer.
* Since it is not present in the original ERC677 standard, the callback is only called on the bridge contract,
* in order to simplify UX. In other cases, this token complies with the ERC677/ERC20 standard.
* @param _from tokens sender address.
* @param _to tokens receiver address.
* @param _value amount of sent tokens.
*/
function callAfterTransfer(address _from, address _to, uint256 _value) internal {
if (isBridge(_to)) {
require(contractFallback(_from, _to, _value, new bytes(0)));
}
}
function isBridge(address _address) public view returns (bool) {
return _address == bridgeContractAddr;
}
/**
* @dev call onTokenTransfer fallback on the token recipient contract
* @param _from tokens sender
* @param _to tokens recipient
* @param _value amount of tokens that was sent
* @param _data set of extra bytes that can be passed to the recipient
*/
function contractFallback(address _from, address _to, uint256 _value, bytes _data) private returns (bool) {
return _to.call(abi.encodeWithSelector(ON_TOKEN_TRANSFER, _from, _value, _data));
}
function finishMinting() public returns (bool) {
revert();
}
function renounceOwnership() public onlyOwner {
revert();
}
/**
* @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 onlyOwner {
claimValues(_token, _to);
}
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
return super.increaseApproval(spender, addedValue);
}
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
return super.decreaseApproval(spender, subtractedValue);
}
}
pragma solidity 0.4.24;
import "./ERC677MultiBridgeToken.sol";
contract ERC677BridgeTokenRewardable is ERC677MultiBridgeToken {
address public blockRewardContract;
address public stakingContract;
constructor(string _name, string _symbol, uint8 _decimals, uint256 _chainId)
public
ERC677MultiBridgeToken(_name, _symbol, _decimals, _chainId)
{
// solhint-disable-previous-line no-empty-blocks
}
/**
* @dev Updates the address of the used block reward contract.
* Only the token owner can call this method.
* Even though this function is inteded only for the initialization purpose,
* it is still possible to change the already used block reward contract.
* In this case users of the old contract won't lose their accumulated rewards,
* they can proceed with the withdrawal by calling the old block reward contract directly.
* @param _blockRewardContract address of the new block reward contract.
*/
function setBlockRewardContract(address _blockRewardContract) external onlyOwner {
require(AddressUtils.isContract(_blockRewardContract));
blockRewardContract = _blockRewardContract;
}
/**
* @dev Updates the address of the used staking contract.
* Only the token owner can call this method.
* Even though this function is inteded only for the initialization purpose,
* it is still possible to change the already used staking contract.
* In this case users of the old staking contract won't lose their tokens,
* they can proceed with the withdrawal by calling the old staking contract directly.
* @param _stakingContract address of the new staking contract.
*/
function setStakingContract(address _stakingContract) external onlyOwner {
require(AddressUtils.isContract(_stakingContract));
require(balanceOf(_stakingContract) == 0);
stakingContract = _stakingContract;
}
modifier onlyBlockRewardContract() {
require(msg.sender == blockRewardContract);
/* solcov ignore next */
_;
}
modifier onlyStakingContract() {
require(msg.sender == stakingContract);
/* solcov ignore next */
_;
}
function mintReward(uint256 _amount) external onlyBlockRewardContract {
if (_amount == 0) return;
// Mint `_amount` for the BlockReward contract
address to = blockRewardContract;
totalSupply_ = totalSupply_.add(_amount);
balances[to] = balances[to].add(_amount);
emit Mint(to, _amount);
emit Transfer(address(0), to, _amount);
}
function stake(address _staker, uint256 _amount) external onlyStakingContract {
// Transfer `_amount` from `_staker` to `stakingContract`
balances[_staker] = balances[_staker].sub(_amount);
balances[stakingContract] = balances[stakingContract].add(_amount);
emit Transfer(_staker, stakingContract, _amount);
}
function transfer(address _to, uint256 _value) public returns (bool) {
require(_to != blockRewardContract);
require(_to != stakingContract);
return super.transfer(_to, _value);
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
require(_to != blockRewardContract);
require(_to != stakingContract);
return super.transferFrom(_from, _to, _value);
}
}
pragma solidity 0.4.24;
import "./PermittableToken.sol";
/**
* @title ERC677MultiBridgeToken
* @dev This contract extends ERC677BridgeToken to support several bridge simulteniously
*/
contract ERC677MultiBridgeToken is PermittableToken {
address public constant F_ADDR = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF;
uint256 internal constant MAX_BRIDGES = 50;
mapping(address => address) public bridgePointers;
uint256 public bridgeCount;
event BridgeAdded(address indexed bridge);
event BridgeRemoved(address indexed bridge);
constructor(string _name, string _symbol, uint8 _decimals, uint256 _chainId)
public
PermittableToken(_name, _symbol, _decimals, _chainId)
{
bridgePointers[F_ADDR] = F_ADDR; // empty bridge contracts list
}
/**
* @dev Removes unused function from ERC677BridgeToken contract
*/
function setBridgeContract(address) external {
revert();
}
/**
* @dev Removes unused getter from ERC677BridgeToken contract
*/
function bridgeContract() external view returns (address) {
revert();
}
/**
* @dev Adds one more bridge contract into the list
* @param _bridge bridge contract address
*/
function addBridge(address _bridge) external onlyOwner {
require(bridgeCount < MAX_BRIDGES);
require(AddressUtils.isContract(_bridge));
require(!isBridge(_bridge));
address firstBridge = bridgePointers[F_ADDR];
require(firstBridge != address(0));
bridgePointers[F_ADDR] = _bridge;
bridgePointers[_bridge] = firstBridge;
bridgeCount = bridgeCount.add(1);
emit BridgeAdded(_bridge);
}
/**
* @dev Removes one existing bridge contract from the list
* @param _bridge bridge contract address
*/
function removeBridge(address _bridge) external onlyOwner {
require(isBridge(_bridge));
address nextBridge = bridgePointers[_bridge];
address index = F_ADDR;
address next = bridgePointers[index];
require(next != address(0));
while (next != _bridge) {
index = next;
next = bridgePointers[index];
require(next != F_ADDR && next != address(0));
}
bridgePointers[index] = nextBridge;
delete bridgePointers[_bridge];
bridgeCount = bridgeCount.sub(1);
emit BridgeRemoved(_bridge);
}
/**
* @dev Returns all recorded bridge contract addresses
* @return address[] bridge contract addresses
*/
function bridgeList() external view returns (address[]) {
address[] memory list = new address[](bridgeCount);
uint256 counter = 0;
address nextBridge = bridgePointers[F_ADDR];
require(nextBridge != address(0));
while (nextBridge != F_ADDR) {
list[counter] = nextBridge;
nextBridge = bridgePointers[nextBridge];
counter++;
require(nextBridge != address(0));
}
return list;
}
/**
* @dev Checks if given address is included into bridge contracts list
* @param _address bridge contract address
* @return bool true, if given address is a known bridge contract
*/
function isBridge(address _address) public view returns (bool) {
return _address != F_ADDR && bridgePointers[_address] != address(0);
}
}
pragma solidity 0.4.24;
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
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);
}
pragma solidity 0.4.24;
contract ERC677Receiver {
function onTokenTransfer(address _from, uint256 _value, bytes _data) external returns (bool);
}
pragma solidity 0.4.24;
interface IAMB {
function messageSender() external view returns (address);
function maxGasPerTx() external view returns (uint256);
function transactionHash() external view returns (bytes32);
function messageId() external view returns (bytes32);
function messageSourceChainId() external view returns (bytes32);
function messageCallStatus(bytes32 _messageId) external view returns (bool);
function failedMessageDataHash(bytes32 _messageId) external view returns (bytes32);
function failedMessageReceiver(bytes32 _messageId) external view returns (address);
function failedMessageSender(bytes32 _messageId) external view returns (address);
function requireToPassMessage(address _contract, bytes _data, uint256 _gas) external returns (bytes32);
function requireToConfirmMessage(address _contract, bytes _data, uint256 _gas) external returns (bytes32);
function sourceChainId() external view returns (uint256);
function destinationChainId() external view returns (uint256);
}
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);
}
pragma solidity 0.4.24;
interface IBridgeUtils {
function addToken(address _tokenAddr) external returns (bool);
function registerSupplier(address ownerAddr) external returns (address);
function isRegistered(address supplierAddr) public view returns (bool);
function safeForSupplier(address supplierAddr) public view returns (address);
}
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);
}
pragma solidity 0.4.24;
import "../interfaces/ERC677.sol";
contract IBurnableMintableERC677Token is ERC677 {
function mint(address _to, uint256 _amount) public returns (bool);
function burn(uint256 _value) public;
function claimTokens(address _token, address _to) external;
}
pragma solidity 0.4.24;
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "../interfaces/IPot.sol";
interface IChai {
function pot() external view returns (IPot);
function daiToken() external view returns (ERC20);
function balanceOf(address) external view returns (uint256);
function dai(address) external view returns (uint256);
function join(address, uint256) external;
function draw(address, uint256) external;
function exit(address, uint256) external;
function transfer(address, uint256) external;
}
pragma solidity 0.4.24;
interface IGasToken {
function balanceOf(address owner) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function mint(uint256 value) external;
}
pragma solidity 0.4.24;
interface IMediatorFeeManager {
function calculateFee(uint256) external view returns (uint256);
}
pragma solidity 0.4.24;
interface IMintHandler {
function mint(address _to, uint256 _amount) external returns (bool);
}
pragma solidity 0.4.24;
interface IPot {
function chi() external view returns (uint256);
function rho() external view returns (uint256);
function drip() external returns (uint256);
}
pragma solidity 0.4.24;
interface IRewardableValidators {
function isValidator(address _validator) external view returns (bool);
function requiredSignatures() external view returns (uint256);
function owner() external view returns (address);
function validatorList() external view returns (address[]);
function getValidatorRewardAddress(address _validator) external view returns (address);
function validatorCount() external view returns (uint256);
function getNextValidator(address _address) external view returns (address);
}
pragma solidity 0.4.24;
interface IUpgradeabilityOwnerStorage {
function upgradeabilityOwner() external view returns (address);
}
pragma solidity 0.4.24;
import "../upgradeable_contracts/Sacrifice.sol";
/**
* @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);
}
}
}
pragma solidity 0.4.24;
library ArbitraryMessage {
/**
* @dev Unpacks data fields from AMB message
* layout of message :: bytes:
* offset 0 : 32 bytes :: uint256 - message length
* offset 32 : 32 bytes :: bytes32 - messageId
* offset 64 : 20 bytes :: address - sender address
* offset 84 : 20 bytes :: address - executor contract
* offset 104 : 4 bytes :: uint32 - gasLimit
* offset 108 : 1 bytes :: uint8 - source chain id length (X)
* offset 109 : 1 bytes :: uint8 - destination chain id length (Y)
* offset 110 : 1 bytes :: uint8 - dataType
* offset 111 : X bytes :: bytes - source chain id
* offset 111 + X : Y bytes :: bytes - destination chain id
* NOTE: when message structure is changed, make sure that MESSAGE_PACKING_VERSION from VersionableAMB is updated as well
* NOTE: assembly code uses calldatacopy, make sure that message is passed as the first argument in the calldata
* @param _data encoded message
*/
function unpackData(bytes _data)
internal
pure
returns (
bytes32 messageId,
address sender,
address executor,
uint32 gasLimit,
uint8 dataType,
uint256[2] chainIds,
bytes memory data
)
{
// 32 (message id) + 20 (sender) + 20 (executor) + 4 (gasLimit) + 1 (source chain id length) + 1 (destination chain id length) + 1 (dataType)
uint256 srcdataptr = 32 + 20 + 20 + 4 + 1 + 1 + 1;
uint256 datasize;
assembly {
messageId := mload(add(_data, 32)) // 32 bytes
sender := and(mload(add(_data, 52)), 0xffffffffffffffffffffffffffffffffffffffff) // 20 bytes
// executor (20 bytes) + gasLimit (4 bytes) + srcChainIdLength (1 byte) + dstChainIdLength (1 bytes) + dataType (1 byte) + remainder (5 bytes)
let blob := mload(add(_data, 84))
// after bit shift left 12 bytes are zeros automatically
executor := shr(96, blob)
gasLimit := and(shr(64, blob), 0xffffffff)
dataType := byte(26, blob)
if gt(dataType, 0) {
// for now, only 0 datatype is supported - regular AMB calls
// other dataType values are kept reserved for future use
revert(0, 0)
}
// load source chain id length
let chainIdLength := byte(24, blob)
// at this moment srcdataptr points to sourceChainId
// mask for sourceChainId
// e.g. length X -> (1 << (X * 8)) - 1
let mask := sub(shl(shl(3, chainIdLength), 1), 1)
// increase payload offset by length of source chain id
srcdataptr := add(srcdataptr, chainIdLength)
// write sourceChainId
mstore(chainIds, and(mload(add(_data, srcdataptr)), mask))
// at this moment srcdataptr points to destinationChainId
// load destination chain id length
chainIdLength := byte(25, blob)
// mask for destinationChainId
// e.g. length X -> (1 << (X * 8)) - 1
mask := sub(shl(shl(3, chainIdLength), 1), 1)
// increase payload offset by length of destination chain id
srcdataptr := add(srcdataptr, chainIdLength)
// write destinationChainId
mstore(add(chainIds, 32), and(mload(add(_data, srcdataptr)), mask))
// at this moment srcdataptr points to payload
// datasize = message length - payload offset
datasize := sub(mload(_data), srcdataptr)
}
data = new bytes(datasize);
assembly {
// 36 = 4 (selector) + 32 (bytes length header)
srcdataptr := add(srcdataptr, 36)
// calldataload(4) - offset of first bytes argument in the calldata
calldatacopy(add(data, 32), add(calldataload(4), srcdataptr), datasize)
}
}
}
pragma solidity 0.4.24;
/**
* @title Bytes
* @dev Helper methods to transform bytes to other solidity types.
*/
library Bytes {
/**
* @dev Converts bytes array to bytes32.
* Truncates bytes array if its size is more than 32 bytes.
* NOTE: This function does not perform any checks on the received parameter.
* Make sure that the _bytes argument has a correct length, not less than 32 bytes.
* A case when _bytes has length less than 32 will lead to the undefined behaviour,
* since assembly will read data from memory that is not related to the _bytes argument.
* @param _bytes to be converted to bytes32 type
* @return bytes32 type of the firsts 32 bytes array in parameter.
*/
function bytesToBytes32(bytes _bytes) internal pure returns (bytes32 result) {
assembly {
result := mload(add(_bytes, 32))
}
}
/**
* @dev Truncate bytes array if its size is more than 20 bytes.
* NOTE: Similar to the bytesToBytes32 function, make sure that _bytes is not shorter than 20 bytes.
* @param _bytes to be converted to address type
* @return address included in the firsts 20 bytes of the bytes array in parameter.
*/
function bytesToAddress(bytes _bytes) internal pure returns (address addr) {
assembly {
addr := mload(add(_bytes, 20))
}
}
}
pragma solidity 0.4.24;
import "../interfaces/IBridgeValidators.sol";
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);
}
}
pragma solidity 0.4.24;
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "../interfaces/ERC677.sol";
/**
* @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)
}
}
}
}
}
pragma solidity 0.4.24;
/**
* @title TokenReader
* @dev Helper methods for reading name/symbol/decimals parameters from ERC20 token contracts.
*/
library TokenReader {
/**
* @dev Reads the name property of the provided token.
* Either name() or NAME() method is used.
* Both, string and bytes32 types are supported.
* @param _token address of the token contract.
* @return token name as a string or an empty string if none of the methods succeeded.
*/
function readName(address _token) internal view returns (string) {
uint256 ptr;
uint256 size;
assembly {
ptr := mload(0x40)
mstore(ptr, 0x06fdde0300000000000000000000000000000000000000000000000000000000) // name()
if iszero(staticcall(gas, _token, ptr, 4, ptr, 32)) {
mstore(ptr, 0xa3f4df7e00000000000000000000000000000000000000000000000000000000) // NAME()
staticcall(gas, _token, ptr, 4, ptr, 32)
pop
}
mstore(0x40, add(ptr, returndatasize))
switch gt(returndatasize, 32)
case 1 {
returndatacopy(mload(0x40), 32, 32) // string length
size := mload(mload(0x40))
}
default {
size := returndatasize // 32 or 0
}
}
string memory res = new string(size);
assembly {
if gt(returndatasize, 32) {
// load as string
returndatacopy(add(res, 32), 64, size)
jump(exit)
}
/* solhint-disable */
if gt(returndatasize, 0) {
let i := 0
ptr := mload(ptr) // load bytes32 value
mstore(add(res, 32), ptr) // save value in result string
for { } gt(ptr, 0) { i := add(i, 1) } { // until string is empty
ptr := shl(8, ptr) // shift left by one symbol
}
mstore(res, i) // save result string length
}
exit:
/* solhint-enable */
}
return res;
}
/**
* @dev Reads the symbol property of the provided token.
* Either symbol() or SYMBOL() method is used.
* Both, string and bytes32 types are supported.
* @param _token address of the token contract.
* @return token symbol as a string or an empty string if none of the methods succeeded.
*/
function readSymbol(address _token) internal view returns (string) {
uint256 ptr;
uint256 size;
assembly {
ptr := mload(0x40)
mstore(ptr, 0x95d89b4100000000000000000000000000000000000000000000000000000000) // symbol()
if iszero(staticcall(gas, _token, ptr, 4, ptr, 32)) {
mstore(ptr, 0xf76f8d7800000000000000000000000000000000000000000000000000000000) // SYMBOL()
staticcall(gas, _token, ptr, 4, ptr, 32)
pop
}
mstore(0x40, add(ptr, returndatasize))
switch gt(returndatasize, 32)
case 1 {
returndatacopy(mload(0x40), 32, 32) // string length
size := mload(mload(0x40))
}
default {
size := returndatasize // 32 or 0
}
}
string memory res = new string(size);
assembly {
if gt(returndatasize, 32) {
// load as string
returndatacopy(add(res, 32), 64, size)
jump(exit)
}
/* solhint-disable */
if gt(returndatasize, 0) {
let i := 0
ptr := mload(ptr) // load bytes32 value
mstore(add(res, 32), ptr) // save value in result string
for { } gt(ptr, 0) { i := add(i, 1) } { // until string is empty
ptr := shl(8, ptr) // shift left by one symbol
}
mstore(res, i) // save result string length
}
exit:
/* solhint-enable */
}
return res;
}
/**
* @dev Reads the decimals property of the provided token.
* Either decimals() or DECIMALS() method is used.
* @param _token address of the token contract.
* @return token decimals or 0 if none of the methods succeeded.
*/
function readDecimals(address _token) internal view returns (uint256) {
uint256 decimals;
assembly {
let ptr := mload(0x40)
mstore(0x40, add(ptr, 32))
mstore(ptr, 0x313ce56700000000000000000000000000000000000000000000000000000000) // decimals()
if iszero(staticcall(gas, _token, ptr, 4, ptr, 32)) {
mstore(ptr, 0x2e0f262500000000000000000000000000000000000000000000000000000000) // DECIMALS()
if iszero(staticcall(gas, _token, ptr, 4, ptr, 32)) {
mstore(ptr, 0)
}
}
decimals := mload(ptr)
}
return decimals;
}
}
pragma solidity 0.4.24;
contract Migrations {
address public owner;
// solhint-disable-next-line var-name-mixedcase
uint256 public last_completed_migration;
modifier restricted() {
if (msg.sender == owner) _;
}
constructor() public {
owner = msg.sender;
}
function setCompleted(uint256 completed) public restricted {
last_completed_migration = completed;
}
function upgrade(address new_address) public restricted {
Migrations upgraded = Migrations(new_address);
upgraded.setCompleted(last_completed_migration);
}
}
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;
}
pragma solidity 0.4.24;
import "./EternalStorage.sol";
import "./OwnedUpgradeabilityProxy.sol";
/**
* @title EternalStorageProxy
* @dev This proxy holds the storage of the token contract and delegates every call to the current implementation set.
* Besides, it allows to upgrade the token's behaviour towards further implementations, and provides basic
* authorization control functionalities
*/
// solhint-disable-next-line no-empty-blocks
contract EternalStorageProxy is EternalStorage, OwnedUpgradeabilityProxy {}
pragma solidity 0.4.24;
import "./UpgradeabilityProxy.sol";
import "./UpgradeabilityOwnerStorage.sol";
/**
* @title OwnedUpgradeabilityProxy
* @dev This contract combines an upgradeability proxy with basic authorization control functionalities
*/
contract OwnedUpgradeabilityProxy is UpgradeabilityOwnerStorage, UpgradeabilityProxy {
/**
* @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 ProxyOwnershipTransferred(address previousOwner, address newOwner);
/**
* @dev the constructor sets the original owner of the contract to the sender account.
*/
constructor() public {
setUpgradeabilityOwner(msg.sender);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyUpgradeabilityOwner() {
require(msg.sender == upgradeabilityOwner());
/* solcov ignore next */
_;
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferProxyOwnership(address newOwner) external onlyUpgradeabilityOwner {
require(newOwner != address(0));
emit ProxyOwnershipTransferred(upgradeabilityOwner(), newOwner);
setUpgradeabilityOwner(newOwner);
}
/**
* @dev Allows the upgradeability owner to upgrade the current version of the proxy.
* @param version representing the version name of the new implementation to be set.
* @param implementation representing the address of the new implementation to be set.
*/
function upgradeTo(uint256 version, address implementation) public onlyUpgradeabilityOwner {
_upgradeTo(version, implementation);
}
/**
* @dev Allows the upgradeability owner to upgrade the current version of the proxy and call the new implementation
* to initialize whatever is needed through a low level call.
* @param version representing the version name of the new implementation to be set.
* @param implementation representing the address of the new implementation to be set.
* @param data represents the msg.data to bet sent in the low level call. This parameter may include the function
* signature of the implementation to be called with the needed payload
*/
function upgradeToAndCall(uint256 version, address implementation, bytes data)
external
payable
onlyUpgradeabilityOwner
{
upgradeTo(version, implementation);
// solhint-disable-next-line avoid-call-value
require(address(this).call.value(msg.value)(data));
}
}
pragma solidity 0.4.24;
/**
* @title Proxy
* @dev Gives the possibility to delegate any call to a foreign implementation.
*/
contract Proxy {
/**
* @dev Tells the address of the implementation where every call will be delegated.
* @return address of the implementation to which it will be delegated
*/
/* solcov ignore next */
function implementation() public view returns (address);
/**
* @dev Fallback function allowing to perform a delegatecall to the given implementation.
* This function will return whatever the implementation call returns
*/
function() public payable {
// solhint-disable-previous-line no-complex-fallback
address _impl = implementation();
require(_impl != address(0));
assembly {
/*
0x40 is the "free memory slot", meaning a pointer to next slot of empty memory. mload(0x40)
loads the data in the free memory slot, so `ptr` is a pointer to the next slot of empty
memory. It's needed because we're going to write the return data of delegatecall to the
free memory slot.
*/
let ptr := mload(0x40)
/*
`calldatacopy` is copy calldatasize bytes from calldata
First argument is the destination to which data is copied(ptr)
Second argument specifies the start position of the copied data.
Since calldata is sort of its own unique location in memory,
0 doesn't refer to 0 in memory or 0 in storage - it just refers to the zeroth byte of calldata.
That's always going to be the zeroth byte of the function selector.
Third argument, calldatasize, specifies how much data will be copied.
calldata is naturally calldatasize bytes long (same thing as msg.data.length)
*/
calldatacopy(ptr, 0, calldatasize)
/*
delegatecall params explained:
gas: the amount of gas to provide for the call. `gas` is an Opcode that gives
us the amount of gas still available to execution
_impl: address of the contract to delegate to
ptr: to pass copied data
calldatasize: loads the size of `bytes memory data`, same as msg.data.length
0, 0: These are for the `out` and `outsize` params. Because the output could be dynamic,
these are set to 0, 0 so the output data will not be written to memory. The output
data will be read using `returndatasize` and `returdatacopy` instead.
result: This will be 0 if the call fails and 1 if it succeeds
*/
let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0)
/*
*/
/*
ptr current points to the value stored at 0x40,
because we assigned it like ptr := mload(0x40).
Because we use 0x40 as a free memory pointer,
we want to make sure that the next time we want to allocate memory,
we aren't overwriting anything important.
So, by adding ptr and returndatasize,
we get a memory location beyond the end of the data we will be copying to ptr.
We place this in at 0x40, and any reads from 0x40 will now read from free memory
*/
mstore(0x40, add(ptr, returndatasize))
/*
`returndatacopy` is an Opcode that copies the last return data to a slot. `ptr` is the
slot it will copy to, 0 means copy from the beginning of the return data, and size is
the amount of data to copy.
`returndatasize` is an Opcode that gives us the size of the last return data. In this case, that is the size of the data returned from delegatecall
*/
returndatacopy(ptr, 0, returndatasize)
/*
if `result` is 0, revert.
if `result` is 1, return `size` amount of data from `ptr`. This is the data that was
copied to `ptr` from the delegatecall return data
*/
switch result
case 0 {
revert(ptr, returndatasize)
}
default {
return(ptr, returndatasize)
}
}
}
}
pragma solidity 0.4.24;
/**
* @title UpgradeabilityOwnerStorage
* @dev This contract keeps track of the upgradeability owner
*/
contract UpgradeabilityOwnerStorage {
// Owner of the contract
address internal _upgradeabilityOwner;
/**
* @dev Tells the address of the owner
* @return the address of the owner
*/
function upgradeabilityOwner() public view returns (address) {
return _upgradeabilityOwner;
}
/**
* @dev Sets the address of the owner
*/
function setUpgradeabilityOwner(address newUpgradeabilityOwner) internal {
_upgradeabilityOwner = newUpgradeabilityOwner;
}
}
pragma solidity 0.4.24;
import "openzeppelin-solidity/contracts/AddressUtils.sol";
import "./Proxy.sol";
import "./UpgradeabilityStorage.sol";
/**
* @title UpgradeabilityProxy
* @dev This contract represents a proxy where the implementation address to which it will delegate can be upgraded
*/
contract UpgradeabilityProxy is Proxy, UpgradeabilityStorage {
/**
* @dev This event will be emitted every time the implementation gets upgraded
* @param version representing the version name of the upgraded implementation
* @param implementation representing the address of the upgraded implementation
*/
event Upgraded(uint256 version, address indexed implementation);
/**
* @dev Upgrades the implementation address
* @param version representing the version name of the new implementation to be set
* @param implementation representing the address of the new implementation to be set
*/
function _upgradeTo(uint256 version, address implementation) internal {
require(_implementation != implementation);
// This additional check verifies that provided implementation is at least a contract
require(AddressUtils.isContract(implementation));
// This additional check guarantees that new version will be at least greater than the privios one,
// so it is impossible to reuse old versions, or use the last version twice
require(version > _version);
_version = version;
_implementation = implementation;
emit Upgraded(version, implementation);
}
}
pragma solidity 0.4.24;
/**
* @title UpgradeabilityStorage
* @dev This contract holds all the necessary state variables to support the upgrade functionality
*/
contract UpgradeabilityStorage {
// Version name of the current implementation
uint256 internal _version;
// Address of the current implementation
address internal _implementation;
/**
* @dev Tells the version name of the current implementation
* @return uint256 representing the name of the current version
*/
function version() external view returns (uint256) {
return _version;
}
/**
* @dev Tells the address of the current implementation
* @return address of the current implementation
*/
function implementation() public view returns (address) {
return _implementation;
}
}
pragma solidity 0.4.24;
import "../BasicBridge.sol";
import "./VersionableAMB.sol";
contract BasicAMB is BasicBridge, VersionableAMB {
bytes32 internal constant MAX_GAS_PER_TX = 0x2670ecc91ec356e32067fd27b36614132d727b84a1e03e08f412a4f2cf075974; // keccak256(abi.encodePacked("maxGasPerTx"))
bytes32 internal constant NONCE = 0x7ab1577440dd7bedf920cb6de2f9fc6bf7ba98c78c85a3fa1f8311aac95e1759; // keccak256(abi.encodePacked("nonce"))
bytes32 internal constant SOURCE_CHAIN_ID = 0x67d6f42a1ed69c62022f2d160ddc6f2f0acd37ad1db0c24f4702d7d3343a4add; // keccak256(abi.encodePacked("sourceChainId"))
bytes32 internal constant SOURCE_CHAIN_ID_LENGTH = 0xe504ae1fd6471eea80f18b8532a61a9bb91fba4f5b837f80a1cfb6752350af44; // keccak256(abi.encodePacked("sourceChainIdLength"))
bytes32 internal constant DESTINATION_CHAIN_ID = 0xbbd454018e72a3f6c02bbd785bacc49e46292744f3f6761276723823aa332320; // keccak256(abi.encodePacked("destinationChainId"))
bytes32 internal constant DESTINATION_CHAIN_ID_LENGTH = 0xfb792ae4ad11102b93f26a51b3749c2b3667f8b561566a4806d4989692811594; // keccak256(abi.encodePacked("destinationChainIdLength"))
/**
* Initializes AMB contract
* @param _sourceChainId chain id of a network where this contract is deployed
* @param _destinationChainId chain id of a network where all outgoing messages are directed
* @param _validatorContract address of the validators contract
* @param _maxGasPerTx maximum amount of gas per one message execution
* @param _gasPrice default gas price used by oracles for sending transactions in this network
* @param _requiredBlockConfirmations number of block confirmations oracle will wait before processing passed messages
* @param _owner address of new bridge owner
*/
function initialize(
uint256 _sourceChainId,
uint256 _destinationChainId,
address _validatorContract,
uint256 _maxGasPerTx,
uint256 _gasPrice,
uint256 _requiredBlockConfirmations,
address _owner
) external onlyRelevantSender returns (bool) {
require(!isInitialized());
require(AddressUtils.isContract(_validatorContract));
_setChainIds(_sourceChainId, _destinationChainId);
addressStorage[VALIDATOR_CONTRACT] = _validatorContract;
uintStorage[DEPLOYED_AT_BLOCK] = block.number;
uintStorage[MAX_GAS_PER_TX] = _maxGasPerTx;
_setGasPrice(_gasPrice);
_setRequiredBlockConfirmations(_requiredBlockConfirmations);
_setOwner(_owner);
setInitialize();
return isInitialized();
}
function getBridgeMode() external pure returns (bytes4 _data) {
return 0x2544fbb9; // bytes4(keccak256(abi.encodePacked("arbitrary-message-bridge-core")))
}
function maxGasPerTx() public view returns (uint256) {
return uintStorage[MAX_GAS_PER_TX];
}
function setMaxGasPerTx(uint256 _maxGasPerTx) external onlyOwner {
uintStorage[MAX_GAS_PER_TX] = _maxGasPerTx;
}
/**
* Internal function for retrieving chain id for the source network
* @return chain id for the current network
*/
function sourceChainId() public view returns (uint256) {
return uintStorage[SOURCE_CHAIN_ID];
}
/**
* Internal function for retrieving chain id for the destination network
* @return chain id for the destination network
*/
function destinationChainId() public view returns (uint256) {
return uintStorage[DESTINATION_CHAIN_ID];
}
/**
* Updates chain ids of used networks
* @param _sourceChainId chain id for current network
* @param _destinationChainId chain id for opposite network
*/
function setChainIds(uint256 _sourceChainId, uint256 _destinationChainId) external onlyOwner {
_setChainIds(_sourceChainId, _destinationChainId);
}
/**
* Internal function for retrieving current nonce value
* @return nonce value
*/
function _nonce() internal view returns (uint64) {
return uint64(uintStorage[NONCE]);
}
/**
* Internal function for updating nonce value
* @param _nonce new nonce value
*/
function _setNonce(uint64 _nonce) internal {
uintStorage[NONCE] = uint256(_nonce);
}
/**
* Internal function for updating chain ids of used networks
* @param _sourceChainId chain id for current network
* @param _destinationChainId chain id for opposite network
*/
function _setChainIds(uint256 _sourceChainId, uint256 _destinationChainId) internal {
require(_sourceChainId > 0 && _destinationChainId > 0);
require(_sourceChainId != _destinationChainId);
// Length fields are needed further when encoding the message.
// Chain ids are compressed, so that leading zero bytes are not preserved.
// In order to save some gas during calls to MessageDelivery.c,
// lengths of chain ids are precalculated and being saved in the storage.
uint256 sourceChainIdLength = 0;
uint256 destinationChainIdLength = 0;
uint256 mask = 0xff;
for (uint256 i = 1; sourceChainIdLength == 0 || destinationChainIdLength == 0; i++) {
if (sourceChainIdLength == 0 && _sourceChainId & mask == _sourceChainId) {
sourceChainIdLength = i;
}
if (destinationChainIdLength == 0 && _destinationChainId & mask == _destinationChainId) {
destinationChainIdLength = i;
}
mask = (mask << 8) | 0xff;
}
uintStorage[SOURCE_CHAIN_ID] = _sourceChainId;
uintStorage[SOURCE_CHAIN_ID_LENGTH] = sourceChainIdLength;
uintStorage[DESTINATION_CHAIN_ID] = _destinationChainId;
uintStorage[DESTINATION_CHAIN_ID_LENGTH] = destinationChainIdLength;
}
/**
* Internal function for retrieving chain id length for the source network
* @return chain id for the current network
*/
function _sourceChainIdLength() internal view returns (uint256) {
return uintStorage[SOURCE_CHAIN_ID_LENGTH];
}
/**
* Internal function for retrieving chain id length for the destination network
* @return chain id for the destination network
*/
function _destinationChainIdLength() internal view returns (uint256) {
return uintStorage[DESTINATION_CHAIN_ID_LENGTH];
}
/**
* Internal function for validating version of the received message
* @param _messageId id of the received message
*/
function _isMessageVersionValid(bytes32 _messageId) internal returns (bool) {
return
_messageId & 0xffffffff00000000000000000000000000000000000000000000000000000000 == MESSAGE_PACKING_VERSION;
}
/**
* Internal function for validating destination chain id of the received message
* @param _chainId destination chain id of the received message
*/
function _isDestinationChainIdValid(uint256 _chainId) internal returns (bool res) {
return _chainId == sourceChainId();
}
}
pragma solidity 0.4.24;
import "../../libraries/Message.sol";
import "../../libraries/ArbitraryMessage.sol";
import "./BasicAMB.sol";
import "./MessageDelivery.sol";
import "../MessageRelay.sol";
contract BasicForeignAMB is BasicAMB, MessageRelay, MessageDelivery {
/**
* @dev Validates provided signatures and relays a given message
* @param _data bytes to be relayed
* @param _signatures bytes blob with signatures to be validated
*/
function executeSignatures(bytes _data, bytes _signatures) external {
// this checks prevents execution of other messages, while some other message is being processed
// nested executeSignatures is considered to be unsafe,
// since it allows to change/reset the AMB context variables (messageId, messageSender, messageSourceChainId)
// while processing nested message
require(messageId() == bytes32(0));
Message.hasEnoughValidSignatures(_data, _signatures, validatorContract(), true);
bytes32 msgId;
address sender;
address executor;
uint32 gasLimit;
uint8 dataType;
uint256[2] memory chainIds;
bytes memory data;
(msgId, sender, executor, gasLimit, dataType, chainIds, data) = ArbitraryMessage.unpackData(_data);
require(_isMessageVersionValid(msgId));
require(_isDestinationChainIdValid(chainIds[1]));
require(!relayedMessages(msgId));
setRelayedMessages(msgId, true);
processMessage(sender, executor, msgId, gasLimit, dataType, chainIds[0], data);
}
/**
* @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);
}
}
pragma solidity 0.4.24;
import "../../libraries/Message.sol";
import "../../libraries/ArbitraryMessage.sol";
import "./BasicAMB.sol";
import "./MessageDelivery.sol";
contract BasicHomeAMB is BasicAMB, MessageDelivery {
event SignedForUserRequest(address indexed signer, bytes32 messageHash);
event SignedForAffirmation(address indexed signer, bytes32 messageHash);
event CollectedSignatures(
address authorityResponsibleForRelay,
bytes32 messageHash,
uint256 NumberOfCollectedSignatures
);
uint256 internal constant SEND_TO_MANUAL_LANE = 0xf0;
function executeAffirmation(bytes message) external onlyValidator {
bytes32 hashMsg = keccak256(abi.encodePacked(message));
bytes32 hashSender = keccak256(abi.encodePacked(msg.sender, hashMsg));
// Duplicated affirmations
require(!affirmationsSigned(hashSender));
setAffirmationsSigned(hashSender, true);
uint256 signed = numAffirmationsSigned(hashMsg);
require(!isAlreadyProcessed(signed));
// the check above assumes that the case when the value could be overflew will not happen in the addition operation below
signed = signed + 1;
setNumAffirmationsSigned(hashMsg, signed);
emit SignedForAffirmation(msg.sender, hashMsg);
if (signed >= requiredSignatures()) {
setNumAffirmationsSigned(hashMsg, markAsProcessed(signed));
handleMessage(message);
}
}
/**
* @dev Requests message relay to the opposite network, message is sent to the manual lane.
* @param _contract executor address on the other side.
* @param _data calldata passed to the executor on the other side.
* @param _gas gas limit used on the other network for executing a message.
*/
function requireToConfirmMessage(address _contract, bytes _data, uint256 _gas) external returns (bytes32) {
return _sendMessage(_contract, _data, _gas, SEND_TO_MANUAL_LANE);
}
/**
* Parses given message, processes a call inside it
* @param _message relayed message
*/
function handleMessage(bytes _message) internal {
bytes32 messageId;
address sender;
address executor;
uint32 gasLimit;
uint8 dataType;
uint256[2] memory chainIds;
bytes memory data;
(messageId, sender, executor, gasLimit, dataType, chainIds, data) = ArbitraryMessage.unpackData(_message);
require(_isMessageVersionValid(messageId));
require(_isDestinationChainIdValid(chainIds[1]));
processMessage(sender, executor, messageId, gasLimit, dataType, chainIds[0], data);
}
function submitSignature(bytes signature, bytes message) external onlyValidator {
// ensure that `signature` is really `message` signed by `msg.sender`
require(msg.sender == Message.recoverAddressFromSignedMessage(signature, message, true));
bytes32 hashMsg = keccak256(abi.encodePacked(message));
bytes32 hashSender = keccak256(abi.encodePacked(msg.sender, hashMsg));
uint256 signed = numMessagesSigned(hashMsg);
require(!isAlreadyProcessed(signed));
// the check above assumes that the case when the value could be overflew
// will not happen in the addition operation below
signed = signed + 1;
if (signed > 1) {
// Duplicated signatures
require(!messagesSigned(hashSender));
} else {
setMessages(hashMsg, message);
}
setMessagesSigned(hashSender, true);
bytes32 signIdx = keccak256(abi.encodePacked(hashMsg, (signed.sub(1))));
setSignatures(signIdx, signature);
setNumMessagesSigned(hashMsg, signed);
emit SignedForUserRequest(msg.sender, hashMsg);
uint256 reqSigs = requiredSignatures();
if (signed >= reqSigs) {
setNumMessagesSigned(hashMsg, markAsProcessed(signed));
emit CollectedSignatures(msg.sender, hashMsg, reqSigs);
}
}
function isAlreadyProcessed(uint256 _number) public pure returns (bool) {
return _number & (2**255) == 2**255;
}
function numMessagesSigned(bytes32 _message) public view returns (uint256) {
return uintStorage[keccak256(abi.encodePacked("numMessagesSigned", _message))];
}
function signature(bytes32 _hash, uint256 _index) public view returns (bytes) {
bytes32 signIdx = keccak256(abi.encodePacked(_hash, _index));
return bytesStorage[keccak256(abi.encodePacked("signatures", signIdx))];
}
function messagesSigned(bytes32 _message) public view returns (bool) {
return boolStorage[keccak256(abi.encodePacked("messagesSigned", _message))];
}
function message(bytes32 _hash) public view returns (bytes) {
return messages(_hash);
}
function affirmationsSigned(bytes32 _hash) public view returns (bool) {
return boolStorage[keccak256(abi.encodePacked("affirmationsSigned", _hash))];
}
function numAffirmationsSigned(bytes32 _hash) public view returns (uint256) {
return uintStorage[keccak256(abi.encodePacked("numAffirmationsSigned", _hash))];
}
function setMessagesSigned(bytes32 _hash, bool _status) internal {
boolStorage[keccak256(abi.encodePacked("messagesSigned", _hash))] = _status;
}
function messages(bytes32 _hash) internal view returns (bytes) {
return bytesStorage[keccak256(abi.encodePacked("messages", _hash))];
}
function setSignatures(bytes32 _hash, bytes _signature) internal {
bytesStorage[keccak256(abi.encodePacked("signatures", _hash))] = _signature;
}
function setMessages(bytes32 _hash, bytes _message) internal {
bytesStorage[keccak256(abi.encodePacked("messages", _hash))] = _message;
}
function setNumMessagesSigned(bytes32 _message, uint256 _number) internal {
uintStorage[keccak256(abi.encodePacked("numMessagesSigned", _message))] = _number;
}
function markAsProcessed(uint256 _v) internal pure returns (uint256) {
return _v | (2**255);
}
function setAffirmationsSigned(bytes32 _hash, bool _status) internal {
boolStorage[keccak256(abi.encodePacked("affirmationsSigned", _hash))] = _status;
}
function setNumAffirmationsSigned(bytes32 _hash, uint256 _number) internal {
uintStorage[keccak256(abi.encodePacked("numAffirmationsSigned", _hash))] = _number;
}
}
pragma solidity 0.4.24;
import "./BasicForeignAMB.sol";
contract ForeignAMB is BasicForeignAMB {
event UserRequestForAffirmation(bytes32 indexed messageId, bytes encodedData);
event RelayedMessage(address indexed sender, address indexed executor, bytes32 indexed messageId, bool status);
function emitEventOnMessageRequest(bytes32 messageId, bytes encodedData) internal {
emit UserRequestForAffirmation(messageId, encodedData);
}
function emitEventOnMessageProcessed(address sender, address executor, bytes32 messageId, bool status) internal {
emit RelayedMessage(sender, executor, messageId, status);
}
}
pragma solidity 0.4.24;
import "./ForeignAMB.sol";
import "../GasTokenConnector.sol";
contract ForeignAMBWithGasToken is ForeignAMB, GasTokenConnector {
function requireToPassMessage(address _contract, bytes _data, uint256 _gas) public returns (bytes32 messageId) {
messageId = super.requireToPassMessage(_contract, _data, _gas);
_collectGasTokens();
}
}
pragma solidity 0.4.24;
import "./BasicHomeAMB.sol";
contract HomeAMB is BasicHomeAMB {
event UserRequestForSignature(bytes32 indexed messageId, bytes encodedData);
event AffirmationCompleted(
address indexed sender,
address indexed executor,
bytes32 indexed messageId,
bool status
);
function emitEventOnMessageRequest(bytes32 messageId, bytes encodedData) internal {
emit UserRequestForSignature(messageId, encodedData);
}
function emitEventOnMessageProcessed(address sender, address executor, bytes32 messageId, bool status) internal {
emit AffirmationCompleted(sender, executor, messageId, status);
}
}
pragma solidity 0.4.24;
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./BasicAMB.sol";
import "./MessageProcessor.sol";
import "../../libraries/ArbitraryMessage.sol";
import "../../libraries/Bytes.sol";
contract MessageDelivery is BasicAMB, MessageProcessor {
using SafeMath for uint256;
uint256 internal constant SEND_TO_ORACLE_DRIVEN_LANE = 0x00;
/**
* @dev Requests message relay to the opposite network
* @param _contract executor address on the other side
* @param _data calldata passed to the executor on the other side
* @param _gas gas limit used on the other network for executing a message
*/
function requireToPassMessage(address _contract, bytes _data, uint256 _gas) public returns (bytes32) {
return _sendMessage(_contract, _data, _gas, SEND_TO_ORACLE_DRIVEN_LANE);
}
/**
* @dev Initiates sending of an AMB message to the opposite network
* @param _contract executor address on the other side
* @param _data calldata passed to the executor on the other side
* @param _gas gas limit used on the other network for executing a message
* @param _dataType AMB message dataType to be included as a part of the header
*/
function _sendMessage(address _contract, bytes _data, uint256 _gas, uint256 _dataType) public returns (bytes32) {
// it is not allowed to pass messages while other messages are processed
require(messageId() == bytes32(0));
require(_gas >= getMinimumGasUsage(_data) && _gas <= maxGasPerTx());
bytes32 _messageId;
bytes memory header = _packHeader(_contract, _gas, _dataType);
_setNonce(_nonce() + 1);
assembly {
_messageId := mload(add(header, 32))
}
bytes memory eventData = abi.encodePacked(header, _data);
emitEventOnMessageRequest(_messageId, eventData);
return _messageId;
}
/**
* @dev Returns a lower limit on gas limit for the particular message data
* @param _data calldata passed to the executor on the other side
*/
function getMinimumGasUsage(bytes _data) public pure returns (uint256 gas) {
// From Ethereum Yellow Paper
// 68 gas is paid for every non-zero byte of data or code for a transaction
// Starting from Istanbul hardfork, 16 gas is paid (EIP-2028)
return _data.length.mul(16);
}
/**
* @dev Packs message header into a single bytes blob
* @param _contract executor address on the other side
* @param _gas gas limit used on the other network for executing a message
* @param _dataType AMB message dataType to be included as a part of the header
*/
function _packHeader(address _contract, uint256 _gas, uint256 _dataType)
internal
view
returns (bytes memory header)
{
uint256 srcChainId = sourceChainId();
uint256 srcChainIdLength = _sourceChainIdLength();
uint256 dstChainId = destinationChainId();
uint256 dstChainIdLength = _destinationChainIdLength();
bytes32 mVer = MESSAGE_PACKING_VERSION;
uint256 nonce = _nonce();
// Bridge id is recalculated every time again and again, since it is still cheaper than using SLOAD opcode (800 gas)
bytes32 bridgeId = keccak256(abi.encodePacked(srcChainId, address(this))) &
0x00000000ffffffffffffffffffffffffffffffffffffffff0000000000000000;
// 79 = 4 + 20 + 8 + 20 + 20 + 4 + 1 + 1 + 1
header = new bytes(79 + srcChainIdLength + dstChainIdLength);
// In order to save the gas, the header is packed in the reverse order.
// With such approach, it is possible to store right-aligned values without any additional bit shifts.
assembly {
let ptr := add(header, mload(header)) // points to the last word of header
mstore(ptr, dstChainId)
mstore(sub(ptr, dstChainIdLength), srcChainId)
mstore(add(header, 79), _dataType)
mstore(add(header, 78), dstChainIdLength)
mstore(add(header, 77), srcChainIdLength)
mstore(add(header, 76), _gas)
mstore(add(header, 72), _contract)
mstore(add(header, 52), caller)
mstore(add(header, 32), or(mVer, or(bridgeId, nonce)))
}
}
/* solcov ignore next */
function emitEventOnMessageRequest(bytes32 messageId, bytes encodedData) internal;
}
pragma solidity 0.4.24;
import "../../upgradeability/EternalStorage.sol";
import "../../libraries/Bytes.sol";
contract MessageProcessor is EternalStorage {
bytes32 internal constant MESSAGE_SENDER = 0x7b58b2a669d8e0992eae9eaef641092c0f686fd31070e7236865557fa1571b5b; // keccak256(abi.encodePacked("messageSender"))
bytes32 internal constant MESSAGE_ID = 0xe34bb2103dc34f2c144cc216c132d6ffb55dac57575c22e089161bbe65083304; // keccak256(abi.encodePacked("messageId"))
bytes32 internal constant MESSAGE_SOURCE_CHAIN_ID = 0x7f0fcd9e49860f055dd0c1682d635d309ecb5e3011654c716d9eb59a7ddec7d2; // keccak256(abi.encodePacked("messageSourceChainId"))
/**
* @dev Returns a status of the message that came from the other side.
* @param _messageId id of the message from the other side that triggered a call.
* @return true if call executed successfully.
*/
function messageCallStatus(bytes32 _messageId) external view returns (bool) {
return boolStorage[keccak256(abi.encodePacked("messageCallStatus", _messageId))];
}
/**
* @dev Sets a status of the message that came from the other side.
* @param _messageId id of the message from the other side that triggered a call.
* @param _status execution status, true if executed successfully.
*/
function setMessageCallStatus(bytes32 _messageId, bool _status) internal {
boolStorage[keccak256(abi.encodePacked("messageCallStatus", _messageId))] = _status;
}
/**
* @dev Returns a data hash of the failed message that came from the other side.
* NOTE: dataHash was used previously to identify outgoing message before AMB message id was introduced.
* It is kept for backwards compatibility with old mediators contracts.
* @param _messageId id of the message from the other side that triggered a call.
* @return keccak256 hash of message data.
*/
function failedMessageDataHash(bytes32 _messageId) external view returns (bytes32) {
return bytes32(uintStorage[keccak256(abi.encodePacked("failedMessageDataHash", _messageId))]);
}
/**
* @dev Sets a data hash of the failed message that came from the other side.
* NOTE: dataHash was used previously to identify outgoing message before AMB message id was introduced.
* It is kept for backwards compatibility with old mediators contracts.
* @param _messageId id of the message from the other side that triggered a call.
* @param data of the processed message.
*/
function setFailedMessageDataHash(bytes32 _messageId, bytes data) internal {
uintStorage[keccak256(abi.encodePacked("failedMessageDataHash", _messageId))] = uint256(keccak256(data));
}
/**
* @dev Returns a receiver address of the failed message that came from the other side.
* @param _messageId id of the message from the other side that triggered a call.
* @return receiver address.
*/
function failedMessageReceiver(bytes32 _messageId) external view returns (address) {
return addressStorage[keccak256(abi.encodePacked("failedMessageReceiver", _messageId))];
}
/**
* @dev Sets a sender address of the failed message that came from the other side.
* @param _messageId id of the message from the other side that triggered a call.
* @param _receiver address of the receiver.
*/
function setFailedMessageReceiver(bytes32 _messageId, address _receiver) internal {
addressStorage[keccak256(abi.encodePacked("failedMessageReceiver", _messageId))] = _receiver;
}
/**
* @dev Returns a sender address of the failed message that came from the other side.
* @param _messageId id of the message from the other side that triggered a call.
* @return sender address on the other side.
*/
function failedMessageSender(bytes32 _messageId) external view returns (address) {
return addressStorage[keccak256(abi.encodePacked("failedMessageSender", _messageId))];
}
/**
* @dev Sets a sender address of the failed message that came from the other side.
* @param _messageId id of the message from the other side that triggered a call.
* @param _sender address of the sender on the other side.
*/
function setFailedMessageSender(bytes32 _messageId, address _sender) internal {
addressStorage[keccak256(abi.encodePacked("failedMessageSender", _messageId))] = _sender;
}
/**
* @dev Returns an address of the sender on the other side for the currently processed message.
* Can be used by executors for getting other side caller address.
* @return address of the sender on the other side.
*/
function messageSender() external view returns (address) {
return addressStorage[MESSAGE_SENDER];
}
/**
* @dev Sets an address of the sender on the other side for the currently processed message.
* @param _sender address of the sender on the other side.
*/
function setMessageSender(address _sender) internal {
addressStorage[MESSAGE_SENDER] = _sender;
}
/**
* @dev Returns an id of the currently processed message.
* @return id of the message that originated on the other side.
*/
function messageId() public view returns (bytes32) {
return bytes32(uintStorage[MESSAGE_ID]);
}
/**
* @dev Returns an id of the currently processed message.
* NOTE: transactionHash was used previously to identify incoming message before AMB message id was introduced.
* It is kept for backwards compatibility with old mediators contracts, although it doesn't return txHash anymore.
* @return id of the message that originated on the other side.
*/
function transactionHash() external view returns (bytes32) {
return messageId();
}
/**
* @dev Sets a message id of the currently processed message.
* @param _messageId id of the message that originated on the other side.
*/
function setMessageId(bytes32 _messageId) internal {
uintStorage[MESSAGE_ID] = uint256(_messageId);
}
/**
* @dev Returns an originating chain id of the currently processed message.
* @return source chain id of the message that originated on the other side.
*/
function messageSourceChainId() external view returns (uint256) {
return uintStorage[MESSAGE_SOURCE_CHAIN_ID];
}
/**
* @dev Returns an originating chain id of the currently processed message.
* @return source chain id of the message that originated on the other side.
*/
function setMessageSourceChainId(uint256 _sourceChainId) internal returns (uint256) {
uintStorage[MESSAGE_SOURCE_CHAIN_ID] = _sourceChainId;
}
/**
* @dev Processes received message. Makes a call to the message executor,
* sets dataHash, receive, sender variables for failed messages.
* @param _sender sender address on the other side.
* @param _executor address of an executor.
* @param _messageId id of the processed message.
* @param _gasLimit gas limit for a call to executor.
* @param _sourceChainId source chain id is of the received message.
* @param _data calldata for a call to executor.
*/
function processMessage(
address _sender,
address _executor,
bytes32 _messageId,
uint256 _gasLimit,
uint8, /* dataType */
uint256 _sourceChainId,
bytes memory _data
) internal {
bool status = _passMessage(_sender, _executor, _data, _gasLimit, _messageId, _sourceChainId);
setMessageCallStatus(_messageId, status);
if (!status) {
setFailedMessageDataHash(_messageId, _data);
setFailedMessageReceiver(_messageId, _executor);
setFailedMessageSender(_messageId, _sender);
}
emitEventOnMessageProcessed(_sender, _executor, _messageId, status);
}
/**
* @dev Makes a call to the message executor.
* @param _sender sender address on the other side.
* @param _contract address of an executor contract.
* @param _data calldata for a call to executor.
* @param _gas gas limit for a call to executor.
* @param _messageId id of the processed message.
* @param _sourceChainId source chain id is of the received message.
*/
function _passMessage(
address _sender,
address _contract,
bytes _data,
uint256 _gas,
bytes32 _messageId,
uint256 _sourceChainId
) internal returns (bool) {
setMessageSender(_sender);
setMessageId(_messageId);
setMessageSourceChainId(_sourceChainId);
// After EIP-150, max gas cost allowed to be passed to the internal call is equal to the 63/64 of total gas left.
// In reallity, min(gasLimit, 63/64 * gasleft()) will be used as the call gas limit.
// Imagine a situation, when message requires 10000000 gas to be executed successfully.
// Also suppose, that at this point, gasleft() is equal to 10158000, so the callee will receive ~ 10158000 * 63 / 64 = 9999300 gas.
// That amount of gas is not enough, so the call will fail. At the same time,
// even if the callee failed the bridge contract still has ~ 158000 gas to
// finish its execution and it will be enough. The internal call fails but
// only because the oracle provides incorrect gas limit for the transaction
// This check is needed here in order to force contract to pass exactly the requested amount of gas.
// Avoiding it may leed to the unwanted message failure in some extreme cases.
require((gasleft() * 63) / 64 > _gas);
bool status = _contract.call.gas(_gas)(_data);
setMessageSender(address(0));
setMessageId(bytes32(0));
setMessageSourceChainId(0);
return status;
}
/* solcov ignore next */
function emitEventOnMessageProcessed(address sender, address executor, bytes32 messageId, bool status) internal;
}
pragma solidity 0.4.24;
import "../VersionableBridge.sol";
contract VersionableAMB is VersionableBridge {
// message format version as a single 4-bytes number padded to 32-bytes
// value, included into every outgoing relay request
//
// the message version should be updated every time when
// - new field appears
// - some field removed
// - fields order is changed
bytes32 internal constant MESSAGE_PACKING_VERSION = 0x00050000 << 224;
/**
* Returns currently used bridge version
* @return (major, minor, patch) version triple
*/
function getBridgeInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) {
return (5, 4, 0);
}
}
pragma solidity 0.4.24;
import "./Ownable.sol";
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./InitializableBridge.sol";
contract BaseBridgeValidators is InitializableBridge, Ownable {
using SafeMath for uint256;
address public constant F_ADDR = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF;
uint256 internal constant MAX_VALIDATORS = 50;
bytes32 internal constant REQUIRED_SIGNATURES = 0xd18ea17c351d6834a0e568067fb71804d2a588d5e26d60f792b1c724b1bd53b1; // keccak256(abi.encodePacked("requiredSignatures"))
bytes32 internal constant VALIDATOR_COUNT = 0x8656d603d9f985c3483946a92789d52202f49736384ba131cb92f62c4c1aa082; // keccak256(abi.encodePacked("validatorCount"))
event ValidatorAdded(address indexed validator);
event ValidatorRemoved(address indexed validator);
event RequiredSignaturesChanged(uint256 requiredSignatures);
function setRequiredSignatures(uint256 _requiredSignatures) external onlyOwner {
require(validatorCount() >= _requiredSignatures);
require(_requiredSignatures != 0);
uintStorage[REQUIRED_SIGNATURES] = _requiredSignatures;
emit RequiredSignaturesChanged(_requiredSignatures);
}
function getBridgeValidatorsInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) {
return (2, 3, 0);
}
function validatorList() external view returns (address[]) {
address[] memory list = new address[](validatorCount());
uint256 counter = 0;
address nextValidator = getNextValidator(F_ADDR);
require(nextValidator != address(0));
while (nextValidator != F_ADDR) {
list[counter] = nextValidator;
nextValidator = getNextValidator(nextValidator);
counter++;
require(nextValidator != address(0));
}
return list;
}
function _addValidator(address _validator) internal {
require(_validator != address(0) && _validator != F_ADDR);
require(!isValidator(_validator));
address firstValidator = getNextValidator(F_ADDR);
require(firstValidator != address(0));
setNextValidator(_validator, firstValidator);
setNextValidator(F_ADDR, _validator);
setValidatorCount(validatorCount().add(1));
}
function _removeValidator(address _validator) internal {
require(validatorCount() > requiredSignatures());
require(isValidator(_validator));
address validatorsNext = getNextValidator(_validator);
address index = F_ADDR;
address next = getNextValidator(index);
require(next != address(0));
while (next != _validator) {
index = next;
next = getNextValidator(index);
require(next != F_ADDR && next != address(0));
}
setNextValidator(index, validatorsNext);
deleteItemFromAddressStorage("validatorsList", _validator);
setValidatorCount(validatorCount().sub(1));
}
function requiredSignatures() public view returns (uint256) {
return uintStorage[REQUIRED_SIGNATURES];
}
function validatorCount() public view returns (uint256) {
return uintStorage[VALIDATOR_COUNT];
}
function isValidator(address _validator) public view returns (bool) {
return _validator != F_ADDR && getNextValidator(_validator) != address(0);
}
function getNextValidator(address _address) public view returns (address) {
return addressStorage[keccak256(abi.encodePacked("validatorsList", _address))];
}
function deleteItemFromAddressStorage(string _mapName, address _address) internal {
delete addressStorage[keccak256(abi.encodePacked(_mapName, _address))];
}
function setValidatorCount(uint256 _validatorCount) internal {
require(_validatorCount <= MAX_VALIDATORS);
uintStorage[VALIDATOR_COUNT] = _validatorCount;
}
function setNextValidator(address _prevValidator, address _validator) internal {
addressStorage[keccak256(abi.encodePacked("validatorsList", _prevValidator))] = _validator;
}
function isValidatorDuty(address _validator) external view returns (bool) {
uint256 counter = 0;
address next = getNextValidator(F_ADDR);
require(next != address(0));
while (next != F_ADDR) {
if (next == _validator) {
return (block.number % validatorCount() == counter);
}
next = getNextValidator(next);
counter++;
require(next != address(0));
}
return false;
}
}
pragma solidity 0.4.24;
import "openzeppelin-solidity/contracts/AddressUtils.sol";
import "./BasicTokenBridge.sol";
import "../interfaces/ERC677.sol";
import "../interfaces/ERC677Receiver.sol";
import "./ERC677Storage.sol";
import "./ChooseReceiverHelper.sol";
contract BaseERC677Bridge is BasicTokenBridge, ERC677Receiver, ERC677Storage, ChooseReceiverHelper {
function _erc677token() internal view returns (ERC677) {
return ERC677(addressStorage[ERC677_TOKEN]);
}
function setErc677token(address _token) internal {
require(AddressUtils.isContract(_token));
addressStorage[ERC677_TOKEN] = _token;
}
function onTokenTransfer(address _from, uint256 _value, bytes _data) external returns (bool) {
ERC677 token = _erc677token();
require(msg.sender == address(token));
require(withinLimit(_value));
addTotalSpentPerDay(getCurrentDay(), _value);
bridgeSpecificActionsOnTokenTransfer(token, _from, _value, _data);
return true;
}
/* solcov ignore next */
function bridgeSpecificActionsOnTokenTransfer(ERC677 _token, address _from, uint256 _value, bytes _data) internal;
}
pragma solidity 0.4.24;
import "../upgradeability/EternalStorage.sol";
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "../interfaces/IRewardableValidators.sol";
import "./FeeTypes.sol";
contract BaseFeeManager is EternalStorage, FeeTypes {
using SafeMath for uint256;
event HomeFeeUpdated(uint256 fee);
event ForeignFeeUpdated(uint256 fee);
// This is not a real fee value but a relative value used to calculate the fee percentage
uint256 internal constant MAX_FEE = 1 ether;
bytes32 internal constant HOME_FEE_STORAGE_KEY = 0xc3781f3cec62d28f56efe98358f59c2105504b194242dbcb2cc0806850c306e7; // keccak256(abi.encodePacked("homeFee"))
bytes32 internal constant FOREIGN_FEE_STORAGE_KEY = 0x68c305f6c823f4d2fa4140f9cf28d32a1faccf9b8081ff1c2de11cf32c733efc; // keccak256(abi.encodePacked("foreignFee"))
/**
* @dev Calculated the amount of fee for the particular bridge operation.
* @param _value bridged amount of tokens/coins for which fee amount is calculated.
* @param _recover true, if the fee was already subtracted from the given _value and needs to be restored.
* @param _feeType type of the fee, should be either HOME_FEE of FOREIGN_FEE.
* @return calculated fee amount.
*/
function calculateFee(uint256 _value, bool _recover, bytes32 _feeType)
public
view
validFeeType(_feeType)
returns (uint256)
{
uint256 fee = _feeType == HOME_FEE ? getHomeFee() : getForeignFee();
if (!_recover) {
return _value.mul(fee).div(MAX_FEE);
}
return _value.mul(fee).div(MAX_FEE.sub(fee));
}
modifier validFee(uint256 _fee) {
require(_fee < MAX_FEE);
/* solcov ignore next */
_;
}
function setHomeFee(uint256 _fee) external validFee(_fee) {
uintStorage[HOME_FEE_STORAGE_KEY] = _fee;
emit HomeFeeUpdated(_fee);
}
function getHomeFee() public view returns (uint256) {
return uintStorage[HOME_FEE_STORAGE_KEY];
}
function setForeignFee(uint256 _fee) external validFee(_fee) {
uintStorage[FOREIGN_FEE_STORAGE_KEY] = _fee;
emit ForeignFeeUpdated(_fee);
}
function getForeignFee() public view returns (uint256) {
return uintStorage[FOREIGN_FEE_STORAGE_KEY];
}
/* solcov ignore next */
function distributeFeeFromAffirmation(uint256 _fee) external;
/* solcov ignore next */
function distributeFeeFromSignatures(uint256 _fee) external;
/* solcov ignore next */
function getFeeManagerMode() external pure returns (bytes4);
function random(uint256 _count) internal view returns (uint256) {
return uint256(blockhash(block.number.sub(1))) % _count;
}
}
pragma solidity 0.4.24;
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "openzeppelin-solidity/contracts/AddressUtils.sol";
/**
* @title BaseMediatorFeeManager
* @dev Base fee manager to handle fees for AMB mediators.
*/
contract BaseMediatorFeeManager is Ownable {
using SafeMath for uint256;
event FeeUpdated(uint256 fee);
// This is not a real fee value but a relative value used to calculate the fee percentage.
// 1 ether = 100% of the value.
uint256 internal constant MAX_FEE = 1 ether;
uint256 internal constant MAX_REWARD_ACCOUNTS = 50;
uint256 public fee;
address[] internal rewardAccounts;
address internal mediatorContract;
modifier validFee(uint256 _fee) {
require(_fee < MAX_FEE);
/* solcov ignore next */
_;
}
/**
* @dev Stores the initial parameters of the fee manager.
* @param _owner address of the owner of the fee manager contract.
* @param _fee the fee percentage amount.
* @param _rewardAccountList list of unique addresses that will receive the fee rewards.
* @param _mediatorContract address of the mediator contract used together with this fee manager.
*/
constructor(address _owner, uint256 _fee, address[] _rewardAccountList, address _mediatorContract) public {
require(AddressUtils.isContract(_mediatorContract));
require(_rewardAccountList.length > 0 && _rewardAccountList.length <= MAX_REWARD_ACCOUNTS);
_transferOwnership(_owner);
_setFee(_fee);
mediatorContract = _mediatorContract;
for (uint256 i = 0; i < _rewardAccountList.length; i++) {
require(isValidAccount(_rewardAccountList[i]));
}
rewardAccounts = _rewardAccountList;
}
/**
* @dev Calculates the fee amount to be subtracted from the value.
* @param _value the base value from which fees are calculated
*/
function calculateFee(uint256 _value) external view returns (uint256) {
return _value.mul(fee).div(MAX_FEE);
}
/**
* @dev Stores the fee percentage amount for the mediator operations.
* @param _fee the fee percentage
*/
function _setFee(uint256 _fee) internal validFee(_fee) {
fee = _fee;
emit FeeUpdated(_fee);
}
/**
* @dev Sets the fee percentage amount for the mediator operations. Only the owner can call this method.
* @param _fee the fee percentage
*/
function setFee(uint256 _fee) external onlyOwner {
_setFee(_fee);
}
function isValidAccount(address _account) internal returns (bool) {
return _account != address(0) && _account != mediatorContract;
}
/**
* @dev Adds a new account to the list of accounts to receive rewards for the operations.
* Only the owner can call this method.
* @param _account new reward account
*/
function addRewardAccount(address _account) external onlyOwner {
require(isValidAccount(_account));
require(!isRewardAccount(_account));
require(rewardAccounts.length < MAX_REWARD_ACCOUNTS);
rewardAccounts.push(_account);
}
/**
* @dev Removes an account from the list of accounts to receive rewards for the operations.
* Only the owner can call this method.
* finds the element, swaps it with the last element, and then deletes it;
* @param _account to be removed
* return boolean whether the element was found and deleted
*/
function removeRewardAccount(address _account) external onlyOwner returns (bool) {
uint256 numOfAccounts = rewardAccountsCount();
for (uint256 i = 0; i < numOfAccounts; i++) {
if (rewardAccounts[i] == _account) {
rewardAccounts[i] = rewardAccounts[numOfAccounts - 1];
delete rewardAccounts[numOfAccounts - 1];
rewardAccounts.length--;
return true;
}
}
// If account is not found and removed, the transactions is reverted
revert();
}
/**
* @dev Tells the amount of accounts in the list of reward accounts.
* @return amount of accounts.
*/
function rewardAccountsCount() public view returns (uint256) {
return rewardAccounts.length;
}
/**
* @dev Tells if the account is part of the list of reward accounts.
* @param _account to check if is part of the list.
* @return true if the account is in the list
*/
function isRewardAccount(address _account) internal view returns (bool) {
for (uint256 i = 0; i < rewardAccountsCount(); i++) {
if (rewardAccounts[i] == _account) {
return true;
}
}
return false;
}
/**
* @dev Tells the list of accounts that receives rewards for the operations.
* @return the list of reward accounts
*/
function rewardAccountsList() public view returns (address[]) {
return rewardAccounts;
}
/**
* @dev ERC677 transfer callback function, received fee is distributed.
* @param _value amount of transferred tokens
*/
function onTokenTransfer(address, uint256 _value, bytes) external returns (bool) {
distributeFee(_value);
return true;
}
/**
* @dev Distributes the provided amount of fees proportionally to the list of reward accounts.
* In case the fees cannot be equally distributed, the remaining difference will be distributed to an account
* in a semi-random way.
* @param _fee total amount to be distributed to the list of reward accounts.
*/
function distributeFee(uint256 _fee) internal {
uint256 numOfAccounts = rewardAccountsCount();
if (numOfAccounts == 0) {
// In case there are no reward accounts defined, no actual fee distribution will happen.
// Funds will be kept locked on the contract until some of the reward accounts will be added.
// After it, locked funds ca be distributed by a call to onTokenTransfer() of this contract, which can be done by anyone.
return;
}
uint256 feePerAccount = _fee.div(numOfAccounts);
uint256 randomAccountIndex;
uint256 diff = _fee.sub(feePerAccount.mul(numOfAccounts));
if (diff > 0) {
randomAccountIndex = random(numOfAccounts);
}
for (uint256 i = 0; i < numOfAccounts; i++) {
uint256 feeToDistribute = feePerAccount;
if (diff > 0 && randomAccountIndex == i) {
feeToDistribute = feeToDistribute.add(diff);
}
onFeeDistribution(rewardAccounts[i], feeToDistribute);
}
}
/**
* @dev Calculates a random number based on the block number.
* @param _count the max value for the random number.
* @return a number between 0 and _count.
*/
function random(uint256 _count) internal view returns (uint256) {
return uint256(blockhash(block.number.sub(1))) % _count;
}
/* solcov ignore next */
function onFeeDistribution(address _rewardAddress, uint256 _fee) internal;
}
pragma solidity 0.4.24;
import "../upgradeability/EternalStorage.sol";
/**
* @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;
}
pragma solidity 0.4.24;
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "../upgradeability/EternalStorage.sol";
/**
* @title BaseRewardAddressList
* @dev Implements the logic to store, add and remove reward account addresses. Works as a linked list.
*/
contract BaseRewardAddressList is EternalStorage {
using SafeMath for uint256;
address public constant F_ADDR = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF;
uint256 internal constant MAX_REWARD_ADDRESSES = 50;
bytes32 internal constant REWARD_ADDRESS_COUNT = 0xabc77c82721ced73eef2645facebe8c30249e6ac372cce6eb9d1fed31bd6648f; // keccak256(abi.encodePacked("rewardAddressCount"))
event RewardAddressAdded(address indexed addr);
event RewardAddressRemoved(address indexed addr);
/**
* @dev Retrieves all registered reward accounts.
* @return address list of the registered reward receivers.
*/
function rewardAddressList() external view returns (address[]) {
address[] memory list = new address[](rewardAddressCount());
uint256 counter = 0;
address nextAddr = getNextRewardAddress(F_ADDR);
while (nextAddr != F_ADDR) {
require(nextAddr != address(0));
list[counter] = nextAddr;
nextAddr = getNextRewardAddress(nextAddr);
counter++;
}
return list;
}
/**
* @dev Retrieves amount of registered reward accounts.
* @return length of reward addresses list.
*/
function rewardAddressCount() public view returns (uint256) {
return uintStorage[REWARD_ADDRESS_COUNT];
}
/**
* @dev Checks if specified address is included into the registered rewards receivers list.
* @param _addr address to verify.
* @return true, if specified address is associated with one of the registered reward accounts.
*/
function isRewardAddress(address _addr) public view returns (bool) {
return _addr != F_ADDR && getNextRewardAddress(_addr) != address(0);
}
/**
* @dev Retrieves next reward address in the linked list, or F_ADDR if given address is the last one.
* @param _address address of some reward account.
* @return address of the next reward receiver.
*/
function getNextRewardAddress(address _address) public view returns (address) {
return addressStorage[keccak256(abi.encodePacked("rewardAddressList", _address))];
}
/**
* @dev Internal function for adding a new reward address to the linked list.
* @param _addr new reward account.
*/
function _addRewardAddress(address _addr) internal {
require(_addr != address(0) && _addr != F_ADDR);
require(!isRewardAddress(_addr));
address nextAddr = getNextRewardAddress(F_ADDR);
require(nextAddr != address(0));
_setNextRewardAddress(_addr, nextAddr);
_setNextRewardAddress(F_ADDR, _addr);
_setRewardAddressCount(rewardAddressCount().add(1));
}
/**
* @dev Internal function for removing existing reward address from the linked list.
* @param _addr old reward account which should be removed.
*/
function _removeRewardAddress(address _addr) internal {
require(isRewardAddress(_addr));
address nextAddr = getNextRewardAddress(_addr);
address index = F_ADDR;
address next = getNextRewardAddress(index);
while (next != _addr) {
require(next != address(0));
index = next;
next = getNextRewardAddress(index);
require(next != F_ADDR);
}
_setNextRewardAddress(index, nextAddr);
delete addressStorage[keccak256(abi.encodePacked("rewardAddressList", _addr))];
_setRewardAddressCount(rewardAddressCount().sub(1));
}
/**
* @dev Internal function for initializing linked list with the array of the initial reward addresses.
* @param _rewardAddresses initial reward addresses list, should be non-empty.
*/
function _setRewardAddressList(address[] _rewardAddresses) internal {
require(_rewardAddresses.length > 0);
_setNextRewardAddress(F_ADDR, _rewardAddresses[0]);
for (uint256 i = 0; i < _rewardAddresses.length; i++) {
require(_rewardAddresses[i] != address(0) && _rewardAddresses[i] != F_ADDR);
require(!isRewardAddress(_rewardAddresses[i]));
if (i == _rewardAddresses.length - 1) {
_setNextRewardAddress(_rewardAddresses[i], F_ADDR);
} else {
_setNextRewardAddress(_rewardAddresses[i], _rewardAddresses[i + 1]);
}
emit RewardAddressAdded(_rewardAddresses[i]);
}
_setRewardAddressCount(_rewardAddresses.length);
}
/**
* @dev Internal function for updating the length of the reward accounts list.
* @param _rewardAddressCount new linked list length.
*/
function _setRewardAddressCount(uint256 _rewardAddressCount) internal {
require(_rewardAddressCount <= MAX_REWARD_ADDRESSES);
uintStorage[REWARD_ADDRESS_COUNT] = _rewardAddressCount;
}
/**
* @dev Internal function for updating the pointer to the next reward receiver.
* @param _prevAddr address of some reward receiver.
* @param _addr address of the next receiver to which _prevAddr should point to.
*/
function _setNextRewardAddress(address _prevAddr, address _addr) internal {
addressStorage[keccak256(abi.encodePacked("rewardAddressList", _prevAddr))] = _addr;
}
}
pragma solidity 0.4.24;
import "./Ownable.sol";
import "../interfaces/IAMB.sol";
import "../libraries/Bytes.sol";
import "openzeppelin-solidity/contracts/AddressUtils.sol";
/**
* @title BasicAMBMediator
* @dev Basic storage and methods needed by mediators to interact with AMB bridge.
*/
contract BasicAMBMediator is Ownable {
bytes32 internal constant BRIDGE_CONTRACT = 0x811bbb11e8899da471f0e69a3ed55090fc90215227fc5fb1cb0d6e962ea7b74f; // keccak256(abi.encodePacked("bridgeContract"))
bytes32 internal constant MEDIATOR_CONTRACT = 0x98aa806e31e94a687a31c65769cb99670064dd7f5a87526da075c5fb4eab9880; // keccak256(abi.encodePacked("mediatorContract"))
bytes32 internal constant REQUEST_GAS_LIMIT = 0x2dfd6c9f781bb6bbb5369c114e949b69ebb440ef3d4dd6b2836225eb1dc3a2be; // keccak256(abi.encodePacked("requestGasLimit"))
/**
* @dev Throws if caller on the other side is not an associated mediator.
*/
modifier onlyMediator {
require(msg.sender == address(bridgeContract()));
require(messageSender() == mediatorContractOnOtherSide());
_;
}
/**
* @dev Sets the AMB bridge contract address. Only the owner can call this method.
* @param _bridgeContract the address of the bridge contract.
*/
function setBridgeContract(address _bridgeContract) external onlyOwner {
_setBridgeContract(_bridgeContract);
}
/**
* @dev Sets the mediator contract address from the other network. Only the owner can call this method.
* @param _mediatorContract the address of the mediator contract.
*/
function setMediatorContractOnOtherSide(address _mediatorContract) external onlyOwner {
_setMediatorContractOnOtherSide(_mediatorContract);
}
/**
* @dev Sets the gas limit to be used in the message execution by the AMB bridge on the other network.
* This value can't exceed the parameter maxGasPerTx defined on the AMB bridge.
* Only the owner can call this method.
* @param _requestGasLimit the gas limit for the message execution.
*/
function setRequestGasLimit(uint256 _requestGasLimit) external onlyOwner {
_setRequestGasLimit(_requestGasLimit);
}
/**
* @dev Get the AMB interface for the bridge contract address
* @return AMB interface for the bridge contract address
*/
function bridgeContract() public view returns (IAMB) {
return IAMB(addressStorage[BRIDGE_CONTRACT]);
}
/**
* @dev Tells the mediator contract address from the other network.
* @return the address of the mediator contract.
*/
function mediatorContractOnOtherSide() public view returns (address) {
return addressStorage[MEDIATOR_CONTRACT];
}
/**
* @dev Tells the gas limit to be used in the message execution by the AMB bridge on the other network.
* @return the gas limit for the message execution.
*/
function requestGasLimit() public view returns (uint256) {
return uintStorage[REQUEST_GAS_LIMIT];
}
/**
* @dev Stores a valid AMB bridge contract address.
* @param _bridgeContract the address of the bridge contract.
*/
function _setBridgeContract(address _bridgeContract) internal {
require(AddressUtils.isContract(_bridgeContract));
addressStorage[BRIDGE_CONTRACT] = _bridgeContract;
}
/**
* @dev Stores the mediator contract address from the other network.
* @param _mediatorContract the address of the mediator contract.
*/
function _setMediatorContractOnOtherSide(address _mediatorContract) internal {
addressStorage[MEDIATOR_CONTRACT] = _mediatorContract;
}
/**
* @dev Stores the gas limit to be used in the message execution by the AMB bridge on the other network.
* @param _requestGasLimit the gas limit for the message execution.
*/
function _setRequestGasLimit(uint256 _requestGasLimit) internal {
require(_requestGasLimit <= maxGasPerTx());
uintStorage[REQUEST_GAS_LIMIT] = _requestGasLimit;
}
/**
* @dev Tells the address that generated the message on the other network that is currently being executed by
* the AMB bridge.
* @return the address of the message sender.
*/
function messageSender() internal view returns (address) {
return bridgeContract().messageSender();
}
/**
* @dev Tells the id of the message originated on the other network.
* @return the id of the message originated on the other network.
*/
function messageId() internal view returns (bytes32) {
return bridgeContract().messageId();
}
/**
* @dev Tells the maximum gas limit that a message can use on its execution by the AMB bridge on the other network.
* @return the maximum gas limit value.
*/
function maxGasPerTx() internal view returns (uint256) {
return bridgeContract().maxGasPerTx();
}
}
pragma solidity 0.4.24;
import "./Upgradeable.sol";
import "./InitializableBridge.sol";
import "openzeppelin-solidity/contracts/AddressUtils.sol";
import "./Validatable.sol";
import "./Ownable.sol";
import "./Claimable.sol";
import "./VersionableBridge.sol";
import "./DecimalShiftBridge.sol";
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);
}
}
pragma solidity 0.4.24;
import "../upgradeability/EternalStorage.sol";
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "./Validatable.sol";
import "../libraries/Message.sol";
import "./MessageRelay.sol";
import "./BasicBridge.sol";
import "./BasicTokenBridge.sol";
import "./MessageRelay.sol";
contract BasicForeignBridge is EternalStorage, Validatable, BasicBridge, BasicTokenBridge, MessageRelay {
/// triggered when relay of deposit from HomeBridge is complete
event RelayedMessage(address recipient, uint256 value, bytes32 transactionHash);
event UserRequestForAffirmation(address recipient, uint256 value);
/**
* @dev Validates provided signatures and relays a given message
* @param message bytes to be relayed
* @param signatures bytes blob with signatures to be validated
*/
function executeSignatures(bytes message, bytes signatures) external {
Message.hasEnoughValidSignatures(message, signatures, validatorContract(), false);
address recipient;
uint256 amount;
bytes32 txHash;
address contractAddress;
(recipient, amount, txHash, contractAddress) = Message.parseMessage(message);
if (withinExecutionLimit(amount)) {
require(contractAddress == address(this));
require(!relayedMessages(txHash));
setRelayedMessages(txHash, true);
require(onExecuteMessage(recipient, amount, txHash));
emit RelayedMessage(recipient, amount, txHash);
} else {
onFailedMessage(recipient, amount, txHash);
}
}
/**
* @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);
}
/* solcov ignore next */
function onExecuteMessage(address, uint256, bytes32) internal returns (bool);
/* solcov ignore next */
function onFailedMessage(address, uint256, bytes32) internal;
}
pragma solidity 0.4.24;
import "../upgradeability/EternalStorage.sol";
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "./Validatable.sol";
import "../libraries/Message.sol";
import "./BasicBridge.sol";
import "./BasicTokenBridge.sol";
/**
* @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();
}
}
pragma solidity 0.4.24;
import "../interfaces/IBlockReward.sol";
import "../upgradeability/EternalStorage.sol";
import "openzeppelin-solidity/contracts/AddressUtils.sol";
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;
}
}
pragma solidity 0.4.24;
import "./BaseFeeManager.sol";
import "./BlockRewardBridge.sol";
contract BlockRewardFeeManager is BaseFeeManager, BlockRewardBridge {
function distributeFeeFromAffirmation(uint256 _fee) external {
distributeFeeFromBlockReward(_fee);
}
function distributeFeeFromSignatures(uint256 _fee) external {
distributeFeeFromBlockReward(_fee);
}
/* solcov ignore next */
function distributeFeeFromBlockReward(uint256 _fee) internal;
}
pragma solidity 0.4.24;
import "./BaseBridgeValidators.sol";
contract BridgeValidators is BaseBridgeValidators {
function initialize(uint256 _requiredSignatures, address[] _initialValidators, address _owner)
external
onlyRelevantSender
returns (bool)
{
require(!isInitialized());
_setOwner(_owner);
require(_requiredSignatures != 0);
require(_initialValidators.length >= _requiredSignatures);
for (uint256 i = 0; i < _initialValidators.length; i++) {
require(_initialValidators[i] != address(0) && _initialValidators[i] != F_ADDR);
require(!isValidator(_initialValidators[i]));
if (i == 0) {
setNextValidator(F_ADDR, _initialValidators[i]);
if (_initialValidators.length == 1) {
setNextValidator(_initialValidators[i], F_ADDR);
}
} else if (i == _initialValidators.length - 1) {
setNextValidator(_initialValidators[i - 1], _initialValidators[i]);
setNextValidator(_initialValidators[i], F_ADDR);
} else {
setNextValidator(_initialValidators[i - 1], _initialValidators[i]);
}
emit ValidatorAdded(_initialValidators[i]);
}
setValidatorCount(_initialValidators.length);
uintStorage[REQUIRED_SIGNATURES] = _requiredSignatures;
uintStorage[DEPLOYED_AT_BLOCK] = block.number;
setInitialize();
emit RequiredSignaturesChanged(_requiredSignatures);
return isInitialized();
}
function addValidator(address _validator) external onlyOwner {
_addValidator(_validator);
emit ValidatorAdded(_validator);
}
function removeValidator(address _validator) external onlyOwner {
_removeValidator(_validator);
emit ValidatorRemoved(_validator);
}
}
pragma solidity 0.4.24;
import "../libraries/Bytes.sol";
contract ChooseReceiverHelper {
/**
* @dev Helper function for alternative receiver feature. Chooses the actual receiver out of sender and passed data.
* @param _from address of tokens sender.
* @param _data passed data in the transfer message.
* @return address of the receiver on the other side.
*/
function chooseReceiver(address _from, bytes _data) internal view returns (address recipient) {
recipient = _from;
if (_data.length > 0) {
require(_data.length == 20);
recipient = Bytes.bytesToAddress(_data);
require(recipient != address(0));
require(recipient != bridgeContractOnOtherSide());
}
}
/* solcov ignore next */
function bridgeContractOnOtherSide() internal view returns (address);
}
pragma solidity 0.4.24;
import "../libraries/Address.sol";
import "../libraries/SafeERC20.sol";
/**
* @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);
}
}
pragma solidity 0.4.24;
import "../upgradeability/EternalStorage.sol";
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
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));
}
}
pragma solidity 0.4.24;
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "openzeppelin-solidity/contracts/AddressUtils.sol";
import "./BasicForeignBridge.sol";
contract ERC20Bridge is BasicForeignBridge {
bytes32 internal constant ERC20_TOKEN = 0x15d63b18dbc21bf4438b7972d80076747e1d93c4f87552fe498c90cbde51665e; // keccak256(abi.encodePacked("erc20token"))
function erc20token() public view returns (ERC20) {
return ERC20(addressStorage[ERC20_TOKEN]);
}
function setErc20token(address _token) internal {
require(AddressUtils.isContract(_token));
addressStorage[ERC20_TOKEN] = _token;
}
function relayTokens(address _receiver, uint256 _amount) external {
require(_receiver != address(0));
require(_receiver != address(this));
require(_amount > 0);
require(withinLimit(_amount));
addTotalSpentPerDay(getCurrentDay(), _amount);
erc20token().transferFrom(msg.sender, address(this), _amount);
emit UserRequestForAffirmation(_receiver, _amount);
}
}
pragma solidity 0.4.24;
import "./BaseERC677Bridge.sol";
import "./OtherSideBridgeStorage.sol";
contract ERC677Bridge is BaseERC677Bridge, OtherSideBridgeStorage {
function erc677token() public view returns (ERC677) {
return _erc677token();
}
function bridgeSpecificActionsOnTokenTransfer(
ERC677, /*_token*/
address _from,
uint256 _value,
bytes _data
) internal {
fireEventOnTokenTransfer(chooseReceiver(_from, _data), _value);
}
/* solcov ignore next */
function fireEventOnTokenTransfer(address _from, uint256 _value) internal;
}
pragma solidity 0.4.24;
import "./ERC677Bridge.sol";
import "../interfaces/IBurnableMintableERC677Token.sol";
contract ERC677BridgeForBurnableMintableToken is ERC677Bridge {
function bridgeSpecificActionsOnTokenTransfer(ERC677 _token, address _from, uint256 _value, bytes _data) internal {
IBurnableMintableERC677Token(_token).burn(_value);
fireEventOnTokenTransfer(chooseReceiver(_from, _data), _value);
}
}
pragma solidity 0.4.24;
contract ERC677Storage {
bytes32 internal constant ERC677_TOKEN = 0xa8b0ade3e2b734f043ce298aca4cc8d19d74270223f34531d0988b7d00cba21d; // keccak256(abi.encodePacked("erc677token"))
}
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 */
_;
}
}
pragma solidity 0.4.24;
import "../interfaces/IGasToken.sol";
import "../upgradeable_contracts/Ownable.sol";
/**
* @title GasTokenConnector
* @dev This logic allows to use GasToken (https://gastoken.io)
*/
contract GasTokenConnector is Ownable {
bytes32 internal constant GAS_TOKEN_TARGET_MINT_VALUE = 0x7188f1264c90762deb4dbddcab803d6487a8f108fbcdec3ff08c642d35826f9f; // keccak256(abi.encodePacked("gasTokenTargetMintValue"))
bytes32 internal constant GAS_TOKEN_RECEIVER = 0x6778a39b83358b10315b40840597142f1db77a44f312ed9c0e45ee7af3bbc552; // keccak256(abi.encodePacked("gasTokenReceiver"))
bytes4 internal constant ON_TOKEN_TRANSFER = 0xa4c0ed36; // onTokenTransfer(address,uint256,bytes)
/**
* @dev Updates gas token related parameters, target mint value and token receiver
* @param _targetMintValue target amount of token to mint/transfer during one call to _collectGasTokens
* @param _receiver receiver of minted gas token
*/
function setGasTokenParameters(uint256 _targetMintValue, address _receiver) external onlyOwner {
uintStorage[GAS_TOKEN_TARGET_MINT_VALUE] = _targetMintValue;
addressStorage[GAS_TOKEN_RECEIVER] = _receiver;
}
/**
* @dev Updates gas token target mint value
* @param _targetMintValue target amount of token to mint/transfer during one call to _collectGasTokens
*/
function setGasTokenTargetMintValue(uint256 _targetMintValue) external onlyOwner {
uintStorage[GAS_TOKEN_TARGET_MINT_VALUE] = _targetMintValue;
}
/**
* @dev Updates gas token receiver
* @param _receiver receiver of minted gas token
*/
function setGasTokenReceiver(address _receiver) external onlyOwner {
addressStorage[GAS_TOKEN_RECEIVER] = _receiver;
}
/**
* @return Configured gas token target mint value
*/
function gasTokenTargetMintValue() public view returns (uint256) {
return uintStorage[GAS_TOKEN_TARGET_MINT_VALUE];
}
/**
* @return Configured gas token receiver
*/
function gasTokenReceiver() public view returns (address) {
return addressStorage[GAS_TOKEN_RECEIVER];
}
/**
* @return GST2 contract address in ethereum Mainnet
*/
function gasToken() public pure returns (IGasToken) {
return IGasToken(0x0000000000b3F879cb30FE243b4Dfee438691c04);
}
/**
* @dev Internal function, for collection gas tokens
* If sufficient allowance from sender exist, the new tokens are not minted at all
* Otherwise, all allowance is taken + remaining tokens are minted
* In total, configured target amount of tokens is transfered to gas token receiver
*/
function _collectGasTokens() internal {
uint256 target = gasTokenTargetMintValue();
if (target == 0) return;
address receiver = gasTokenReceiver();
if (receiver == address(0)) return;
IGasToken gst = gasToken();
uint256 approved = gst.allowance(msg.sender, address(this));
if (approved >= target) {
// tokens are transfered directly to receiver, avoiding transfer to the bridge contract
require(gst.transferFrom(msg.sender, receiver, target));
} else {
if (approved > 0) {
require(gst.transferFrom(msg.sender, address(this), approved));
}
gst.mint(target - approved);
require(gst.transfer(receiver, target));
}
receiver.call(abi.encodeWithSelector(ON_TOKEN_TRANSFER, address(this), target, ""));
}
}
pragma solidity 0.4.24;
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./Upgradeable.sol";
import "./RewardableBridge.sol";
import "./BasicHomeBridge.sol";
import "./BaseOverdrawManagement.sol";
/**
* @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));
}
}
}
pragma solidity 0.4.24;
import "../upgradeability/EternalStorage.sol";
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];
}
}
pragma solidity 0.4.24;
import "./Initializable.sol";
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];
}
}
pragma solidity 0.4.24;
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
import "openzeppelin-solidity/contracts/AddressUtils.sol";
import "../interfaces/IChai.sol";
import "../interfaces/ERC677Receiver.sol";
import "./Claimable.sol";
import "./TokenSwapper.sol";
/**
* @title InterestReceiver
* @dev Сontract for receiving Chai interest and immediatly converting it into Dai.
* Contract also will try to automaticaly relay tokens to configured xDai receiver
*/
contract InterestReceiver is ERC677Receiver, Ownable, Claimable, TokenSwapper {
bytes4 internal constant RELAY_TOKENS = 0x01e4f53a; // relayTokens(address,uint256)
address public bridgeContract;
address public receiverInXDai;
event RelayTokensFailed(address receiver, uint256 amount);
/**
* @dev Initializes interest receiver, sets an owner of a contract
* @param _owner address of owner account, only owner can withdraw Dai tokens from contract
* @param _bridgeContract address of the bridge contract in the foreign chain
* @param _receiverInXDai address of the receiver account, in the xDai chain
*/
constructor(address _owner, address _bridgeContract, address _receiverInXDai) public {
require(AddressUtils.isContract(_bridgeContract));
require(_receiverInXDai != address(0));
_transferOwnership(_owner);
bridgeContract = _bridgeContract;
receiverInXDai = _receiverInXDai;
}
/**
* @dev Updates bridge contract from which interest is expected to come from,
* the incoming tokens will be relayed through this bridge also
* @param _bridgeContract address of new contract in the foreign chain
*/
function setBridgeContract(address _bridgeContract) external onlyOwner {
require(AddressUtils.isContract(_bridgeContract));
bridgeContract = _bridgeContract;
}
/**
* @dev Updates receiver address in the xDai chain
* @param _receiverInXDai address of new receiver account in the xDai chain
*/
function setReceiverInXDai(address _receiverInXDai) external onlyOwner {
require(_receiverInXDai != address(0));
receiverInXDai = _receiverInXDai;
}
/**
* @return Chai token contract address
*/
function chaiToken() public view returns (IChai) {
return IChai(0x06AF07097C9Eeb7fD685c692751D5C66dB49c215);
}
/**
* @return Dai token contract address
*/
function daiToken() public view returns (ERC20) {
return ERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F);
}
/**
* @dev ERC677 transfer callback function, received interest is converted from Chai token into Dai
* and then relayed via bridge to xDai receiver
*/
function onTokenTransfer(address, uint256, bytes) external returns (bool) {
uint256 chaiBalance = chaiToken().balanceOf(address(this));
uint256 initialDaiBalance = daiToken().balanceOf(address(this));
uint256 finalDaiBalance = initialDaiBalance;
if (chaiBalance > 0) {
chaiToken().exit(address(this), chaiBalance);
finalDaiBalance = daiToken().balanceOf(address(this));
// Dai balance cannot decrease here, so SafeMath is not needed
uint256 redeemed = finalDaiBalance - initialDaiBalance;
emit TokensSwapped(chaiToken(), daiToken(), redeemed);
// chi is always >= 10**27, so chai/dai rate is always >= 1
require(redeemed >= chaiBalance);
}
daiToken().approve(address(bridgeContract), finalDaiBalance);
if (!bridgeContract.call(abi.encodeWithSelector(RELAY_TOKENS, receiverInXDai, finalDaiBalance))) {
daiToken().approve(address(bridgeContract), 0);
emit RelayTokensFailed(receiverInXDai, finalDaiBalance);
}
return true;
}
/**
* @dev Claims tokens from receiver account
* @param _token address of claimed token, address(0) for native
* @param _to address of tokens receiver
*/
function claimTokens(address _token, address _to) external onlyOwner {
// Only tokens other than CHAI/DAI can be claimed from this contract.
require(_token != address(chaiToken()) && _token != address(daiToken()));
claimValues(_token, _to);
}
}
pragma solidity 0.4.24;
import "../upgradeability/EternalStorage.sol";
/**
* @title MediatorBalanceStorage
* @dev Storage helpers for the mediator balance tracking.
*/
contract MediatorBalanceStorage is EternalStorage {
bytes32 internal constant MEDIATOR_BALANCE = 0x3db340e280667ee926fa8c51e8f9fcf88a0ff221a66d84d63b4778127d97d139; // keccak256(abi.encodePacked("mediatorBalance"))
/**
* @dev Tells the expected mediator balance.
* @return the current expected mediator balance.
*/
function mediatorBalance() public view returns (uint256) {
return uintStorage[MEDIATOR_BALANCE];
}
/**
* @dev Sets the expected mediator balance of the contract.
* @param _balance the new expected mediator balance value.
*/
function _setMediatorBalance(uint256 _balance) internal {
uintStorage[MEDIATOR_BALANCE] = _balance;
}
}
pragma solidity 0.4.24;
import "../upgradeability/EternalStorage.sol";
contract MessageRelay is EternalStorage {
function relayedMessages(bytes32 _txHash) public view returns (bool) {
return boolStorage[keccak256(abi.encodePacked("relayedMessages", _txHash))];
}
function setRelayedMessages(bytes32 _txHash, bool _status) internal {
boolStorage[keccak256(abi.encodePacked("relayedMessages", _txHash))] = _status;
}
}
{
"deploy": {
"VM:-": {
"linkReferences": {},
"autoDeployLib": true
},
"main:1": {
"linkReferences": {},
"autoDeployLib": true
},
"ropsten:3": {
"linkReferences": {},
"autoDeployLib": true
},
"rinkeby:4": {
"linkReferences": {},
"autoDeployLib": true
},
"kovan:42": {
"linkReferences": {},
"autoDeployLib": true
},
"görli:5": {
"linkReferences": {},
"autoDeployLib": true
},
"Custom": {
"linkReferences": {},
"autoDeployLib": true
}
},
"data": {
"bytecode": {
"linkReferences": {},
"object": "608060405234801561001057600080fd5b50614512806100206000396000f3006080604052600436106101f55763ffffffff60e060020a60003504166301e4f53a81146101fa57806301fcc1d314610220578063032f693f146102445780630950d515146102775780630b26cf661461028f57806310775238146102b0578063125e4cfb146102e857806316ef191314610312578063194153d31461033357806326aa101f146103545780632803212f14610375578063351a826414610399578063392e53cd146103d15780633a50bc87146103e65780633e6968b61461040a57806340f8dd861461041f578063437764df14610440578063593399821461047257806369ffa08a1461048a5780636e5d6bea146104b15780637610722f146104d25780637837cf91146104f35780638190d90614610517578063871c0760146105385780638da5cb5b146105695780639a4a43951461057e5780639cb7595a14610596578063a4b1c243146105d7578063a4c0ed36146105f8578063ab3a25d914610661578063ad58bdd114610685578063b53472ef146106af578063be3b625b146106d0578063cd596583146106e5578063d0342acd146106fa578063db6fff8c14610721578063e79767af14610745578063ec47de2a14610766578063f2c54fe81461078a578063f2fde38b146107ae578063f3b83791146107cf578063f3f51415146107e7578063f9eaee0d14610808575b600080fd5b34801561020657600080fd5b5061021e600160a060020a0360043516602435610829565b005b34801561022c57600080fd5b5061021e600160a060020a0360043516602435610838565b34801561025057600080fd5b50610265600160a060020a0360043516610955565b60408051918252519081900360200190f35b34801561028357600080fd5b5061021e600435610a18565b34801561029b57600080fd5b5061021e600160a060020a0360043516610dc7565b3480156102bc57600080fd5b506102d4600160a060020a0360043516602435610def565b604080519115158252519081900360200190f35b3480156102f457600080fd5b5061021e600160a060020a0360043581169060243516604435610e66565b34801561031e57600080fd5b50610265600160a060020a0360043516610ed2565b34801561033f57600080fd5b50610265600160a060020a0360043516610f53565b34801561036057600080fd5b506102d4600160a060020a0360043516610fdb565b34801561038157600080fd5b5061021e600160a060020a0360043516602435610fee565b3480156103a557600080fd5b506102d4600160a060020a0360043581169060243581169060449060a49060e43590610104351661112d565b3480156103dd57600080fd5b506102d46112ff565b3480156103f257600080fd5b506102d4600160a060020a036004351660243561132c565b34801561041657600080fd5b50610265611382565b34801561042b57600080fd5b50610265600160a060020a036004351661138b565b34801561044c57600080fd5b5061045561140c565b60408051600160e060020a03199092168252519081900360200190f35b34801561047e57600080fd5b506102d460043561141a565b34801561049657600080fd5b5061021e600160a060020a03600435811690602435166114d5565b3480156104bd57600080fd5b5061021e600160a060020a0360043516611584565b3480156104de57600080fd5b50610265600160a060020a03600435166115a9565b3480156104ff57600080fd5b5061021e600160a060020a0360043516602435611602565b34801561052357600080fd5b50610265600160a060020a036004351661173f565b34801561054457600080fd5b5061054d6117c0565b60408051600160a060020a039092168252519081900360200190f35b34801561057557600080fd5b5061054d6117f3565b34801561058a57600080fd5b5061021e600435611826565b3480156105a257600080fd5b506105ab611b4c565b6040805167ffffffffffffffff9485168152928416602084015292168183015290519081900360600190f35b3480156105e357600080fd5b50610265600160a060020a0360043516611b57565b34801561060457600080fd5b50604080516020600460443581810135601f81018490048402850184019095528484526102d4948235600160a060020a0316946024803595369594606494920191908190840183828082843750949750611bd89650505050505050565b34801561066d57600080fd5b50610265600160a060020a0360043516602435611c02565b34801561069157600080fd5b5061021e600160a060020a0360043581169060243516604435611cd8565b3480156106bb57600080fd5b5061021e600160a060020a0360043516611ce3565b3480156106dc57600080fd5b50610265611d08565b3480156106f157600080fd5b5061054d611d32565b34801561070657600080fd5b5061021e600160a060020a0360043581169060243516611d65565b34801561072d57600080fd5b5061021e600160a060020a0360043516602435612088565b34801561075157600080fd5b5061021e600160a060020a0360043516612169565b34801561077257600080fd5b5061021e600160a060020a036004351660243561218e565b34801561079657600080fd5b50610265600160a060020a0360043516602435612273565b3480156107ba57600080fd5b5061021e600160a060020a0360043516612307565b3480156107db57600080fd5b5061021e60043561232c565b3480156107f357600080fd5b50610265600160a060020a0360043516612351565b34801561081457600080fd5b506102d4600160a060020a03600435166123d4565b61083482338361245a565b5050565b6108406117f3565b600160a060020a0316331461085457600080fd5b61085d82610fdb565b151561086857600080fd5b801580610887575060008111801561088757506108848261138b565b81105b151561089257600080fd5b806000808460405160200180806000805160206144a783398151915281525060110182600160a060020a0316600160a060020a0316606060020a0281526014019150506040516020818303038152906040526040518082805190602001908083835b602083106109135780518252601f1990920191602091820191016108f4565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020939093555050505050565b600080600083604051602001808060c360020a670dac2f0a0cae4a8f0281525060080182600160a060020a0316600160a060020a0316606060020a0281526014019150506040516020818303038152906040526040518082805190602001908083835b602083106109d75780518252601f1990920191602091820191016109b8565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205495945050505050565b6000610a238261265c565b610a2c82612744565b9050610a378161173f565b8214156108345760008082604051602001808060b260020a6919185a5b1e531a5b5a5d02815250600a0182600160a060020a0316600160a060020a0316606060020a0281526014019150506040516020818303038152906040526040518082805190602001908083835b60208310610ac05780518252601f199092019160209182019101610aa1565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285810196909652509283016000908120819055835160c360020a670dac2f0a0cae4a8f0281870152600160a060020a038716606060020a0260288201528451808203601c018152603c909101948590528051919586959194509092508291908401908083835b60208310610b6f5780518252601f199092019160209182019101610b50565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285810196909652509283016000908120819055835160c360020a670dad2dca0cae4a8f0281870152600160a060020a038716606060020a0260288201528451808203601c018152603c909101948590528051919586959194509092508291908401908083835b60208310610c1e5780518252601f199092019160209182019101610bff565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528581019690965250928301600090812081905583516000805160206142c783398151915281870152600160a060020a038716606060020a026033820152845180820360270181526047909101948590528051919586959194509092508291908401908083835b60208310610ccd5780518252601f199092019160209182019101610cae565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528581019690965250928301600090812081905583516000805160206144a783398151915281870152600160a060020a038716606060020a026031820152845180820360250181526045909101948590528051919586959194509092508291908401908083835b60208310610d7c5780518252601f199092019160209182019101610d5d565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600090812081905561083493508492509050612805565b610dcf6117f3565b600160a060020a03163314610de357600080fd5b610dec8161287b565b50565b600080610e1383610e0786610e02611382565b611c02565b9063ffffffff6128d516565b90506000610e216000612351565b118015610e36575080610e3385612351565b10155b8015610e4a5750610e4684610955565b8311155b8015610e5e5750610e5a84611b57565b8310155b949350505050565b610e6e611d32565b600160a060020a03163314610e8257600080fd5b610e8a6117c0565b600160a060020a0316610e9b6128e2565b600160a060020a031614610eae57600080fd5b610eb783610fdb565b1515610ec257600080fd5b610ecd83838361295a565b505050565b60008060008360405160200180806000805160206144a783398151915281525060110182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106109d75780518252601f1990920191602091820191016109b8565b6000806000836040516020018080608860020a6e6d65646961746f7242616c616e636502815250600f0182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106109d75780518252601f1990920191602091820191016109b8565b600080610fe783611b57565b1192915050565b610ff66117f3565b600160a060020a0316331461100a57600080fd5b61101382610fdb565b151561101e57600080fd5b61102782610955565b811180611032575080155b151561103d57600080fd5b8060008084604051602001808060b260020a6919185a5b1e531a5b5a5d02815250600a0182600160a060020a0316600160a060020a0316606060020a0281526014019150506040516020818303038152906040526040518082805190602001908083835b602083106110c05780518252601f1990920191602091820191016110a1565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528581019690965250928301600020949094555080518481529051600160a060020a03861693506000805160206142e7833981519152929181900390910190a25050565b6040805160048152602481018252602081018051600160e060020a031660e160020a6337ef4101021781529151815160009330939291829190808383895b8381101561118357818101518382015260200161116b565b50505050905090810190601f1680156111b05780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af19150501580611242575030600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561120a57600080fd5b505af115801561121e573d6000803e3d6000fd5b505050506040513d602081101561123457600080fd5b5051600160a060020a031633145b8061124c57503330145b151561125757600080fd5b61125f6112ff565b1561126957600080fd5b6112728761287b565b61127b86612996565b6112a96000866003806020026040519081016040528092919082600360200280828437506129dc9350505050565b6040805180820182526112d291600091908790600290839083908082843750612c6c9350505050565b6112db83612e09565b6112e482612e46565b6112ec612eec565b6112f46112ff565b979650505050505050565b60008051602061438783398151915260005260046020526000805160206143078339815191525460ff1690565b60008061134483610e078661133f611382565b612273565b90506000611352600061138b565b1180156113675750806113648561138b565b10155b8015610e5e575061137784610ed2565b909211159392505050565b62015180420490565b60008060008360405160200180806000805160206142c783398151915281525060130182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106109d75780518252601f1990920191602091820191016109b8565b60e160020a6358a8b6130290565b60006004600083604051602001808060a260020a6b1b595cdcd859d9519a5e195902815250600c0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106114915780518252601f199092019160209182019101611472565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205460ff1695945050505050565b30600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561151357600080fd5b505af1158015611527573d6000803e3d6000fd5b505050506040513d602081101561153d57600080fd5b5051600160a060020a0316331461155357600080fd5b600160a060020a038216158061156f575061156d82610fdb565b155b151561157a57600080fd5b6108348282612f1f565b61158c6117f3565b600160a060020a031633146115a057600080fd5b610dec81612996565b60008060008060006115ba86610955565b93506115c586612351565b92506115d386610e02611382565b91508183116115e35760006115e7565b8183035b90508084106115f657806115f8565b835b9695505050505050565b61160a6117f3565b600160a060020a0316331461161e57600080fd5b61162782610fdb565b151561163257600080fd5b61163b82610ed2565b811180611646575080155b151561165157600080fd5b806000808460405160200180806000805160206142c783398151915281525060130182600160a060020a0316600160a060020a0316606060020a0281526014019150506040516020818303038152906040526040518082805190602001908083835b602083106116d25780518252601f1990920191602091820191016116b3565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528581019690965250928301600020949094555080518481529051600160a060020a03861693506000805160206143c7833981519152929181900390910190a25050565b60008060008360405160200180806000805160206144c7833981519152815250601a0182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106109d75780518252601f1990920191602091820191016109b8565b6000805160206143e7833981519152600052600260205260008051602061442783398151915254600160a060020a031690565b600080516020614367833981519152600052600260205260008051602061434783398151915254600160a060020a031690565b60006060611832611d32565b600160a060020a031663cb08a10c846040518263ffffffff1660e060020a028152600401808260001916600019168152602001915050602060405180830381600087803b15801561188257600080fd5b505af1158015611896573d6000803e3d6000fd5b505050506040513d60208110156118ac57600080fd5b5051156118b857600080fd5b306118c1611d32565b600160a060020a0316633f9a8e7e856040518263ffffffff1660e060020a028152600401808260001916600019168152602001915050602060405180830381600087803b15801561191157600080fd5b505af1158015611925573d6000803e3d6000fd5b505050506040513d602081101561193b57600080fd5b5051600160a060020a03161461195057600080fd5b6119586117c0565b600160a060020a0316611969611d32565b600160a060020a0316634a610b04856040518263ffffffff1660e060020a028152600401808260001916600019168152602001915050602060405180830381600087803b1580156119b957600080fd5b505af11580156119cd573d6000803e3d6000fd5b505050506040513d60208110156119e357600080fd5b5051600160a060020a0316146119f857600080fd5b5050604080516024808201849052825180830390910181526044909101909152602081018051600160e060020a031660e060020a630950d5150290811790915290611a41611d32565b600160a060020a031663dc8601b3611a576117c0565b83611a60611d08565b6040518463ffffffff1660e060020a0281526004018084600160a060020a0316600160a060020a0316815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b83811015611acd578181015183820152602001611ab5565b50505050905090810190601f168015611afa5780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600087803b158015611b1b57600080fd5b505af1158015611b2f573d6000803e3d6000fd5b505050506040513d6020811015611b4557600080fd5b5050505050565b600160026000909192565b600080600083604051602001808060c360020a670dad2dca0cae4a8f0281525060080182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106109d75780518252601f1990920191602091820191016109b8565b600080611be3612f58565b1515611bf7575033611bf781868686612f85565b506001949350505050565b600080600084846040516020018080608060020a6f746f74616c5370656e745065724461790281525060100183600160a060020a0316600160a060020a0316606060020a028152601401828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310611c945780518252601f199092019160209182019101611c75565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205493505050505b92915050565b610ecd83838361245a565b611ceb6117f3565b600160a060020a03163314611cff57600080fd5b610dec816133b9565b60008051602061446783398151915260009081526020526000805160206143a78339815191525490565b600080516020614407833981519152600052600260205260008051602061448783398151915254600160a060020a031690565b6000806000806060600030600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015611dad57600080fd5b505af1158015611dc1573d6000803e3d6000fd5b505050506040513d6020811015611dd757600080fd5b5051600160a060020a03163314611ded57600080fd5b86600160a060020a0381161515611e0357600080fd5b611e0c89610fdb565b1515611e1757600080fd5b6040805160e060020a6370a082310281523060048201529051600160a060020a038b16916370a082319160248083019260209291908290030181600087803b158015611e6257600080fd5b505af1158015611e76573d6000803e3d6000fd5b505050506040513d6020811015611e8c57600080fd5b50519650611e9989610f53565b9550858711611ea757600080fd5b8587039450611eb5896115a9565b935060008411611ec457600080fd5b83851115611ed0578394505b611ee289611edc611382565b876134e5565b611efb89611ef6888863ffffffff6128d516565b6135c6565b60408051600160a060020a03808c1660248301528a1660448201526064808201889052825180830390910181526084909101909152602081018051600160e060020a031660e060020a63125e4cfb021790529250611f57611d32565b600160a060020a031663dc8601b3611f6d6117c0565b85611f76611d08565b6040518463ffffffff1660e060020a0281526004018084600160a060020a0316600160a060020a0316815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b83811015611fe3578181015183820152602001611fcb565b50505050905090810190601f1680156120105780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600087803b15801561203157600080fd5b505af1158015612045573d6000803e3d6000fd5b505050506040513d602081101561205b57600080fd5b50519150612069828a61364d565b6120738286613720565b61207d8289613794565b505050505050505050565b6120906117f3565b600160a060020a031633146120a457600080fd5b6120ad82610fdb565b15156120b857600080fd5b8015806120de57506120c982611b57565b811180156120de57506120db82612351565b81105b15156120e957600080fd5b8060008084604051602001808060c360020a670dac2f0a0cae4a8f0281525060080182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106109135780518252601f1990920191602091820191016108f4565b6121716117f3565b600160a060020a0316331461218557600080fd5b610dec8161380d565b6121966117f3565b600160a060020a031633146121aa57600080fd5b6121b382610fdb565b15156121be57600080fd5b6000811180156121d557506121d282612351565b81105b80156121e857506121e582610955565b81105b15156121f357600080fd5b8060008084604051602001808060c360020a670dad2dca0cae4a8f0281525060080182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106109135780518252601f1990920191602091820191016108f4565b600080600084846040516020018080606860020a72746f74616c45786563757465645065724461790281525060130183600160a060020a0316600160a060020a0316606060020a0281526014018281526020019250505060405160208183030381529060405260405180828051906020019080838360208310611c945780518252601f199092019160209182019101611c75565b61230f6117f3565b600160a060020a0316331461232357600080fd5b610dec81612e46565b6123346117f3565b600160a060020a0316331461234857600080fd5b610dec81612e09565b600080600083604051602001808060b260020a6919185a5b1e531a5b5a5d02815250600a0182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106109d75780518252601f1990920191602091820191016109b8565b60006004600083604051602001808060a260020a6b1d1bdad95b905b1b1bddd95902815250600c0182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106114915780518252601f199092019160209182019101611472565b600080612465612f58565b1561246f57600080fd5b6040805160e060020a6370a082310281523060048201529051600160a060020a038716916370a082319160248083019260209291908290030181600087803b1580156124ba57600080fd5b505af11580156124ce573d6000803e3d6000fd5b505050506040513d60208110156124e457600080fd5b505191506124f2600161393a565b6040805160e060020a6323b872dd028152336004820152306024820152604481018590529051600160a060020a038716916323b872dd9160648083019260209291908290030181600087803b15801561254a57600080fd5b505af115801561255e573d6000803e3d6000fd5b505050506040513d602081101561257457600080fd5b506125819050600061393a565b6040805160e060020a6370a08231028152306004820152905161260a918491600160a060020a038916916370a082319160248083019260209291908290030181600087803b1580156125d257600080fd5b505af11580156125e6573d6000803e3d6000fd5b505050506040513d60208110156125fc57600080fd5b50519063ffffffff61397116565b90508281111561261957600080fd5b611b45853383876040516020018082600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052612f85565b6000806000612669611d32565b600160a060020a0316331461267d57600080fd5b6126856117c0565b600160a060020a03166126966128e2565b600160a060020a0316146126a957600080fd5b6126b28461141a565b156126bc57600080fd5b6126c584612744565b92506126d084613983565b91506126db846139fd565b90506126e684613a72565b6126f1838383613b36565b60408051600160a060020a03808616825284166020820152808201839052905185917f07b5483b8e4bd8ea240a474d5117738350e7d431e3668c48a97910b0b397796a919081900360600190a250505050565b60006002600083604051602001808060a160020a6b36b2b9b9b0b3b2aa37b5b2b702815250600c0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106127bb5780518252601f19909201916020918201910161279c565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002054600160a060020a031695945050505050565b604080516000805160206144c7833981519152602080830191909152606060020a600160a060020a03861602603a8301528251602e818403018152604e9092019283905281518493600093849390928291840190808383602083106109135780518252601f1990920191602091820191016108f4565b61288481613b6d565b151561288f57600080fd5b60008051602061440783398151915260005260026020526000805160206144878339815191528054600160a060020a031916600160a060020a0392909216919091179055565b81810182811015611cd257fe5b60006128ec611d32565b600160a060020a031663d67bdd256040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561292957600080fd5b505af115801561293d573d6000803e3d6000fd5b505050506040513d602081101561295357600080fd5b5051905090565b612964838261132c565b1561298b5761297b83612975611382565b83613b75565b612986838383613c15565b610ecd565b610ecd8383836101f5565b6000805160206143e783398151915260005260026020526000805160206144278339815191528054600160a060020a031916600160a060020a0392909216919091179055565b604081015160001080156129f7575060408101516020820151115b8015612a07575060208101518151115b1515612a1257600080fd5b80516040805160b260020a6919185a5b1e531a5b5a5d02602082810191909152606060020a600160a060020a03871602602a8301528251601e818403018152603e909201928390528151600093849392909182918401908083835b60208310612a8c5780518252601f199092019160209182019101612a6d565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528581019690965250928301600090812095909555505083820151815160c360020a670dac2f0a0cae4a8f0281850152600160a060020a038716606060020a0260288201528251808203601c018152603c9091019283905280519194938493919282918401908083835b60208310612b3e5780518252601f199092019160209182019101612b1f565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528581019690965250928301600090812095909555505083810151815160c360020a670dad2dca0cae4a8f0281850152600160a060020a038716606060020a0260288201528251808203601c018152603c9091019283905280519194938493919282918401908083835b60208310612bf05780518252601f199092019160209182019101612bd1565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600090812094909455505050600160a060020a038316906000805160206142e78339815191529083905b60200201516040518082815260200191505060405180910390a25050565b8051602082015110612c7d57600080fd5b8051604080516000805160206142c7833981519152602082810191909152606060020a600160a060020a038716026033830152825160278184030181526047909201928390528151600093849392909182918401908083835b60208310612cf55780518252601f199092019160209182019101612cd6565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652858101969096525092830160009081209590955550508382015181516000805160206144a783398151915281850152600160a060020a038716606060020a0260318201528251808203602501815260459091019283905280519194938493919282918401908083835b60208310612da75780518252601f199092019160209182019101612d88565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600090812094909455505050600160a060020a038316906000805160206143c7833981519152908390612c4e565b612e11613c98565b811115612e1d57600080fd5b60008051602061446783398151915260009081526020526000805160206143a783398151915255565b600160a060020a0381161515612e5b57600080fd5b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0612e846117f3565b60408051600160a060020a03928316815291841660208301528051918290030190a160008051602061436783398151915260005260026020526000805160206143478339815191528054600160a060020a031916600160a060020a0392909216919091179055565b6000805160206143878339815191526000526004602052600080516020614307833981519152805460ff19166001179055565b80600160a060020a0381161515612f3557600080fd5b600160a060020a0383161515612f4e5761298682613cdf565b610ecd8383613ceb565b60008051602061444783398151915260005260046020526000805160206143278339815191525460ff1690565b600060608060006060600080612f99612f58565b15612fa3576133ac565b612fac8b6123d4565b1515612fb757600080fd5b612fc08b610fdb565b965086151561301357612fd28b613d88565b9550612fdd8b613e6d565b9450612fe88b613ec3565b9350600086511180612ffb575060008551115b151561300657600080fd5b6130138b8560ff16613f15565b61301d8b8a610def565b151561302857600080fd5b61303a8b613034611382565b8b6134e5565b6130448a896140ab565b915086156130a55760408051600160a060020a03808e1660248301528416604482015260648082018c9052825180830390910181526084909101909152602081018051600160e060020a031660e060020a63125e4cfb021790529250613215565b30600160a060020a0316632ae87cdd905060e060020a028b878787868e6040516024018087600160a060020a0316600160a060020a0316815260200180602001806020018660ff1660ff16815260200185600160a060020a0316600160a060020a03168152602001848152602001838103835288818151815260200191508051906020019080838360005b83811015613148578181015183820152602001613130565b50505050905090810190601f1680156131755780820380516001836020036101000a031916815260200191505b50838103825287518152875160209182019189019080838360005b838110156131a8578181015183820152602001613190565b50505050905090810190601f1680156131d55780820380516001836020036101000a031916815260200191505b5060408051601f19818403018152919052602081018051600160e060020a0316600160e060020a0319909c169b909b17909a5250979a5050505050505050505b6132268b611ef68b610e078f610f53565b61322e611d32565b600160a060020a031663dc8601b36132446117c0565b8561324d611d08565b6040518463ffffffff1660e060020a0281526004018084600160a060020a0316600160a060020a0316815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156132ba5781810151838201526020016132a2565b50505050905090810190601f1680156132e75780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600087803b15801561330857600080fd5b505af115801561331c573d6000803e3d6000fd5b505050506040513d602081101561333257600080fd5b50519050613340818c61364d565b61334a818a613720565b613354818b613794565b861515613365576133658b82612805565b604080518a815290518291600160a060020a03808e1692908f16917f59a9a8027b9c87b961e254899821c9a276b5efc35d1f7409ea4f291470f1629a919081900360200190a45b5050505050505050505050565b6133c2816123d4565b156133cc57600080fd5b6133d581613b6d565b15156133e057600080fd5b60016004600083604051602001808060a260020a6b1d1bdad95b905b1b1bddd95902815250600c0182600160a060020a0316600160a060020a0316606060020a0281526014019150506040516020818303038152906040526040518082805190602001908083835b602083106134675780518252601f199092019160209182019101613448565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529283016000908120805460ff191696151596909617909555505051600160a060020a038416927fbeceb48aeaa805aeae57be163cca6249077a18734e408a85aa74e875c4373809925090a250565b6134f381610e078585611c02565b60008085856040516020018080608060020a6f746f74616c5370656e745065724461790281525060100183600160a060020a0316600160a060020a0316606060020a028152601401828152602001925050506040516020818303038152906040526040518082805190602001908083835b602083106135835780518252601f199092019160209182019101613564565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002093909355505050505050565b80600080846040516020018080608860020a6e6d65646961746f7242616c616e636502815250600f0182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106109135780518252601f1990920191602091820191016108f4565b806002600084604051602001808060a160020a6b36b2b9b9b0b3b2aa37b5b2b702815250600c0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106136c35780518252601f1990920191602091820191016136a4565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000208054600160a060020a031916600160a060020a0395909516949094179093555050505050565b8060008084604051602001808060a060020a6b6d65737361676556616c756502815250600c018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106109135780518252601f1990920191602091820191016108f4565b8060026000846040516020018080608260020a6f1b595cdcd859d9549958da5c1a595b9d028152506010018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106136c35780518252601f1990920191602091820191016136a4565b613816816123d4565b151561382157600080fd5b61382a81613b6d565b151561383557600080fd5b60006004600083604051602001808060a260020a6b1d1bdad95b905b1b1bddd95902815250600c0182600160a060020a0316600160a060020a0316606060020a0281526014019150506040516020818303038152906040526040518082805190602001908083835b602083106138bc5780518252601f19909201916020918201910161389d565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529283016000908120805460ff191696151596909617909555505051600160a060020a038416927feaa9136602e3b70a4e689b5b6f55bda25ca62b917d839c0ff87f5902387f77b9925090a250565b6000805160206144478339815191526000526004602052600080516020614327833981519152805460ff1916911515919091179055565b60008282111561397d57fe5b50900390565b600060026000836040516020018080608260020a6f1b595cdcd859d9549958da5c1a595b9d028152506010018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106127bb5780518252601f19909201916020918201910161279c565b600080600083604051602001808060a060020a6b6d65737361676556616c756502815250600c018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106109d75780518252601f1990920191602091820191016109b8565b60016004600083604051602001808060a260020a6b1b595cdcd859d9519a5e195902815250600c0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310613ae95780518252601f199092019160209182019101613aca565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805460ff19169415159490941790935550505050565b613b5383611ef683613b4787610f53565b9063ffffffff61397116565b610ecd600160a060020a038416838363ffffffff61410516565b6000903b1190565b613b8381610e078585612273565b60008085856040516020018080606860020a72746f74616c45786563757465645065724461790281525060130183600160a060020a0316600160a060020a0316606060020a02815260140182815260200192505050604051602081830303815290604052604051808280519060200190808383602083106135835780518252601f199092019160209182019101613564565b6000613c1f61419a565b9050613c3b600160a060020a038516848463ffffffff61410516565b613c4c84611ef684613b4788610f53565b6040805183815290518291600160a060020a0380871692908816917f9afd47907e25028cdaca89d193518c302bbb128617d5a992c5abd45815526593919081900360200190a450505050565b6000613ca2611d32565b600160a060020a031663e5789d036040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561292957600080fd5b303161083482826141e1565b6040805160e060020a6370a0823102815230600482015290518391600091600160a060020a038416916370a0823191602480830192602092919082900301818787803b158015613d3a57600080fd5b505af1158015613d4e573d6000803e3d6000fd5b505050506040513d6020811015613d6457600080fd5b50519050613d82600160a060020a038516848363ffffffff61410516565b50505050565b60405160e060020a6306fdde03028152606090600082602083600481885afa1515613dc55760e160020a6351fa6fbf028352602083600485885afa505b3d830160405260203d1160018114613ddf573d9250613ded565b6020806040513e6040515192505b50816040519080825280601f01601f191660200182016040528015613e1c578160200160208202803883390190505b50905060203d1115613e3557816040602083013e610e5e565b60003d1115610e5e576000835193508360208301525b6000841115613e635760089390931b92600101613e4b565b8152949350505050565b60405160e060020a6395d89b41028152606090600082602083600481885afa1515613dc55760e360020a631eedf1af028352602083600485885afa503d830160405260203d1160018114613ddf573d9250613ded565b6000806040516020810160405260e060020a63313ce567028152602081600483875afa1515613f0d5760e060020a632e0f2625028152602081600483875afa1515613f0d57600081525b519392505050565b600080600080600080601287101561400a5786601203600a0a9550613f4a86613f3e6000611b57565b9063ffffffff61424216565b9450613f5a86613f3e6000610955565b9350613f6a86613f3e6000612351565b9250613f7a86613f3e6000610ed2565b9150613f8a86613f3e600061138b565b9050841515613fc25760019450848411613fc25760649350606491508383111580613fb55750818111155b15613fc257506127109150815b613fe788606060405190810160405280868152602001878152602001888152506129dc565b61400588604080519081016040528084815260200185815250612c6c565b6140a1565b60128703600a0a955061406a8860606040519081016040528061403d8a6140316000612351565b9063ffffffff61425716565b81526020016140508a6140316000610955565b81526020016140638a6140316000611b57565b90526129dc565b6140a18860408051908101604052806140878a614031600061138b565b815260200161409a8a6140316000610ed2565b9052612c6c565b5050505050505050565b8051829060001015611cd25781516014146140c557600080fd5b6140ce82614280565b9050600160a060020a03811615156140e557600080fd5b6140ed614287565b600160a060020a0382811691161415611cd257600080fd5b82600160a060020a031663a9059cbb83836040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050600060405180830381600087803b15801561416857600080fd5b505af115801561417c573d6000803e3d6000fd5b505050503d15610ecd5760206000803e6000511515610ecd57600080fd5b60006141a4611d32565b600160a060020a031663669f618b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561292957600080fd5b604051600160a060020a0383169082156108fc029083906000818181858888f193505050501515610834578082614216614296565b600160a060020a039091168152604051908190036020019082f080158015611b45573d6000803e3d6000fd5b6000818381151561424f57fe5b049392505050565b600082151561426857506000611cd2565b5081810281838281151561427857fe5b0414611cd257fe5b6014015190565b60006142916117c0565b905090565b6040516021806142a6833901905600608060405260405160208060218339810160405251600160a060020a038116ff00657865637574696f6e4461696c794c696d697400000000000000000000000000ca0b3dabefdbd8c72c0a9cf4a6e9d107da897abf036ef3f3f3b010cdd2594159078d888f9b66f3f8bfa10909e31f1e16240db73449f0500afdbbe3a70da457cccb8d022f2163402334a4962e3279c5def3417d3d8dab9e27ba26e81e3f833784b7802e97e87ef2842a6cce7da7ffaeaedaa2f61a6a7870b23d9d01fc9b73712e02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c00a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba2de0d2cdc19d356cb53b5984f91bfd3b31fe0c678a0d190a6db39274bb34753f4c177b42dbe934b3abbc0208c11a42e46589983431616f1710ab19969c5ed62e98aa806e31e94a687a31c65769cb99670064dd7f5a87526da075c5fb4eab9880811bbb11e8899da471f0e69a3ed55090fc90215227fc5fb1cb0d6e962ea7b74f0c1206883be66049a02d4937078367c00b3d71dd1a9465df969363c6ddeac96d6168652c307c1e813ca11cfb3a601f1cf3b22452021a5052d8b05f1f1f8a3e922dfd6c9f781bb6bbb5369c114e949b69ebb440ef3d4dd6b2836225eb1dc3a2beb4ed64697d3ef8518241966f7c6f28b0d72f20f51198717d198d2d55076c593d657865637574696f6e4d61785065725478000000000000000000000000000000746f6b656e526567697374726174696f6e4d6573736167654964000000000000a165627a7a723058203f04eb68ba625d53c01d3c1380a6b082ba393badba220072f5746c73a0b554ad0029",
"opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x4512 DUP1 PUSH2 0x20 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH2 0x1F5 JUMPI PUSH4 0xFFFFFFFF PUSH1 0xE0 PUSH1 0x2 EXP PUSH1 0x0 CALLDATALOAD DIV AND PUSH4 0x1E4F53A DUP2 EQ PUSH2 0x1FA JUMPI DUP1 PUSH4 0x1FCC1D3 EQ PUSH2 0x220 JUMPI DUP1 PUSH4 0x32F693F EQ PUSH2 0x244 JUMPI DUP1 PUSH4 0x950D515 EQ PUSH2 0x277 JUMPI DUP1 PUSH4 0xB26CF66 EQ PUSH2 0x28F JUMPI DUP1 PUSH4 0x10775238 EQ PUSH2 0x2B0 JUMPI DUP1 PUSH4 0x125E4CFB EQ PUSH2 0x2E8 JUMPI DUP1 PUSH4 0x16EF1913 EQ PUSH2 0x312 JUMPI DUP1 PUSH4 0x194153D3 EQ PUSH2 0x333 JUMPI DUP1 PUSH4 0x26AA101F EQ PUSH2 0x354 JUMPI DUP1 PUSH4 0x2803212F EQ PUSH2 0x375 JUMPI DUP1 PUSH4 0x351A8264 EQ PUSH2 0x399 JUMPI DUP1 PUSH4 0x392E53CD EQ PUSH2 0x3D1 JUMPI DUP1 PUSH4 0x3A50BC87 EQ PUSH2 0x3E6 JUMPI DUP1 PUSH4 0x3E6968B6 EQ PUSH2 0x40A JUMPI DUP1 PUSH4 0x40F8DD86 EQ PUSH2 0x41F JUMPI DUP1 PUSH4 0x437764DF EQ PUSH2 0x440 JUMPI DUP1 PUSH4 0x59339982 EQ PUSH2 0x472 JUMPI DUP1 PUSH4 0x69FFA08A EQ PUSH2 0x48A JUMPI DUP1 PUSH4 0x6E5D6BEA EQ PUSH2 0x4B1 JUMPI DUP1 PUSH4 0x7610722F EQ PUSH2 0x4D2 JUMPI DUP1 PUSH4 0x7837CF91 EQ PUSH2 0x4F3 JUMPI DUP1 PUSH4 0x8190D906 EQ PUSH2 0x517 JUMPI DUP1 PUSH4 0x871C0760 EQ PUSH2 0x538 JUMPI DUP1 PUSH4 0x8DA5CB5B EQ PUSH2 0x569 JUMPI DUP1 PUSH4 0x9A4A4395 EQ PUSH2 0x57E JUMPI DUP1 PUSH4 0x9CB7595A EQ PUSH2 0x596 JUMPI DUP1 PUSH4 0xA4B1C243 EQ PUSH2 0x5D7 JUMPI DUP1 PUSH4 0xA4C0ED36 EQ PUSH2 0x5F8 JUMPI DUP1 PUSH4 0xAB3A25D9 EQ PUSH2 0x661 JUMPI DUP1 PUSH4 0xAD58BDD1 EQ PUSH2 0x685 JUMPI DUP1 PUSH4 0xB53472EF EQ PUSH2 0x6AF JUMPI DUP1 PUSH4 0xBE3B625B EQ PUSH2 0x6D0 JUMPI DUP1 PUSH4 0xCD596583 EQ PUSH2 0x6E5 JUMPI DUP1 PUSH4 0xD0342ACD EQ PUSH2 0x6FA JUMPI DUP1 PUSH4 0xDB6FFF8C EQ PUSH2 0x721 JUMPI DUP1 PUSH4 0xE79767AF EQ PUSH2 0x745 JUMPI DUP1 PUSH4 0xEC47DE2A EQ PUSH2 0x766 JUMPI DUP1 PUSH4 0xF2C54FE8 EQ PUSH2 0x78A JUMPI DUP1 PUSH4 0xF2FDE38B EQ PUSH2 0x7AE JUMPI DUP1 PUSH4 0xF3B83791 EQ PUSH2 0x7CF JUMPI DUP1 PUSH4 0xF3F51415 EQ PUSH2 0x7E7 JUMPI DUP1 PUSH4 0xF9EAEE0D EQ PUSH2 0x808 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x206 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x829 JUMP JUMPDEST STOP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x22C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x838 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x250 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x955 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x283 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x4 CALLDATALOAD PUSH2 0xA18 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x29B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0xDC7 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x2BC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x2D4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0xDEF JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 ISZERO ISZERO DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x2F4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x24 CALLDATALOAD AND PUSH1 0x44 CALLDATALOAD PUSH2 0xE66 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x31E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0xED2 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x33F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0xF53 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x360 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x2D4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0xFDB JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x381 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0xFEE JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x3A5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x2D4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x24 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x44 SWAP1 PUSH1 0xA4 SWAP1 PUSH1 0xE4 CALLDATALOAD SWAP1 PUSH2 0x104 CALLDATALOAD AND PUSH2 0x112D JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x3DD JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x2D4 PUSH2 0x12FF JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x3F2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x2D4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x132C JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x416 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH2 0x1382 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x42B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x138B JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x44C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x455 PUSH2 0x140C JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 PUSH1 0xE0 PUSH1 0x2 EXP SUB NOT SWAP1 SWAP3 AND DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x47E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x2D4 PUSH1 0x4 CALLDATALOAD PUSH2 0x141A JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x496 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x24 CALLDATALOAD AND PUSH2 0x14D5 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x4BD JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x1584 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x4DE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x15A9 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x4FF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x1602 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x523 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x173F JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x544 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x54D PUSH2 0x17C0 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB SWAP1 SWAP3 AND DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x575 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x54D PUSH2 0x17F3 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x58A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x4 CALLDATALOAD PUSH2 0x1826 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x5A2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x5AB PUSH2 0x1B4C JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF SWAP5 DUP6 AND DUP2 MSTORE SWAP3 DUP5 AND PUSH1 0x20 DUP5 ADD MSTORE SWAP3 AND DUP2 DUP4 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x60 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x5E3 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x1B57 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x604 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 DUP1 MLOAD PUSH1 0x20 PUSH1 0x4 PUSH1 0x44 CALLDATALOAD DUP2 DUP2 ADD CALLDATALOAD PUSH1 0x1F DUP2 ADD DUP5 SWAP1 DIV DUP5 MUL DUP6 ADD DUP5 ADD SWAP1 SWAP6 MSTORE DUP5 DUP5 MSTORE PUSH2 0x2D4 SWAP5 DUP3 CALLDATALOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND SWAP5 PUSH1 0x24 DUP1 CALLDATALOAD SWAP6 CALLDATASIZE SWAP6 SWAP5 PUSH1 0x64 SWAP5 SWAP3 ADD SWAP2 SWAP1 DUP2 SWAP1 DUP5 ADD DUP4 DUP3 DUP1 DUP3 DUP5 CALLDATACOPY POP SWAP5 SWAP8 POP PUSH2 0x1BD8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x66D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x1C02 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x691 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x24 CALLDATALOAD AND PUSH1 0x44 CALLDATALOAD PUSH2 0x1CD8 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x6BB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x1CE3 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x6DC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH2 0x1D08 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x6F1 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x54D PUSH2 0x1D32 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x706 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x24 CALLDATALOAD AND PUSH2 0x1D65 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x72D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x2088 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x751 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x2169 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x772 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x218E JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x796 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x2273 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x7BA JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x2307 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x7DB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x4 CALLDATALOAD PUSH2 0x232C JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x7F3 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x2351 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x814 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x2D4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x23D4 JUMP JUMPDEST PUSH2 0x834 DUP3 CALLER DUP4 PUSH2 0x245A JUMP JUMPDEST POP POP JUMP JUMPDEST PUSH2 0x840 PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x854 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x85D DUP3 PUSH2 0xFDB JUMP JUMPDEST ISZERO ISZERO PUSH2 0x868 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 ISZERO DUP1 PUSH2 0x887 JUMPI POP PUSH1 0x0 DUP2 GT DUP1 ISZERO PUSH2 0x887 JUMPI POP PUSH2 0x884 DUP3 PUSH2 0x138B JUMP JUMPDEST DUP2 LT JUMPDEST ISZERO ISZERO PUSH2 0x892 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x0 DUP1 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x44A7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP2 MSTORE POP PUSH1 0x11 ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x913 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x8F4 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 KECCAK256 SWAP4 SWAP1 SWAP4 SSTORE POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xC3 PUSH1 0x2 EXP PUSH8 0xDAC2F0A0CAE4A8F MUL DUP2 MSTORE POP PUSH1 0x8 ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x9D7 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x9B8 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 KECCAK256 SLOAD SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0xA23 DUP3 PUSH2 0x265C JUMP JUMPDEST PUSH2 0xA2C DUP3 PUSH2 0x2744 JUMP JUMPDEST SWAP1 POP PUSH2 0xA37 DUP2 PUSH2 0x173F JUMP JUMPDEST DUP3 EQ ISZERO PUSH2 0x834 JUMPI PUSH1 0x0 DUP1 DUP3 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xB2 PUSH1 0x2 EXP PUSH10 0x19185A5B1E531A5B5A5D MUL DUP2 MSTORE POP PUSH1 0xA ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0xAC0 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0xAA1 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 DUP2 ADD SWAP7 SWAP1 SWAP7 MSTORE POP SWAP3 DUP4 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 DUP2 SWAP1 SSTORE DUP4 MLOAD PUSH1 0xC3 PUSH1 0x2 EXP PUSH8 0xDAC2F0A0CAE4A8F MUL DUP2 DUP8 ADD MSTORE PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND PUSH1 0x60 PUSH1 0x2 EXP MUL PUSH1 0x28 DUP3 ADD MSTORE DUP5 MLOAD DUP1 DUP3 SUB PUSH1 0x1C ADD DUP2 MSTORE PUSH1 0x3C SWAP1 SWAP2 ADD SWAP5 DUP6 SWAP1 MSTORE DUP1 MLOAD SWAP2 SWAP6 DUP7 SWAP6 SWAP2 SWAP5 POP SWAP1 SWAP3 POP DUP3 SWAP2 SWAP1 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0xB6F JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0xB50 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 DUP2 ADD SWAP7 SWAP1 SWAP7 MSTORE POP SWAP3 DUP4 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 DUP2 SWAP1 SSTORE DUP4 MLOAD PUSH1 0xC3 PUSH1 0x2 EXP PUSH8 0xDAD2DCA0CAE4A8F MUL DUP2 DUP8 ADD MSTORE PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND PUSH1 0x60 PUSH1 0x2 EXP MUL PUSH1 0x28 DUP3 ADD MSTORE DUP5 MLOAD DUP1 DUP3 SUB PUSH1 0x1C ADD DUP2 MSTORE PUSH1 0x3C SWAP1 SWAP2 ADD SWAP5 DUP6 SWAP1 MSTORE DUP1 MLOAD SWAP2 SWAP6 DUP7 SWAP6 SWAP2 SWAP5 POP SWAP1 SWAP3 POP DUP3 SWAP2 SWAP1 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0xC1E JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0xBFF JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 DUP2 ADD SWAP7 SWAP1 SWAP7 MSTORE POP SWAP3 DUP4 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 DUP2 SWAP1 SSTORE DUP4 MLOAD PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x42C7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP2 DUP8 ADD MSTORE PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND PUSH1 0x60 PUSH1 0x2 EXP MUL PUSH1 0x33 DUP3 ADD MSTORE DUP5 MLOAD DUP1 DUP3 SUB PUSH1 0x27 ADD DUP2 MSTORE PUSH1 0x47 SWAP1 SWAP2 ADD SWAP5 DUP6 SWAP1 MSTORE DUP1 MLOAD SWAP2 SWAP6 DUP7 SWAP6 SWAP2 SWAP5 POP SWAP1 SWAP3 POP DUP3 SWAP2 SWAP1 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0xCCD JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0xCAE JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 DUP2 ADD SWAP7 SWAP1 SWAP7 MSTORE POP SWAP3 DUP4 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 DUP2 SWAP1 SSTORE DUP4 MLOAD PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x44A7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP2 DUP8 ADD MSTORE PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND PUSH1 0x60 PUSH1 0x2 EXP MUL PUSH1 0x31 DUP3 ADD MSTORE DUP5 MLOAD DUP1 DUP3 SUB PUSH1 0x25 ADD DUP2 MSTORE PUSH1 0x45 SWAP1 SWAP2 ADD SWAP5 DUP6 SWAP1 MSTORE DUP1 MLOAD SWAP2 SWAP6 DUP7 SWAP6 SWAP2 SWAP5 POP SWAP1 SWAP3 POP DUP3 SWAP2 SWAP1 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0xD7C JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0xD5D JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 DUP2 SWAP1 SSTORE PUSH2 0x834 SWAP4 POP DUP5 SWAP3 POP SWAP1 POP PUSH2 0x2805 JUMP JUMPDEST PUSH2 0xDCF PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0xDE3 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xDEC DUP2 PUSH2 0x287B JUMP JUMPDEST POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH2 0xE13 DUP4 PUSH2 0xE07 DUP7 PUSH2 0xE02 PUSH2 0x1382 JUMP JUMPDEST PUSH2 0x1C02 JUMP JUMPDEST SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x28D5 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0xE21 PUSH1 0x0 PUSH2 0x2351 JUMP JUMPDEST GT DUP1 ISZERO PUSH2 0xE36 JUMPI POP DUP1 PUSH2 0xE33 DUP6 PUSH2 0x2351 JUMP JUMPDEST LT ISZERO JUMPDEST DUP1 ISZERO PUSH2 0xE4A JUMPI POP PUSH2 0xE46 DUP5 PUSH2 0x955 JUMP JUMPDEST DUP4 GT ISZERO JUMPDEST DUP1 ISZERO PUSH2 0xE5E JUMPI POP PUSH2 0xE5A DUP5 PUSH2 0x1B57 JUMP JUMPDEST DUP4 LT ISZERO JUMPDEST SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH2 0xE6E PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0xE82 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xE8A PUSH2 0x17C0 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH2 0xE9B PUSH2 0x28E2 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND EQ PUSH2 0xEAE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xEB7 DUP4 PUSH2 0xFDB JUMP JUMPDEST ISZERO ISZERO PUSH2 0xEC2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xECD DUP4 DUP4 DUP4 PUSH2 0x295A JUMP JUMPDEST POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x44A7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP2 MSTORE POP PUSH1 0x11 ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x9D7 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x9B8 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x88 PUSH1 0x2 EXP PUSH15 0x6D65646961746F7242616C616E6365 MUL DUP2 MSTORE POP PUSH1 0xF ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x9D7 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x9B8 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH2 0xFE7 DUP4 PUSH2 0x1B57 JUMP JUMPDEST GT SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH2 0xFF6 PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x100A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1013 DUP3 PUSH2 0xFDB JUMP JUMPDEST ISZERO ISZERO PUSH2 0x101E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1027 DUP3 PUSH2 0x955 JUMP JUMPDEST DUP2 GT DUP1 PUSH2 0x1032 JUMPI POP DUP1 ISZERO JUMPDEST ISZERO ISZERO PUSH2 0x103D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x0 DUP1 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xB2 PUSH1 0x2 EXP PUSH10 0x19185A5B1E531A5B5A5D MUL DUP2 MSTORE POP PUSH1 0xA ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x10C0 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x10A1 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 DUP2 ADD SWAP7 SWAP1 SWAP7 MSTORE POP SWAP3 DUP4 ADD PUSH1 0x0 KECCAK256 SWAP5 SWAP1 SWAP5 SSTORE POP DUP1 MLOAD DUP5 DUP2 MSTORE SWAP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP7 AND SWAP4 POP PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x42E7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SWAP3 SWAP2 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG2 POP POP JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x4 DUP2 MSTORE PUSH1 0x24 DUP2 ADD DUP3 MSTORE PUSH1 0x20 DUP2 ADD DUP1 MLOAD PUSH1 0x1 PUSH1 0xE0 PUSH1 0x2 EXP SUB AND PUSH1 0xE1 PUSH1 0x2 EXP PUSH4 0x37EF4101 MUL OR DUP2 MSTORE SWAP2 MLOAD DUP2 MLOAD PUSH1 0x0 SWAP4 ADDRESS SWAP4 SWAP3 SWAP2 DUP3 SWAP2 SWAP1 DUP1 DUP4 DUP4 DUP10 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1183 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x116B JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x11B0 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP2 POP POP PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP7 GAS CALL SWAP2 POP POP ISZERO DUP1 PUSH2 0x1242 JUMPI POP ADDRESS PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0x6FDE8202 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x120A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x121E JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1234 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ JUMPDEST DUP1 PUSH2 0x124C JUMPI POP CALLER ADDRESS EQ JUMPDEST ISZERO ISZERO PUSH2 0x1257 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x125F PUSH2 0x12FF JUMP JUMPDEST ISZERO PUSH2 0x1269 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1272 DUP8 PUSH2 0x287B JUMP JUMPDEST PUSH2 0x127B DUP7 PUSH2 0x2996 JUMP JUMPDEST PUSH2 0x12A9 PUSH1 0x0 DUP7 PUSH1 0x3 DUP1 PUSH1 0x20 MUL PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP3 SWAP2 SWAP1 DUP3 PUSH1 0x3 PUSH1 0x20 MUL DUP1 DUP3 DUP5 CALLDATACOPY POP PUSH2 0x29DC SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD DUP3 MSTORE PUSH2 0x12D2 SWAP2 PUSH1 0x0 SWAP2 SWAP1 DUP8 SWAP1 PUSH1 0x2 SWAP1 DUP4 SWAP1 DUP4 SWAP1 DUP1 DUP3 DUP5 CALLDATACOPY POP PUSH2 0x2C6C SWAP4 POP POP POP POP JUMP JUMPDEST PUSH2 0x12DB DUP4 PUSH2 0x2E09 JUMP JUMPDEST PUSH2 0x12E4 DUP3 PUSH2 0x2E46 JUMP JUMPDEST PUSH2 0x12EC PUSH2 0x2EEC JUMP JUMPDEST PUSH2 0x12F4 PUSH2 0x12FF JUMP JUMPDEST SWAP8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4387 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x4 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4307 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SLOAD PUSH1 0xFF AND SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH2 0x1344 DUP4 PUSH2 0xE07 DUP7 PUSH2 0x133F PUSH2 0x1382 JUMP JUMPDEST PUSH2 0x2273 JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x1352 PUSH1 0x0 PUSH2 0x138B JUMP JUMPDEST GT DUP1 ISZERO PUSH2 0x1367 JUMPI POP DUP1 PUSH2 0x1364 DUP6 PUSH2 0x138B JUMP JUMPDEST LT ISZERO JUMPDEST DUP1 ISZERO PUSH2 0xE5E JUMPI POP PUSH2 0x1377 DUP5 PUSH2 0xED2 JUMP JUMPDEST SWAP1 SWAP3 GT ISZERO SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH3 0x15180 TIMESTAMP DIV SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x42C7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP2 MSTORE POP PUSH1 0x13 ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x9D7 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x9B8 JUMP JUMPDEST PUSH1 0xE1 PUSH1 0x2 EXP PUSH4 0x58A8B613 MUL SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x4 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xA2 PUSH1 0x2 EXP PUSH12 0x1B595CDCD859D9519A5E1959 MUL DUP2 MSTORE POP PUSH1 0xC ADD DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x1491 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x1472 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 KECCAK256 SLOAD PUSH1 0xFF AND SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST ADDRESS PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0x6FDE8202 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1513 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x1527 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x153D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x1553 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP3 AND ISZERO DUP1 PUSH2 0x156F JUMPI POP PUSH2 0x156D DUP3 PUSH2 0xFDB JUMP JUMPDEST ISZERO JUMPDEST ISZERO ISZERO PUSH2 0x157A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x834 DUP3 DUP3 PUSH2 0x2F1F JUMP JUMPDEST PUSH2 0x158C PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x15A0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xDEC DUP2 PUSH2 0x2996 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x0 PUSH2 0x15BA DUP7 PUSH2 0x955 JUMP JUMPDEST SWAP4 POP PUSH2 0x15C5 DUP7 PUSH2 0x2351 JUMP JUMPDEST SWAP3 POP PUSH2 0x15D3 DUP7 PUSH2 0xE02 PUSH2 0x1382 JUMP JUMPDEST SWAP2 POP DUP2 DUP4 GT PUSH2 0x15E3 JUMPI PUSH1 0x0 PUSH2 0x15E7 JUMP JUMPDEST DUP2 DUP4 SUB JUMPDEST SWAP1 POP DUP1 DUP5 LT PUSH2 0x15F6 JUMPI DUP1 PUSH2 0x15F8 JUMP JUMPDEST DUP4 JUMPDEST SWAP7 SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH2 0x160A PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x161E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1627 DUP3 PUSH2 0xFDB JUMP JUMPDEST ISZERO ISZERO PUSH2 0x1632 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x163B DUP3 PUSH2 0xED2 JUMP JUMPDEST DUP2 GT DUP1 PUSH2 0x1646 JUMPI POP DUP1 ISZERO JUMPDEST ISZERO ISZERO PUSH2 0x1651 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x0 DUP1 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x42C7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP2 MSTORE POP PUSH1 0x13 ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x16D2 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x16B3 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 DUP2 ADD SWAP7 SWAP1 SWAP7 MSTORE POP SWAP3 DUP4 ADD PUSH1 0x0 KECCAK256 SWAP5 SWAP1 SWAP5 SSTORE POP DUP1 MLOAD DUP5 DUP2 MSTORE SWAP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP7 AND SWAP4 POP PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x43C7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SWAP3 SWAP2 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x44C7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP2 MSTORE POP PUSH1 0x1A ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x9D7 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x9B8 JUMP JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x43E7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x2 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4427 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4367 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x2 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4347 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x60 PUSH2 0x1832 PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0xCB08A10C DUP5 PUSH1 0x40 MLOAD DUP3 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1882 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x1896 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x18AC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD ISZERO PUSH2 0x18B8 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST ADDRESS PUSH2 0x18C1 PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0x3F9A8E7E DUP6 PUSH1 0x40 MLOAD DUP3 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1911 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x1925 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x193B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND EQ PUSH2 0x1950 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1958 PUSH2 0x17C0 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH2 0x1969 PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0x4A610B04 DUP6 PUSH1 0x40 MLOAD DUP3 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x19B9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x19CD JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x19E3 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND EQ PUSH2 0x19F8 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP POP PUSH1 0x40 DUP1 MLOAD PUSH1 0x24 DUP1 DUP3 ADD DUP5 SWAP1 MSTORE DUP3 MLOAD DUP1 DUP4 SUB SWAP1 SWAP2 ADD DUP2 MSTORE PUSH1 0x44 SWAP1 SWAP2 ADD SWAP1 SWAP2 MSTORE PUSH1 0x20 DUP2 ADD DUP1 MLOAD PUSH1 0x1 PUSH1 0xE0 PUSH1 0x2 EXP SUB AND PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x950D515 MUL SWAP1 DUP2 OR SWAP1 SWAP2 MSTORE SWAP1 PUSH2 0x1A41 PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0xDC8601B3 PUSH2 0x1A57 PUSH2 0x17C0 JUMP JUMPDEST DUP4 PUSH2 0x1A60 PUSH2 0x1D08 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP5 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP5 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH1 0x20 ADD DUP4 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP5 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1ACD JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x1AB5 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x1AFA JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP5 POP POP POP POP POP PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1B1B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x1B2F JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1B45 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP POP POP POP POP JUMP JUMPDEST PUSH1 0x1 PUSH1 0x2 PUSH1 0x0 SWAP1 SWAP2 SWAP3 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xC3 PUSH1 0x2 EXP PUSH8 0xDAD2DCA0CAE4A8F MUL DUP2 MSTORE POP PUSH1 0x8 ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x9D7 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x9B8 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH2 0x1BE3 PUSH2 0x2F58 JUMP JUMPDEST ISZERO ISZERO PUSH2 0x1BF7 JUMPI POP CALLER PUSH2 0x1BF7 DUP2 DUP7 DUP7 DUP7 PUSH2 0x2F85 JUMP JUMPDEST POP PUSH1 0x1 SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP5 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x80 PUSH1 0x2 EXP PUSH16 0x746F74616C5370656E74506572446179 MUL DUP2 MSTORE POP PUSH1 0x10 ADD DUP4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP3 POP POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x1C94 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x1C75 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 KECCAK256 SLOAD SWAP4 POP POP POP POP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH2 0xECD DUP4 DUP4 DUP4 PUSH2 0x245A JUMP JUMPDEST PUSH2 0x1CEB PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x1CFF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xDEC DUP2 PUSH2 0x33B9 JUMP JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4467 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x43A7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SLOAD SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4407 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x2 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4487 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x60 PUSH1 0x0 ADDRESS PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0x6FDE8202 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1DAD JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x1DC1 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1DD7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x1DED JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP7 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP2 AND ISZERO ISZERO PUSH2 0x1E03 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1E0C DUP10 PUSH2 0xFDB JUMP JUMPDEST ISZERO ISZERO PUSH2 0x1E17 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x70A08231 MUL DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP12 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1E62 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x1E76 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1E8C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP7 POP PUSH2 0x1E99 DUP10 PUSH2 0xF53 JUMP JUMPDEST SWAP6 POP DUP6 DUP8 GT PUSH2 0x1EA7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP6 DUP8 SUB SWAP5 POP PUSH2 0x1EB5 DUP10 PUSH2 0x15A9 JUMP JUMPDEST SWAP4 POP PUSH1 0x0 DUP5 GT PUSH2 0x1EC4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP4 DUP6 GT ISZERO PUSH2 0x1ED0 JUMPI DUP4 SWAP5 POP JUMPDEST PUSH2 0x1EE2 DUP10 PUSH2 0x1EDC PUSH2 0x1382 JUMP JUMPDEST DUP8 PUSH2 0x34E5 JUMP JUMPDEST PUSH2 0x1EFB DUP10 PUSH2 0x1EF6 DUP9 DUP9 PUSH4 0xFFFFFFFF PUSH2 0x28D5 AND JUMP JUMPDEST PUSH2 0x35C6 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP1 DUP13 AND PUSH1 0x24 DUP4 ADD MSTORE DUP11 AND PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 DUP1 DUP3 ADD DUP9 SWAP1 MSTORE DUP3 MLOAD DUP1 DUP4 SUB SWAP1 SWAP2 ADD DUP2 MSTORE PUSH1 0x84 SWAP1 SWAP2 ADD SWAP1 SWAP2 MSTORE PUSH1 0x20 DUP2 ADD DUP1 MLOAD PUSH1 0x1 PUSH1 0xE0 PUSH1 0x2 EXP SUB AND PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x125E4CFB MUL OR SWAP1 MSTORE SWAP3 POP PUSH2 0x1F57 PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0xDC8601B3 PUSH2 0x1F6D PUSH2 0x17C0 JUMP JUMPDEST DUP6 PUSH2 0x1F76 PUSH2 0x1D08 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP5 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP5 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH1 0x20 ADD DUP4 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP5 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1FE3 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x1FCB JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x2010 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP5 POP POP POP POP POP PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x2031 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x2045 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x205B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP2 POP PUSH2 0x2069 DUP3 DUP11 PUSH2 0x364D JUMP JUMPDEST PUSH2 0x2073 DUP3 DUP7 PUSH2 0x3720 JUMP JUMPDEST PUSH2 0x207D DUP3 DUP10 PUSH2 0x3794 JUMP JUMPDEST POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH2 0x2090 PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x20A4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x20AD DUP3 PUSH2 0xFDB JUMP JUMPDEST ISZERO ISZERO PUSH2 0x20B8 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 ISZERO DUP1 PUSH2 0x20DE JUMPI POP PUSH2 0x20C9 DUP3 PUSH2 0x1B57 JUMP JUMPDEST DUP2 GT DUP1 ISZERO PUSH2 0x20DE JUMPI POP PUSH2 0x20DB DUP3 PUSH2 0x2351 JUMP JUMPDEST DUP2 LT JUMPDEST ISZERO ISZERO PUSH2 0x20E9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x0 DUP1 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xC3 PUSH1 0x2 EXP PUSH8 0xDAC2F0A0CAE4A8F MUL DUP2 MSTORE POP PUSH1 0x8 ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x913 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x8F4 JUMP JUMPDEST PUSH2 0x2171 PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x2185 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xDEC DUP2 PUSH2 0x380D JUMP JUMPDEST PUSH2 0x2196 PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x21AA JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x21B3 DUP3 PUSH2 0xFDB JUMP JUMPDEST ISZERO ISZERO PUSH2 0x21BE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 DUP2 GT DUP1 ISZERO PUSH2 0x21D5 JUMPI POP PUSH2 0x21D2 DUP3 PUSH2 0x2351 JUMP JUMPDEST DUP2 LT JUMPDEST DUP1 ISZERO PUSH2 0x21E8 JUMPI POP PUSH2 0x21E5 DUP3 PUSH2 0x955 JUMP JUMPDEST DUP2 LT JUMPDEST ISZERO ISZERO PUSH2 0x21F3 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x0 DUP1 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xC3 PUSH1 0x2 EXP PUSH8 0xDAD2DCA0CAE4A8F MUL DUP2 MSTORE POP PUSH1 0x8 ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x913 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x8F4 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP5 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x68 PUSH1 0x2 EXP PUSH19 0x746F74616C4578656375746564506572446179 MUL DUP2 MSTORE POP PUSH1 0x13 ADD DUP4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP3 POP POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x1C94 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x1C75 JUMP JUMPDEST PUSH2 0x230F PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x2323 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xDEC DUP2 PUSH2 0x2E46 JUMP JUMPDEST PUSH2 0x2334 PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x2348 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xDEC DUP2 PUSH2 0x2E09 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xB2 PUSH1 0x2 EXP PUSH10 0x19185A5B1E531A5B5A5D MUL DUP2 MSTORE POP PUSH1 0xA ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x9D7 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x9B8 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x4 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xA2 PUSH1 0x2 EXP PUSH12 0x1D1BDAD95B905B1B1BDDD959 MUL DUP2 MSTORE POP PUSH1 0xC ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x1491 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x1472 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH2 0x2465 PUSH2 0x2F58 JUMP JUMPDEST ISZERO PUSH2 0x246F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x70A08231 MUL DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x24BA JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x24CE JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x24E4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP2 POP PUSH2 0x24F2 PUSH1 0x1 PUSH2 0x393A JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x23B872DD MUL DUP2 MSTORE CALLER PUSH1 0x4 DUP3 ADD MSTORE ADDRESS PUSH1 0x24 DUP3 ADD MSTORE PUSH1 0x44 DUP2 ADD DUP6 SWAP1 MSTORE SWAP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND SWAP2 PUSH4 0x23B872DD SWAP2 PUSH1 0x64 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x254A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x255E JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x2574 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x2581 SWAP1 POP PUSH1 0x0 PUSH2 0x393A JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x70A08231 MUL DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD PUSH2 0x260A SWAP2 DUP5 SWAP2 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP10 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x25D2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x25E6 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x25FC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x3971 AND JUMP JUMPDEST SWAP1 POP DUP3 DUP2 GT ISZERO PUSH2 0x2619 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1B45 DUP6 CALLER DUP4 DUP8 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH2 0x2F85 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 PUSH2 0x2669 PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x267D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x2685 PUSH2 0x17C0 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH2 0x2696 PUSH2 0x28E2 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND EQ PUSH2 0x26A9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x26B2 DUP5 PUSH2 0x141A JUMP JUMPDEST ISZERO PUSH2 0x26BC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x26C5 DUP5 PUSH2 0x2744 JUMP JUMPDEST SWAP3 POP PUSH2 0x26D0 DUP5 PUSH2 0x3983 JUMP JUMPDEST SWAP2 POP PUSH2 0x26DB DUP5 PUSH2 0x39FD JUMP JUMPDEST SWAP1 POP PUSH2 0x26E6 DUP5 PUSH2 0x3A72 JUMP JUMPDEST PUSH2 0x26F1 DUP4 DUP4 DUP4 PUSH2 0x3B36 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP1 DUP7 AND DUP3 MSTORE DUP5 AND PUSH1 0x20 DUP3 ADD MSTORE DUP1 DUP3 ADD DUP4 SWAP1 MSTORE SWAP1 MLOAD DUP6 SWAP2 PUSH32 0x7B5483B8E4BD8EA240A474D5117738350E7D431E3668C48A97910B0B397796A SWAP2 SWAP1 DUP2 SWAP1 SUB PUSH1 0x60 ADD SWAP1 LOG2 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x2 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xA1 PUSH1 0x2 EXP PUSH12 0x36B2B9B9B0B3B2AA37B5B2B7 MUL DUP2 MSTORE POP PUSH1 0xC ADD DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x27BB JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x279C JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 KECCAK256 SLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x44C7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x20 DUP1 DUP4 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x60 PUSH1 0x2 EXP PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP7 AND MUL PUSH1 0x3A DUP4 ADD MSTORE DUP3 MLOAD PUSH1 0x2E DUP2 DUP5 SUB ADD DUP2 MSTORE PUSH1 0x4E SWAP1 SWAP3 ADD SWAP3 DUP4 SWAP1 MSTORE DUP2 MLOAD DUP5 SWAP4 PUSH1 0x0 SWAP4 DUP5 SWAP4 SWAP1 SWAP3 DUP3 SWAP2 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x913 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x8F4 JUMP JUMPDEST PUSH2 0x2884 DUP2 PUSH2 0x3B6D JUMP JUMPDEST ISZERO ISZERO PUSH2 0x288F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4407 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x2 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4487 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP1 SLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB NOT AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB SWAP3 SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE JUMP JUMPDEST DUP2 DUP2 ADD DUP3 DUP2 LT ISZERO PUSH2 0x1CD2 JUMPI INVALID JUMPDEST PUSH1 0x0 PUSH2 0x28EC PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0xD67BDD25 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x2929 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x293D JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x2953 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP1 POP SWAP1 JUMP JUMPDEST PUSH2 0x2964 DUP4 DUP3 PUSH2 0x132C JUMP JUMPDEST ISZERO PUSH2 0x298B JUMPI PUSH2 0x297B DUP4 PUSH2 0x2975 PUSH2 0x1382 JUMP JUMPDEST DUP4 PUSH2 0x3B75 JUMP JUMPDEST PUSH2 0x2986 DUP4 DUP4 DUP4 PUSH2 0x3C15 JUMP JUMPDEST PUSH2 0xECD JUMP JUMPDEST PUSH2 0xECD DUP4 DUP4 DUP4 PUSH2 0x1F5 JUMP JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x43E7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x2 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4427 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP1 SLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB NOT AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB SWAP3 SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE JUMP JUMPDEST PUSH1 0x40 DUP2 ADD MLOAD PUSH1 0x0 LT DUP1 ISZERO PUSH2 0x29F7 JUMPI POP PUSH1 0x40 DUP2 ADD MLOAD PUSH1 0x20 DUP3 ADD MLOAD GT JUMPDEST DUP1 ISZERO PUSH2 0x2A07 JUMPI POP PUSH1 0x20 DUP2 ADD MLOAD DUP2 MLOAD GT JUMPDEST ISZERO ISZERO PUSH2 0x2A12 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 MLOAD PUSH1 0x40 DUP1 MLOAD PUSH1 0xB2 PUSH1 0x2 EXP PUSH10 0x19185A5B1E531A5B5A5D MUL PUSH1 0x20 DUP3 DUP2 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x60 PUSH1 0x2 EXP PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND MUL PUSH1 0x2A DUP4 ADD MSTORE DUP3 MLOAD PUSH1 0x1E DUP2 DUP5 SUB ADD DUP2 MSTORE PUSH1 0x3E SWAP1 SWAP3 ADD SWAP3 DUP4 SWAP1 MSTORE DUP2 MLOAD PUSH1 0x0 SWAP4 DUP5 SWAP4 SWAP3 SWAP1 SWAP2 DUP3 SWAP2 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x2A8C JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x2A6D JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 DUP2 ADD SWAP7 SWAP1 SWAP7 MSTORE POP SWAP3 DUP4 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 SWAP6 SWAP1 SWAP6 SSTORE POP POP DUP4 DUP3 ADD MLOAD DUP2 MLOAD PUSH1 0xC3 PUSH1 0x2 EXP PUSH8 0xDAC2F0A0CAE4A8F MUL DUP2 DUP6 ADD MSTORE PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND PUSH1 0x60 PUSH1 0x2 EXP MUL PUSH1 0x28 DUP3 ADD MSTORE DUP3 MLOAD DUP1 DUP3 SUB PUSH1 0x1C ADD DUP2 MSTORE PUSH1 0x3C SWAP1 SWAP2 ADD SWAP3 DUP4 SWAP1 MSTORE DUP1 MLOAD SWAP2 SWAP5 SWAP4 DUP5 SWAP4 SWAP2 SWAP3 DUP3 SWAP2 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x2B3E JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x2B1F JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 DUP2 ADD SWAP7 SWAP1 SWAP7 MSTORE POP SWAP3 DUP4 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 SWAP6 SWAP1 SWAP6 SSTORE POP POP DUP4 DUP2 ADD MLOAD DUP2 MLOAD PUSH1 0xC3 PUSH1 0x2 EXP PUSH8 0xDAD2DCA0CAE4A8F MUL DUP2 DUP6 ADD MSTORE PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND PUSH1 0x60 PUSH1 0x2 EXP MUL PUSH1 0x28 DUP3 ADD MSTORE DUP3 MLOAD DUP1 DUP3 SUB PUSH1 0x1C ADD DUP2 MSTORE PUSH1 0x3C SWAP1 SWAP2 ADD SWAP3 DUP4 SWAP1 MSTORE DUP1 MLOAD SWAP2 SWAP5 SWAP4 DUP5 SWAP4 SWAP2 SWAP3 DUP3 SWAP2 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x2BF0 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x2BD1 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 SWAP5 SWAP1 SWAP5 SSTORE POP POP POP PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP4 AND SWAP1 PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x42E7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SWAP1 DUP4 SWAP1 JUMPDEST PUSH1 0x20 MUL ADD MLOAD PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG2 POP POP JUMP JUMPDEST DUP1 MLOAD PUSH1 0x20 DUP3 ADD MLOAD LT PUSH2 0x2C7D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 MLOAD PUSH1 0x40 DUP1 MLOAD PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x42C7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x20 DUP3 DUP2 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x60 PUSH1 0x2 EXP PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND MUL PUSH1 0x33 DUP4 ADD MSTORE DUP3 MLOAD PUSH1 0x27 DUP2 DUP5 SUB ADD DUP2 MSTORE PUSH1 0x47 SWAP1 SWAP3 ADD SWAP3 DUP4 SWAP1 MSTORE DUP2 MLOAD PUSH1 0x0 SWAP4 DUP5 SWAP4 SWAP3 SWAP1 SWAP2 DUP3 SWAP2 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x2CF5 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x2CD6 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 DUP2 ADD SWAP7 SWAP1 SWAP7 MSTORE POP SWAP3 DUP4 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 SWAP6 SWAP1 SWAP6 SSTORE POP POP DUP4 DUP3 ADD MLOAD DUP2 MLOAD PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x44A7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP2 DUP6 ADD MSTORE PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND PUSH1 0x60 PUSH1 0x2 EXP MUL PUSH1 0x31 DUP3 ADD MSTORE DUP3 MLOAD DUP1 DUP3 SUB PUSH1 0x25 ADD DUP2 MSTORE PUSH1 0x45 SWAP1 SWAP2 ADD SWAP3 DUP4 SWAP1 MSTORE DUP1 MLOAD SWAP2 SWAP5 SWAP4 DUP5 SWAP4 SWAP2 SWAP3 DUP3 SWAP2 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x2DA7 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x2D88 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 SWAP5 SWAP1 SWAP5 SSTORE POP POP POP PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP4 AND SWAP1 PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x43C7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SWAP1 DUP4 SWAP1 PUSH2 0x2C4E JUMP JUMPDEST PUSH2 0x2E11 PUSH2 0x3C98 JUMP JUMPDEST DUP2 GT ISZERO PUSH2 0x2E1D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4467 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x43A7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SSTORE JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP2 AND ISZERO ISZERO PUSH2 0x2E5B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH32 0x8BE0079C531659141344CD1FD0A4F28419497F9722A3DAAFE3B4186F6B6457E0 PUSH2 0x2E84 PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB SWAP3 DUP4 AND DUP2 MSTORE SWAP2 DUP5 AND PUSH1 0x20 DUP4 ADD MSTORE DUP1 MLOAD SWAP2 DUP3 SWAP1 SUB ADD SWAP1 LOG1 PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4367 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x2 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4347 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP1 SLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB NOT AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB SWAP3 SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE JUMP JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4387 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x4 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4307 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP1 SLOAD PUSH1 0xFF NOT AND PUSH1 0x1 OR SWAP1 SSTORE JUMP JUMPDEST DUP1 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP2 AND ISZERO ISZERO PUSH2 0x2F35 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP4 AND ISZERO ISZERO PUSH2 0x2F4E JUMPI PUSH2 0x2986 DUP3 PUSH2 0x3CDF JUMP JUMPDEST PUSH2 0xECD DUP4 DUP4 PUSH2 0x3CEB JUMP JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4447 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x4 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4327 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SLOAD PUSH1 0xFF AND SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x60 DUP1 PUSH1 0x0 PUSH1 0x60 PUSH1 0x0 DUP1 PUSH2 0x2F99 PUSH2 0x2F58 JUMP JUMPDEST ISZERO PUSH2 0x2FA3 JUMPI PUSH2 0x33AC JUMP JUMPDEST PUSH2 0x2FAC DUP12 PUSH2 0x23D4 JUMP JUMPDEST ISZERO ISZERO PUSH2 0x2FB7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x2FC0 DUP12 PUSH2 0xFDB JUMP JUMPDEST SWAP7 POP DUP7 ISZERO ISZERO PUSH2 0x3013 JUMPI PUSH2 0x2FD2 DUP12 PUSH2 0x3D88 JUMP JUMPDEST SWAP6 POP PUSH2 0x2FDD DUP12 PUSH2 0x3E6D JUMP JUMPDEST SWAP5 POP PUSH2 0x2FE8 DUP12 PUSH2 0x3EC3 JUMP JUMPDEST SWAP4 POP PUSH1 0x0 DUP7 MLOAD GT DUP1 PUSH2 0x2FFB JUMPI POP PUSH1 0x0 DUP6 MLOAD GT JUMPDEST ISZERO ISZERO PUSH2 0x3006 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x3013 DUP12 DUP6 PUSH1 0xFF AND PUSH2 0x3F15 JUMP JUMPDEST PUSH2 0x301D DUP12 DUP11 PUSH2 0xDEF JUMP JUMPDEST ISZERO ISZERO PUSH2 0x3028 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x303A DUP12 PUSH2 0x3034 PUSH2 0x1382 JUMP JUMPDEST DUP12 PUSH2 0x34E5 JUMP JUMPDEST PUSH2 0x3044 DUP11 DUP10 PUSH2 0x40AB JUMP JUMPDEST SWAP2 POP DUP7 ISZERO PUSH2 0x30A5 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP1 DUP15 AND PUSH1 0x24 DUP4 ADD MSTORE DUP5 AND PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 DUP1 DUP3 ADD DUP13 SWAP1 MSTORE DUP3 MLOAD DUP1 DUP4 SUB SWAP1 SWAP2 ADD DUP2 MSTORE PUSH1 0x84 SWAP1 SWAP2 ADD SWAP1 SWAP2 MSTORE PUSH1 0x20 DUP2 ADD DUP1 MLOAD PUSH1 0x1 PUSH1 0xE0 PUSH1 0x2 EXP SUB AND PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x125E4CFB MUL OR SWAP1 MSTORE SWAP3 POP PUSH2 0x3215 JUMP JUMPDEST ADDRESS PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0x2AE87CDD SWAP1 POP PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP12 DUP8 DUP8 DUP8 DUP7 DUP15 PUSH1 0x40 MLOAD PUSH1 0x24 ADD DUP1 DUP8 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH1 0x20 ADD DUP1 PUSH1 0x20 ADD DUP7 PUSH1 0xFF AND PUSH1 0xFF AND DUP2 MSTORE PUSH1 0x20 ADD DUP6 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND DUP2 MSTORE PUSH1 0x20 ADD DUP5 DUP2 MSTORE PUSH1 0x20 ADD DUP4 DUP2 SUB DUP4 MSTORE DUP9 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x3148 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x3130 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x3175 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP DUP4 DUP2 SUB DUP3 MSTORE DUP8 MLOAD DUP2 MSTORE DUP8 MLOAD PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 DUP10 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x31A8 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x3190 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x31D5 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP PUSH1 0x40 DUP1 MLOAD PUSH1 0x1F NOT DUP2 DUP5 SUB ADD DUP2 MSTORE SWAP2 SWAP1 MSTORE PUSH1 0x20 DUP2 ADD DUP1 MLOAD PUSH1 0x1 PUSH1 0xE0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xE0 PUSH1 0x2 EXP SUB NOT SWAP1 SWAP13 AND SWAP12 SWAP1 SWAP12 OR SWAP1 SWAP11 MSTORE POP SWAP8 SWAP11 POP POP POP POP POP POP POP POP POP JUMPDEST PUSH2 0x3226 DUP12 PUSH2 0x1EF6 DUP12 PUSH2 0xE07 DUP16 PUSH2 0xF53 JUMP JUMPDEST PUSH2 0x322E PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0xDC8601B3 PUSH2 0x3244 PUSH2 0x17C0 JUMP JUMPDEST DUP6 PUSH2 0x324D PUSH2 0x1D08 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP5 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP5 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH1 0x20 ADD DUP4 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP5 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x32BA JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x32A2 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x32E7 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP5 POP POP POP POP POP PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x3308 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x331C JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x3332 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP1 POP PUSH2 0x3340 DUP2 DUP13 PUSH2 0x364D JUMP JUMPDEST PUSH2 0x334A DUP2 DUP11 PUSH2 0x3720 JUMP JUMPDEST PUSH2 0x3354 DUP2 DUP12 PUSH2 0x3794 JUMP JUMPDEST DUP7 ISZERO ISZERO PUSH2 0x3365 JUMPI PUSH2 0x3365 DUP12 DUP3 PUSH2 0x2805 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP11 DUP2 MSTORE SWAP1 MLOAD DUP3 SWAP2 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP1 DUP15 AND SWAP3 SWAP1 DUP16 AND SWAP2 PUSH32 0x59A9A8027B9C87B961E254899821C9A276B5EFC35D1F7409EA4F291470F1629A SWAP2 SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 LOG4 JUMPDEST POP POP POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH2 0x33C2 DUP2 PUSH2 0x23D4 JUMP JUMPDEST ISZERO PUSH2 0x33CC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x33D5 DUP2 PUSH2 0x3B6D JUMP JUMPDEST ISZERO ISZERO PUSH2 0x33E0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x1 PUSH1 0x4 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xA2 PUSH1 0x2 EXP PUSH12 0x1D1BDAD95B905B1B1BDDD959 MUL DUP2 MSTORE POP PUSH1 0xC ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x3467 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x3448 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 DUP4 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 DUP1 SLOAD PUSH1 0xFF NOT AND SWAP7 ISZERO ISZERO SWAP7 SWAP1 SWAP7 OR SWAP1 SWAP6 SSTORE POP POP MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP5 AND SWAP3 PUSH32 0xBECEB48AEAA805AEAE57BE163CCA6249077A18734E408A85AA74E875C4373809 SWAP3 POP SWAP1 LOG2 POP JUMP JUMPDEST PUSH2 0x34F3 DUP2 PUSH2 0xE07 DUP6 DUP6 PUSH2 0x1C02 JUMP JUMPDEST PUSH1 0x0 DUP1 DUP6 DUP6 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x80 PUSH1 0x2 EXP PUSH16 0x746F74616C5370656E74506572446179 MUL DUP2 MSTORE POP PUSH1 0x10 ADD DUP4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP3 POP POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x3583 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x3564 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 KECCAK256 SWAP4 SWAP1 SWAP4 SSTORE POP POP POP POP POP POP JUMP JUMPDEST DUP1 PUSH1 0x0 DUP1 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x88 PUSH1 0x2 EXP PUSH15 0x6D65646961746F7242616C616E6365 MUL DUP2 MSTORE POP PUSH1 0xF ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x913 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x8F4 JUMP JUMPDEST DUP1 PUSH1 0x2 PUSH1 0x0 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xA1 PUSH1 0x2 EXP PUSH12 0x36B2B9B9B0B3B2AA37B5B2B7 MUL DUP2 MSTORE POP PUSH1 0xC ADD DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x36C3 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x36A4 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 KECCAK256 DUP1 SLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB NOT AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB SWAP6 SWAP1 SWAP6 AND SWAP5 SWAP1 SWAP5 OR SWAP1 SWAP4 SSTORE POP POP POP POP POP JUMP JUMPDEST DUP1 PUSH1 0x0 DUP1 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xA0 PUSH1 0x2 EXP PUSH12 0x6D65737361676556616C7565 MUL DUP2 MSTORE POP PUSH1 0xC ADD DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x913 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x8F4 JUMP JUMPDEST DUP1 PUSH1 0x2 PUSH1 0x0 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x82 PUSH1 0x2 EXP PUSH16 0x1B595CDCD859D9549958DA5C1A595B9D MUL DUP2 MSTORE POP PUSH1 0x10 ADD DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x36C3 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x36A4 JUMP JUMPDEST PUSH2 0x3816 DUP2 PUSH2 0x23D4 JUMP JUMPDEST ISZERO ISZERO PUSH2 0x3821 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x382A DUP2 PUSH2 0x3B6D JUMP JUMPDEST ISZERO ISZERO PUSH2 0x3835 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 PUSH1 0x4 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xA2 PUSH1 0x2 EXP PUSH12 0x1D1BDAD95B905B1B1BDDD959 MUL DUP2 MSTORE POP PUSH1 0xC ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x38BC JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x389D JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 DUP4 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 DUP1 SLOAD PUSH1 0xFF NOT AND SWAP7 ISZERO ISZERO SWAP7 SWAP1 SWAP7 OR SWAP1 SWAP6 SSTORE POP POP MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP5 AND SWAP3 PUSH32 0xEAA9136602E3B70A4E689B5B6F55BDA25CA62B917D839C0FF87F5902387F77B9 SWAP3 POP SWAP1 LOG2 POP JUMP JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4447 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x4 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4327 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP1 SLOAD PUSH1 0xFF NOT AND SWAP2 ISZERO ISZERO SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE JUMP JUMPDEST PUSH1 0x0 DUP3 DUP3 GT ISZERO PUSH2 0x397D JUMPI INVALID JUMPDEST POP SWAP1 SUB SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x2 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x82 PUSH1 0x2 EXP PUSH16 0x1B595CDCD859D9549958DA5C1A595B9D MUL DUP2 MSTORE POP PUSH1 0x10 ADD DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x27BB JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x279C JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xA0 PUSH1 0x2 EXP PUSH12 0x6D65737361676556616C7565 MUL DUP2 MSTORE POP PUSH1 0xC ADD DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x9D7 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x9B8 JUMP JUMPDEST PUSH1 0x1 PUSH1 0x4 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xA2 PUSH1 0x2 EXP PUSH12 0x1B595CDCD859D9519A5E1959 MUL DUP2 MSTORE POP PUSH1 0xC ADD DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x3AE9 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x3ACA JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 KECCAK256 DUP1 SLOAD PUSH1 0xFF NOT AND SWAP5 ISZERO ISZERO SWAP5 SWAP1 SWAP5 OR SWAP1 SWAP4 SSTORE POP POP POP POP JUMP JUMPDEST PUSH2 0x3B53 DUP4 PUSH2 0x1EF6 DUP4 PUSH2 0x3B47 DUP8 PUSH2 0xF53 JUMP JUMPDEST SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x3971 AND JUMP JUMPDEST PUSH2 0xECD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP5 AND DUP4 DUP4 PUSH4 0xFFFFFFFF PUSH2 0x4105 AND JUMP JUMPDEST PUSH1 0x0 SWAP1 EXTCODESIZE GT SWAP1 JUMP JUMPDEST PUSH2 0x3B83 DUP2 PUSH2 0xE07 DUP6 DUP6 PUSH2 0x2273 JUMP JUMPDEST PUSH1 0x0 DUP1 DUP6 DUP6 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x68 PUSH1 0x2 EXP PUSH19 0x746F74616C4578656375746564506572446179 MUL DUP2 MSTORE POP PUSH1 0x13 ADD DUP4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP3 POP POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x3583 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x3564 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x3C1F PUSH2 0x419A JUMP JUMPDEST SWAP1 POP PUSH2 0x3C3B PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP6 AND DUP5 DUP5 PUSH4 0xFFFFFFFF PUSH2 0x4105 AND JUMP JUMPDEST PUSH2 0x3C4C DUP5 PUSH2 0x1EF6 DUP5 PUSH2 0x3B47 DUP9 PUSH2 0xF53 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP4 DUP2 MSTORE SWAP1 MLOAD DUP3 SWAP2 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP1 DUP8 AND SWAP3 SWAP1 DUP9 AND SWAP2 PUSH32 0x9AFD47907E25028CDACA89D193518C302BBB128617D5A992C5ABD45815526593 SWAP2 SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 LOG4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x3CA2 PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0xE5789D03 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x2929 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST ADDRESS BALANCE PUSH2 0x834 DUP3 DUP3 PUSH2 0x41E1 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x70A08231 MUL DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD DUP4 SWAP2 PUSH1 0x0 SWAP2 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP5 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP8 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x3D3A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x3D4E JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x3D64 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP1 POP PUSH2 0x3D82 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP6 AND DUP5 DUP4 PUSH4 0xFFFFFFFF PUSH2 0x4105 AND JUMP JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x6FDDE03 MUL DUP2 MSTORE PUSH1 0x60 SWAP1 PUSH1 0x0 DUP3 PUSH1 0x20 DUP4 PUSH1 0x4 DUP2 DUP9 GAS STATICCALL ISZERO ISZERO PUSH2 0x3DC5 JUMPI PUSH1 0xE1 PUSH1 0x2 EXP PUSH4 0x51FA6FBF MUL DUP4 MSTORE PUSH1 0x20 DUP4 PUSH1 0x4 DUP6 DUP9 GAS STATICCALL POP JUMPDEST RETURNDATASIZE DUP4 ADD PUSH1 0x40 MSTORE PUSH1 0x20 RETURNDATASIZE GT PUSH1 0x1 DUP2 EQ PUSH2 0x3DDF JUMPI RETURNDATASIZE SWAP3 POP PUSH2 0x3DED JUMP JUMPDEST PUSH1 0x20 DUP1 PUSH1 0x40 MLOAD RETURNDATACOPY PUSH1 0x40 MLOAD MLOAD SWAP3 POP JUMPDEST POP DUP2 PUSH1 0x40 MLOAD SWAP1 DUP1 DUP3 MSTORE DUP1 PUSH1 0x1F ADD PUSH1 0x1F NOT AND PUSH1 0x20 ADD DUP3 ADD PUSH1 0x40 MSTORE DUP1 ISZERO PUSH2 0x3E1C JUMPI DUP2 PUSH1 0x20 ADD PUSH1 0x20 DUP3 MUL DUP1 CODESIZE DUP4 CODECOPY ADD SWAP1 POP JUMPDEST POP SWAP1 POP PUSH1 0x20 RETURNDATASIZE GT ISZERO PUSH2 0x3E35 JUMPI DUP2 PUSH1 0x40 PUSH1 0x20 DUP4 ADD RETURNDATACOPY PUSH2 0xE5E JUMP JUMPDEST PUSH1 0x0 RETURNDATASIZE GT ISZERO PUSH2 0xE5E JUMPI PUSH1 0x0 DUP4 MLOAD SWAP4 POP DUP4 PUSH1 0x20 DUP4 ADD MSTORE JUMPDEST PUSH1 0x0 DUP5 GT ISZERO PUSH2 0x3E63 JUMPI PUSH1 0x8 SWAP4 SWAP1 SWAP4 SHL SWAP3 PUSH1 0x1 ADD PUSH2 0x3E4B JUMP JUMPDEST DUP2 MSTORE SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x95D89B41 MUL DUP2 MSTORE PUSH1 0x60 SWAP1 PUSH1 0x0 DUP3 PUSH1 0x20 DUP4 PUSH1 0x4 DUP2 DUP9 GAS STATICCALL ISZERO ISZERO PUSH2 0x3DC5 JUMPI PUSH1 0xE3 PUSH1 0x2 EXP PUSH4 0x1EEDF1AF MUL DUP4 MSTORE PUSH1 0x20 DUP4 PUSH1 0x4 DUP6 DUP9 GAS STATICCALL POP RETURNDATASIZE DUP4 ADD PUSH1 0x40 MSTORE PUSH1 0x20 RETURNDATASIZE GT PUSH1 0x1 DUP2 EQ PUSH2 0x3DDF JUMPI RETURNDATASIZE SWAP3 POP PUSH2 0x3DED JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 ADD PUSH1 0x40 MSTORE PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x313CE567 MUL DUP2 MSTORE PUSH1 0x20 DUP2 PUSH1 0x4 DUP4 DUP8 GAS STATICCALL ISZERO ISZERO PUSH2 0x3F0D JUMPI PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x2E0F2625 MUL DUP2 MSTORE PUSH1 0x20 DUP2 PUSH1 0x4 DUP4 DUP8 GAS STATICCALL ISZERO ISZERO PUSH2 0x3F0D JUMPI PUSH1 0x0 DUP2 MSTORE JUMPDEST MLOAD SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x12 DUP8 LT ISZERO PUSH2 0x400A JUMPI DUP7 PUSH1 0x12 SUB PUSH1 0xA EXP SWAP6 POP PUSH2 0x3F4A DUP7 PUSH2 0x3F3E PUSH1 0x0 PUSH2 0x1B57 JUMP JUMPDEST SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x4242 AND JUMP JUMPDEST SWAP5 POP PUSH2 0x3F5A DUP7 PUSH2 0x3F3E PUSH1 0x0 PUSH2 0x955 JUMP JUMPDEST SWAP4 POP PUSH2 0x3F6A DUP7 PUSH2 0x3F3E PUSH1 0x0 PUSH2 0x2351 JUMP JUMPDEST SWAP3 POP PUSH2 0x3F7A DUP7 PUSH2 0x3F3E PUSH1 0x0 PUSH2 0xED2 JUMP JUMPDEST SWAP2 POP PUSH2 0x3F8A DUP7 PUSH2 0x3F3E PUSH1 0x0 PUSH2 0x138B JUMP JUMPDEST SWAP1 POP DUP5 ISZERO ISZERO PUSH2 0x3FC2 JUMPI PUSH1 0x1 SWAP5 POP DUP5 DUP5 GT PUSH2 0x3FC2 JUMPI PUSH1 0x64 SWAP4 POP PUSH1 0x64 SWAP2 POP DUP4 DUP4 GT ISZERO DUP1 PUSH2 0x3FB5 JUMPI POP DUP2 DUP2 GT ISZERO JUMPDEST ISZERO PUSH2 0x3FC2 JUMPI POP PUSH2 0x2710 SWAP2 POP DUP2 JUMPDEST PUSH2 0x3FE7 DUP9 PUSH1 0x60 PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 DUP7 DUP2 MSTORE PUSH1 0x20 ADD DUP8 DUP2 MSTORE PUSH1 0x20 ADD DUP9 DUP2 MSTORE POP PUSH2 0x29DC JUMP JUMPDEST PUSH2 0x4005 DUP9 PUSH1 0x40 DUP1 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 DUP5 DUP2 MSTORE PUSH1 0x20 ADD DUP6 DUP2 MSTORE POP PUSH2 0x2C6C JUMP JUMPDEST PUSH2 0x40A1 JUMP JUMPDEST PUSH1 0x12 DUP8 SUB PUSH1 0xA EXP SWAP6 POP PUSH2 0x406A DUP9 PUSH1 0x60 PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 PUSH2 0x403D DUP11 PUSH2 0x4031 PUSH1 0x0 PUSH2 0x2351 JUMP JUMPDEST SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x4257 AND JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x4050 DUP11 PUSH2 0x4031 PUSH1 0x0 PUSH2 0x955 JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x4063 DUP11 PUSH2 0x4031 PUSH1 0x0 PUSH2 0x1B57 JUMP JUMPDEST SWAP1 MSTORE PUSH2 0x29DC JUMP JUMPDEST PUSH2 0x40A1 DUP9 PUSH1 0x40 DUP1 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 PUSH2 0x4087 DUP11 PUSH2 0x4031 PUSH1 0x0 PUSH2 0x138B JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x409A DUP11 PUSH2 0x4031 PUSH1 0x0 PUSH2 0xED2 JUMP JUMPDEST SWAP1 MSTORE PUSH2 0x2C6C JUMP JUMPDEST POP POP POP POP POP POP POP POP JUMP JUMPDEST DUP1 MLOAD DUP3 SWAP1 PUSH1 0x0 LT ISZERO PUSH2 0x1CD2 JUMPI DUP2 MLOAD PUSH1 0x14 EQ PUSH2 0x40C5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x40CE DUP3 PUSH2 0x4280 JUMP JUMPDEST SWAP1 POP PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP2 AND ISZERO ISZERO PUSH2 0x40E5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x40ED PUSH2 0x4287 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP3 DUP2 AND SWAP2 AND EQ ISZERO PUSH2 0x1CD2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0xA9059CBB DUP4 DUP4 PUSH1 0x40 MLOAD DUP4 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP3 POP POP POP PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x4168 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x417C JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP RETURNDATASIZE ISZERO PUSH2 0xECD JUMPI PUSH1 0x20 PUSH1 0x0 DUP1 RETURNDATACOPY PUSH1 0x0 MLOAD ISZERO ISZERO PUSH2 0xECD JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 PUSH2 0x41A4 PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0x669F618B PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x2929 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP4 AND SWAP1 DUP3 ISZERO PUSH2 0x8FC MUL SWAP1 DUP4 SWAP1 PUSH1 0x0 DUP2 DUP2 DUP2 DUP6 DUP9 DUP9 CALL SWAP4 POP POP POP POP ISZERO ISZERO PUSH2 0x834 JUMPI DUP1 DUP3 PUSH2 0x4216 PUSH2 0x4296 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x40 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 DUP3 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0x1B45 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST PUSH1 0x0 DUP2 DUP4 DUP2 ISZERO ISZERO PUSH2 0x424F JUMPI INVALID JUMPDEST DIV SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 ISZERO ISZERO PUSH2 0x4268 JUMPI POP PUSH1 0x0 PUSH2 0x1CD2 JUMP JUMPDEST POP DUP2 DUP2 MUL DUP2 DUP4 DUP3 DUP2 ISZERO ISZERO PUSH2 0x4278 JUMPI INVALID JUMPDEST DIV EQ PUSH2 0x1CD2 JUMPI INVALID JUMPDEST PUSH1 0x14 ADD MLOAD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4291 PUSH2 0x17C0 JUMP JUMPDEST SWAP1 POP SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x21 DUP1 PUSH2 0x42A6 DUP4 CODECOPY ADD SWAP1 JUMP STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD PUSH1 0x20 DUP1 PUSH1 0x21 DUP4 CODECOPY DUP2 ADD PUSH1 0x40 MSTORE MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP2 AND SELFDESTRUCT STOP PUSH6 0x786563757469 PUSH16 0x6E4461696C794C696D69740000000000 STOP STOP STOP STOP STOP STOP STOP STOP 0xca SIGNEXTEND RETURNDATASIZE 0xab 0xef 0xdb 0xd8 0xc7 0x2c EXP SWAP13 DELEGATECALL 0xa6 0xe9 0xd1 SMOD 0xda DUP10 PUSH27 0xBF036EF3F3F3B010CDD2594159078D888F9B66F3F8BFA10909E31F 0x1e AND 0x24 0xd 0xb7 CALLVALUE 0x49 CREATE POP EXP REVERT 0xbb 0xe3 0xa7 0xd LOG4 JUMPI 0xcc 0xcb DUP14 MUL 0x2f 0x21 PUSH4 0x402334A4 SWAP7 0x2e ORIGIN PUSH26 0xC5DEF3417D3D8DAB9E27BA26E81E3F833784B7802E97E87EF284 0x2a PUSH13 0xCE7DA7FFAEAEDAA2F61A6A7870 0xb2 RETURNDATASIZE SWAP14 ADD 0xfc SWAP12 PUSH20 0x712E02016836A56B71F0D02689E69E326F4F4C1B SWAP1 JUMPI AND 0x4e 0xf5 SWAP3 PUSH8 0x1CF0D37C8040C00A PUSH16 0x646CD611241D8073675E00D1A1FF700F 0xbf SHL MSTORE8 0xfc DELEGATECALL PUSH20 0xDE56D1E6E4B714BA2DE0D2CDC19D356CB53B5984 0xf9 SHL REVERT EXTCODESIZE BALANCE INVALID 0xc PUSH8 0x8A0D190A6DB39274 0xbb CALLVALUE PUSH22 0x3F4C177B42DBE934B3ABBC0208C11A42E46589983431 PUSH2 0x6F17 LT 0xab NOT SWAP7 SWAP13 0x5e 0xd6 0x2e SWAP9 0xaa DUP1 PUSH15 0x31E94A687A31C65769CB99670064DD PUSH32 0x5A87526DA075C5FB4EAB9880811BBB11E8899DA471F0E69A3ED55090FC902152 0x27 0xfc 0x5f 0xb1 0xcb 0xd PUSH15 0x962EA7B74F0C1206883BE66049A02D 0x49 CALLDATACOPY SMOD DUP4 PUSH8 0xC00B3D71DD1A9465 0xdf SWAP7 SWAP4 PUSH4 0xC6DDEAC9 PUSH14 0x6168652C307C1E813CA11CFB3A60 0x1f SHR RETURN 0xb2 0x24 MSTORE MUL BYTE POP MSTORE 0xd8 0xb0 0x5f 0x1f 0x1f DUP11 RETURNDATACOPY SWAP3 0x2d REVERT PUSH13 0x9F781BB6BBB5369C114E949B69 0xeb 0xb4 BLOCKHASH 0xef RETURNDATASIZE 0x4d 0xd6 0xb2 DUP4 PUSH3 0x25EB1D 0xc3 LOG2 0xbe 0xb4 0xed PUSH5 0x697D3EF851 DUP3 COINBASE SWAP7 PUSH16 0x7C6F28B0D72F20F51198717D198D2D55 SMOD PUSH13 0x593D657865637574696F6E4D61 PUSH25 0x5065725478000000000000000000000000000000746F6B656E MSTORE PUSH6 0x676973747261 PUSH21 0x696F6E4D6573736167654964000000000000A16562 PUSH27 0x7A723058203F04EB68BA625D53C01D3C1380A6B082BA393BADBA22 STOP PUSH19 0xF5746C73A0B554AD0029000000000000000000 ",
"sourceMap": "514:12464:24:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;514:12464:24;;;;;;;"
},
"deployedBytecode": {
"linkReferences": {},
"object": "6080604052600436106101f55763ffffffff60e060020a60003504166301e4f53a81146101fa57806301fcc1d314610220578063032f693f146102445780630950d515146102775780630b26cf661461028f57806310775238146102b0578063125e4cfb146102e857806316ef191314610312578063194153d31461033357806326aa101f146103545780632803212f14610375578063351a826414610399578063392e53cd146103d15780633a50bc87146103e65780633e6968b61461040a57806340f8dd861461041f578063437764df14610440578063593399821461047257806369ffa08a1461048a5780636e5d6bea146104b15780637610722f146104d25780637837cf91146104f35780638190d90614610517578063871c0760146105385780638da5cb5b146105695780639a4a43951461057e5780639cb7595a14610596578063a4b1c243146105d7578063a4c0ed36146105f8578063ab3a25d914610661578063ad58bdd114610685578063b53472ef146106af578063be3b625b146106d0578063cd596583146106e5578063d0342acd146106fa578063db6fff8c14610721578063e79767af14610745578063ec47de2a14610766578063f2c54fe81461078a578063f2fde38b146107ae578063f3b83791146107cf578063f3f51415146107e7578063f9eaee0d14610808575b600080fd5b34801561020657600080fd5b5061021e600160a060020a0360043516602435610829565b005b34801561022c57600080fd5b5061021e600160a060020a0360043516602435610838565b34801561025057600080fd5b50610265600160a060020a0360043516610955565b60408051918252519081900360200190f35b34801561028357600080fd5b5061021e600435610a18565b34801561029b57600080fd5b5061021e600160a060020a0360043516610dc7565b3480156102bc57600080fd5b506102d4600160a060020a0360043516602435610def565b604080519115158252519081900360200190f35b3480156102f457600080fd5b5061021e600160a060020a0360043581169060243516604435610e66565b34801561031e57600080fd5b50610265600160a060020a0360043516610ed2565b34801561033f57600080fd5b50610265600160a060020a0360043516610f53565b34801561036057600080fd5b506102d4600160a060020a0360043516610fdb565b34801561038157600080fd5b5061021e600160a060020a0360043516602435610fee565b3480156103a557600080fd5b506102d4600160a060020a0360043581169060243581169060449060a49060e43590610104351661112d565b3480156103dd57600080fd5b506102d46112ff565b3480156103f257600080fd5b506102d4600160a060020a036004351660243561132c565b34801561041657600080fd5b50610265611382565b34801561042b57600080fd5b50610265600160a060020a036004351661138b565b34801561044c57600080fd5b5061045561140c565b60408051600160e060020a03199092168252519081900360200190f35b34801561047e57600080fd5b506102d460043561141a565b34801561049657600080fd5b5061021e600160a060020a03600435811690602435166114d5565b3480156104bd57600080fd5b5061021e600160a060020a0360043516611584565b3480156104de57600080fd5b50610265600160a060020a03600435166115a9565b3480156104ff57600080fd5b5061021e600160a060020a0360043516602435611602565b34801561052357600080fd5b50610265600160a060020a036004351661173f565b34801561054457600080fd5b5061054d6117c0565b60408051600160a060020a039092168252519081900360200190f35b34801561057557600080fd5b5061054d6117f3565b34801561058a57600080fd5b5061021e600435611826565b3480156105a257600080fd5b506105ab611b4c565b6040805167ffffffffffffffff9485168152928416602084015292168183015290519081900360600190f35b3480156105e357600080fd5b50610265600160a060020a0360043516611b57565b34801561060457600080fd5b50604080516020600460443581810135601f81018490048402850184019095528484526102d4948235600160a060020a0316946024803595369594606494920191908190840183828082843750949750611bd89650505050505050565b34801561066d57600080fd5b50610265600160a060020a0360043516602435611c02565b34801561069157600080fd5b5061021e600160a060020a0360043581169060243516604435611cd8565b3480156106bb57600080fd5b5061021e600160a060020a0360043516611ce3565b3480156106dc57600080fd5b50610265611d08565b3480156106f157600080fd5b5061054d611d32565b34801561070657600080fd5b5061021e600160a060020a0360043581169060243516611d65565b34801561072d57600080fd5b5061021e600160a060020a0360043516602435612088565b34801561075157600080fd5b5061021e600160a060020a0360043516612169565b34801561077257600080fd5b5061021e600160a060020a036004351660243561218e565b34801561079657600080fd5b50610265600160a060020a0360043516602435612273565b3480156107ba57600080fd5b5061021e600160a060020a0360043516612307565b3480156107db57600080fd5b5061021e60043561232c565b3480156107f357600080fd5b50610265600160a060020a0360043516612351565b34801561081457600080fd5b506102d4600160a060020a03600435166123d4565b61083482338361245a565b5050565b6108406117f3565b600160a060020a0316331461085457600080fd5b61085d82610fdb565b151561086857600080fd5b801580610887575060008111801561088757506108848261138b565b81105b151561089257600080fd5b806000808460405160200180806000805160206144a783398151915281525060110182600160a060020a0316600160a060020a0316606060020a0281526014019150506040516020818303038152906040526040518082805190602001908083835b602083106109135780518252601f1990920191602091820191016108f4565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020939093555050505050565b600080600083604051602001808060c360020a670dac2f0a0cae4a8f0281525060080182600160a060020a0316600160a060020a0316606060020a0281526014019150506040516020818303038152906040526040518082805190602001908083835b602083106109d75780518252601f1990920191602091820191016109b8565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205495945050505050565b6000610a238261265c565b610a2c82612744565b9050610a378161173f565b8214156108345760008082604051602001808060b260020a6919185a5b1e531a5b5a5d02815250600a0182600160a060020a0316600160a060020a0316606060020a0281526014019150506040516020818303038152906040526040518082805190602001908083835b60208310610ac05780518252601f199092019160209182019101610aa1565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285810196909652509283016000908120819055835160c360020a670dac2f0a0cae4a8f0281870152600160a060020a038716606060020a0260288201528451808203601c018152603c909101948590528051919586959194509092508291908401908083835b60208310610b6f5780518252601f199092019160209182019101610b50565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285810196909652509283016000908120819055835160c360020a670dad2dca0cae4a8f0281870152600160a060020a038716606060020a0260288201528451808203601c018152603c909101948590528051919586959194509092508291908401908083835b60208310610c1e5780518252601f199092019160209182019101610bff565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528581019690965250928301600090812081905583516000805160206142c783398151915281870152600160a060020a038716606060020a026033820152845180820360270181526047909101948590528051919586959194509092508291908401908083835b60208310610ccd5780518252601f199092019160209182019101610cae565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528581019690965250928301600090812081905583516000805160206144a783398151915281870152600160a060020a038716606060020a026031820152845180820360250181526045909101948590528051919586959194509092508291908401908083835b60208310610d7c5780518252601f199092019160209182019101610d5d565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600090812081905561083493508492509050612805565b610dcf6117f3565b600160a060020a03163314610de357600080fd5b610dec8161287b565b50565b600080610e1383610e0786610e02611382565b611c02565b9063ffffffff6128d516565b90506000610e216000612351565b118015610e36575080610e3385612351565b10155b8015610e4a5750610e4684610955565b8311155b8015610e5e5750610e5a84611b57565b8310155b949350505050565b610e6e611d32565b600160a060020a03163314610e8257600080fd5b610e8a6117c0565b600160a060020a0316610e9b6128e2565b600160a060020a031614610eae57600080fd5b610eb783610fdb565b1515610ec257600080fd5b610ecd83838361295a565b505050565b60008060008360405160200180806000805160206144a783398151915281525060110182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106109d75780518252601f1990920191602091820191016109b8565b6000806000836040516020018080608860020a6e6d65646961746f7242616c616e636502815250600f0182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106109d75780518252601f1990920191602091820191016109b8565b600080610fe783611b57565b1192915050565b610ff66117f3565b600160a060020a0316331461100a57600080fd5b61101382610fdb565b151561101e57600080fd5b61102782610955565b811180611032575080155b151561103d57600080fd5b8060008084604051602001808060b260020a6919185a5b1e531a5b5a5d02815250600a0182600160a060020a0316600160a060020a0316606060020a0281526014019150506040516020818303038152906040526040518082805190602001908083835b602083106110c05780518252601f1990920191602091820191016110a1565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528581019690965250928301600020949094555080518481529051600160a060020a03861693506000805160206142e7833981519152929181900390910190a25050565b6040805160048152602481018252602081018051600160e060020a031660e160020a6337ef4101021781529151815160009330939291829190808383895b8381101561118357818101518382015260200161116b565b50505050905090810190601f1680156111b05780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af19150501580611242575030600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561120a57600080fd5b505af115801561121e573d6000803e3d6000fd5b505050506040513d602081101561123457600080fd5b5051600160a060020a031633145b8061124c57503330145b151561125757600080fd5b61125f6112ff565b1561126957600080fd5b6112728761287b565b61127b86612996565b6112a96000866003806020026040519081016040528092919082600360200280828437506129dc9350505050565b6040805180820182526112d291600091908790600290839083908082843750612c6c9350505050565b6112db83612e09565b6112e482612e46565b6112ec612eec565b6112f46112ff565b979650505050505050565b60008051602061438783398151915260005260046020526000805160206143078339815191525460ff1690565b60008061134483610e078661133f611382565b612273565b90506000611352600061138b565b1180156113675750806113648561138b565b10155b8015610e5e575061137784610ed2565b909211159392505050565b62015180420490565b60008060008360405160200180806000805160206142c783398151915281525060130182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106109d75780518252601f1990920191602091820191016109b8565b60e160020a6358a8b6130290565b60006004600083604051602001808060a260020a6b1b595cdcd859d9519a5e195902815250600c0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106114915780518252601f199092019160209182019101611472565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205460ff1695945050505050565b30600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561151357600080fd5b505af1158015611527573d6000803e3d6000fd5b505050506040513d602081101561153d57600080fd5b5051600160a060020a0316331461155357600080fd5b600160a060020a038216158061156f575061156d82610fdb565b155b151561157a57600080fd5b6108348282612f1f565b61158c6117f3565b600160a060020a031633146115a057600080fd5b610dec81612996565b60008060008060006115ba86610955565b93506115c586612351565b92506115d386610e02611382565b91508183116115e35760006115e7565b8183035b90508084106115f657806115f8565b835b9695505050505050565b61160a6117f3565b600160a060020a0316331461161e57600080fd5b61162782610fdb565b151561163257600080fd5b61163b82610ed2565b811180611646575080155b151561165157600080fd5b806000808460405160200180806000805160206142c783398151915281525060130182600160a060020a0316600160a060020a0316606060020a0281526014019150506040516020818303038152906040526040518082805190602001908083835b602083106116d25780518252601f1990920191602091820191016116b3565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528581019690965250928301600020949094555080518481529051600160a060020a03861693506000805160206143c7833981519152929181900390910190a25050565b60008060008360405160200180806000805160206144c7833981519152815250601a0182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106109d75780518252601f1990920191602091820191016109b8565b6000805160206143e7833981519152600052600260205260008051602061442783398151915254600160a060020a031690565b600080516020614367833981519152600052600260205260008051602061434783398151915254600160a060020a031690565b60006060611832611d32565b600160a060020a031663cb08a10c846040518263ffffffff1660e060020a028152600401808260001916600019168152602001915050602060405180830381600087803b15801561188257600080fd5b505af1158015611896573d6000803e3d6000fd5b505050506040513d60208110156118ac57600080fd5b5051156118b857600080fd5b306118c1611d32565b600160a060020a0316633f9a8e7e856040518263ffffffff1660e060020a028152600401808260001916600019168152602001915050602060405180830381600087803b15801561191157600080fd5b505af1158015611925573d6000803e3d6000fd5b505050506040513d602081101561193b57600080fd5b5051600160a060020a03161461195057600080fd5b6119586117c0565b600160a060020a0316611969611d32565b600160a060020a0316634a610b04856040518263ffffffff1660e060020a028152600401808260001916600019168152602001915050602060405180830381600087803b1580156119b957600080fd5b505af11580156119cd573d6000803e3d6000fd5b505050506040513d60208110156119e357600080fd5b5051600160a060020a0316146119f857600080fd5b5050604080516024808201849052825180830390910181526044909101909152602081018051600160e060020a031660e060020a630950d5150290811790915290611a41611d32565b600160a060020a031663dc8601b3611a576117c0565b83611a60611d08565b6040518463ffffffff1660e060020a0281526004018084600160a060020a0316600160a060020a0316815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b83811015611acd578181015183820152602001611ab5565b50505050905090810190601f168015611afa5780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600087803b158015611b1b57600080fd5b505af1158015611b2f573d6000803e3d6000fd5b505050506040513d6020811015611b4557600080fd5b5050505050565b600160026000909192565b600080600083604051602001808060c360020a670dad2dca0cae4a8f0281525060080182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106109d75780518252601f1990920191602091820191016109b8565b600080611be3612f58565b1515611bf7575033611bf781868686612f85565b506001949350505050565b600080600084846040516020018080608060020a6f746f74616c5370656e745065724461790281525060100183600160a060020a0316600160a060020a0316606060020a028152601401828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310611c945780518252601f199092019160209182019101611c75565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205493505050505b92915050565b610ecd83838361245a565b611ceb6117f3565b600160a060020a03163314611cff57600080fd5b610dec816133b9565b60008051602061446783398151915260009081526020526000805160206143a78339815191525490565b600080516020614407833981519152600052600260205260008051602061448783398151915254600160a060020a031690565b6000806000806060600030600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015611dad57600080fd5b505af1158015611dc1573d6000803e3d6000fd5b505050506040513d6020811015611dd757600080fd5b5051600160a060020a03163314611ded57600080fd5b86600160a060020a0381161515611e0357600080fd5b611e0c89610fdb565b1515611e1757600080fd5b6040805160e060020a6370a082310281523060048201529051600160a060020a038b16916370a082319160248083019260209291908290030181600087803b158015611e6257600080fd5b505af1158015611e76573d6000803e3d6000fd5b505050506040513d6020811015611e8c57600080fd5b50519650611e9989610f53565b9550858711611ea757600080fd5b8587039450611eb5896115a9565b935060008411611ec457600080fd5b83851115611ed0578394505b611ee289611edc611382565b876134e5565b611efb89611ef6888863ffffffff6128d516565b6135c6565b60408051600160a060020a03808c1660248301528a1660448201526064808201889052825180830390910181526084909101909152602081018051600160e060020a031660e060020a63125e4cfb021790529250611f57611d32565b600160a060020a031663dc8601b3611f6d6117c0565b85611f76611d08565b6040518463ffffffff1660e060020a0281526004018084600160a060020a0316600160a060020a0316815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b83811015611fe3578181015183820152602001611fcb565b50505050905090810190601f1680156120105780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600087803b15801561203157600080fd5b505af1158015612045573d6000803e3d6000fd5b505050506040513d602081101561205b57600080fd5b50519150612069828a61364d565b6120738286613720565b61207d8289613794565b505050505050505050565b6120906117f3565b600160a060020a031633146120a457600080fd5b6120ad82610fdb565b15156120b857600080fd5b8015806120de57506120c982611b57565b811180156120de57506120db82612351565b81105b15156120e957600080fd5b8060008084604051602001808060c360020a670dac2f0a0cae4a8f0281525060080182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106109135780518252601f1990920191602091820191016108f4565b6121716117f3565b600160a060020a0316331461218557600080fd5b610dec8161380d565b6121966117f3565b600160a060020a031633146121aa57600080fd5b6121b382610fdb565b15156121be57600080fd5b6000811180156121d557506121d282612351565b81105b80156121e857506121e582610955565b81105b15156121f357600080fd5b8060008084604051602001808060c360020a670dad2dca0cae4a8f0281525060080182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106109135780518252601f1990920191602091820191016108f4565b600080600084846040516020018080606860020a72746f74616c45786563757465645065724461790281525060130183600160a060020a0316600160a060020a0316606060020a0281526014018281526020019250505060405160208183030381529060405260405180828051906020019080838360208310611c945780518252601f199092019160209182019101611c75565b61230f6117f3565b600160a060020a0316331461232357600080fd5b610dec81612e46565b6123346117f3565b600160a060020a0316331461234857600080fd5b610dec81612e09565b600080600083604051602001808060b260020a6919185a5b1e531a5b5a5d02815250600a0182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106109d75780518252601f1990920191602091820191016109b8565b60006004600083604051602001808060a260020a6b1d1bdad95b905b1b1bddd95902815250600c0182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106114915780518252601f199092019160209182019101611472565b600080612465612f58565b1561246f57600080fd5b6040805160e060020a6370a082310281523060048201529051600160a060020a038716916370a082319160248083019260209291908290030181600087803b1580156124ba57600080fd5b505af11580156124ce573d6000803e3d6000fd5b505050506040513d60208110156124e457600080fd5b505191506124f2600161393a565b6040805160e060020a6323b872dd028152336004820152306024820152604481018590529051600160a060020a038716916323b872dd9160648083019260209291908290030181600087803b15801561254a57600080fd5b505af115801561255e573d6000803e3d6000fd5b505050506040513d602081101561257457600080fd5b506125819050600061393a565b6040805160e060020a6370a08231028152306004820152905161260a918491600160a060020a038916916370a082319160248083019260209291908290030181600087803b1580156125d257600080fd5b505af11580156125e6573d6000803e3d6000fd5b505050506040513d60208110156125fc57600080fd5b50519063ffffffff61397116565b90508281111561261957600080fd5b611b45853383876040516020018082600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052612f85565b6000806000612669611d32565b600160a060020a0316331461267d57600080fd5b6126856117c0565b600160a060020a03166126966128e2565b600160a060020a0316146126a957600080fd5b6126b28461141a565b156126bc57600080fd5b6126c584612744565b92506126d084613983565b91506126db846139fd565b90506126e684613a72565b6126f1838383613b36565b60408051600160a060020a03808616825284166020820152808201839052905185917f07b5483b8e4bd8ea240a474d5117738350e7d431e3668c48a97910b0b397796a919081900360600190a250505050565b60006002600083604051602001808060a160020a6b36b2b9b9b0b3b2aa37b5b2b702815250600c0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106127bb5780518252601f19909201916020918201910161279c565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002054600160a060020a031695945050505050565b604080516000805160206144c7833981519152602080830191909152606060020a600160a060020a03861602603a8301528251602e818403018152604e9092019283905281518493600093849390928291840190808383602083106109135780518252601f1990920191602091820191016108f4565b61288481613b6d565b151561288f57600080fd5b60008051602061440783398151915260005260026020526000805160206144878339815191528054600160a060020a031916600160a060020a0392909216919091179055565b81810182811015611cd257fe5b60006128ec611d32565b600160a060020a031663d67bdd256040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561292957600080fd5b505af115801561293d573d6000803e3d6000fd5b505050506040513d602081101561295357600080fd5b5051905090565b612964838261132c565b1561298b5761297b83612975611382565b83613b75565b612986838383613c15565b610ecd565b610ecd8383836101f5565b6000805160206143e783398151915260005260026020526000805160206144278339815191528054600160a060020a031916600160a060020a0392909216919091179055565b604081015160001080156129f7575060408101516020820151115b8015612a07575060208101518151115b1515612a1257600080fd5b80516040805160b260020a6919185a5b1e531a5b5a5d02602082810191909152606060020a600160a060020a03871602602a8301528251601e818403018152603e909201928390528151600093849392909182918401908083835b60208310612a8c5780518252601f199092019160209182019101612a6d565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528581019690965250928301600090812095909555505083820151815160c360020a670dac2f0a0cae4a8f0281850152600160a060020a038716606060020a0260288201528251808203601c018152603c9091019283905280519194938493919282918401908083835b60208310612b3e5780518252601f199092019160209182019101612b1f565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528581019690965250928301600090812095909555505083810151815160c360020a670dad2dca0cae4a8f0281850152600160a060020a038716606060020a0260288201528251808203601c018152603c9091019283905280519194938493919282918401908083835b60208310612bf05780518252601f199092019160209182019101612bd1565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600090812094909455505050600160a060020a038316906000805160206142e78339815191529083905b60200201516040518082815260200191505060405180910390a25050565b8051602082015110612c7d57600080fd5b8051604080516000805160206142c7833981519152602082810191909152606060020a600160a060020a038716026033830152825160278184030181526047909201928390528151600093849392909182918401908083835b60208310612cf55780518252601f199092019160209182019101612cd6565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652858101969096525092830160009081209590955550508382015181516000805160206144a783398151915281850152600160a060020a038716606060020a0260318201528251808203602501815260459091019283905280519194938493919282918401908083835b60208310612da75780518252601f199092019160209182019101612d88565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600090812094909455505050600160a060020a038316906000805160206143c7833981519152908390612c4e565b612e11613c98565b811115612e1d57600080fd5b60008051602061446783398151915260009081526020526000805160206143a783398151915255565b600160a060020a0381161515612e5b57600080fd5b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0612e846117f3565b60408051600160a060020a03928316815291841660208301528051918290030190a160008051602061436783398151915260005260026020526000805160206143478339815191528054600160a060020a031916600160a060020a0392909216919091179055565b6000805160206143878339815191526000526004602052600080516020614307833981519152805460ff19166001179055565b80600160a060020a0381161515612f3557600080fd5b600160a060020a0383161515612f4e5761298682613cdf565b610ecd8383613ceb565b60008051602061444783398151915260005260046020526000805160206143278339815191525460ff1690565b600060608060006060600080612f99612f58565b15612fa3576133ac565b612fac8b6123d4565b1515612fb757600080fd5b612fc08b610fdb565b965086151561301357612fd28b613d88565b9550612fdd8b613e6d565b9450612fe88b613ec3565b9350600086511180612ffb575060008551115b151561300657600080fd5b6130138b8560ff16613f15565b61301d8b8a610def565b151561302857600080fd5b61303a8b613034611382565b8b6134e5565b6130448a896140ab565b915086156130a55760408051600160a060020a03808e1660248301528416604482015260648082018c9052825180830390910181526084909101909152602081018051600160e060020a031660e060020a63125e4cfb021790529250613215565b30600160a060020a0316632ae87cdd905060e060020a028b878787868e6040516024018087600160a060020a0316600160a060020a0316815260200180602001806020018660ff1660ff16815260200185600160a060020a0316600160a060020a03168152602001848152602001838103835288818151815260200191508051906020019080838360005b83811015613148578181015183820152602001613130565b50505050905090810190601f1680156131755780820380516001836020036101000a031916815260200191505b50838103825287518152875160209182019189019080838360005b838110156131a8578181015183820152602001613190565b50505050905090810190601f1680156131d55780820380516001836020036101000a031916815260200191505b5060408051601f19818403018152919052602081018051600160e060020a0316600160e060020a0319909c169b909b17909a5250979a5050505050505050505b6132268b611ef68b610e078f610f53565b61322e611d32565b600160a060020a031663dc8601b36132446117c0565b8561324d611d08565b6040518463ffffffff1660e060020a0281526004018084600160a060020a0316600160a060020a0316815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156132ba5781810151838201526020016132a2565b50505050905090810190601f1680156132e75780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600087803b15801561330857600080fd5b505af115801561331c573d6000803e3d6000fd5b505050506040513d602081101561333257600080fd5b50519050613340818c61364d565b61334a818a613720565b613354818b613794565b861515613365576133658b82612805565b604080518a815290518291600160a060020a03808e1692908f16917f59a9a8027b9c87b961e254899821c9a276b5efc35d1f7409ea4f291470f1629a919081900360200190a45b5050505050505050505050565b6133c2816123d4565b156133cc57600080fd5b6133d581613b6d565b15156133e057600080fd5b60016004600083604051602001808060a260020a6b1d1bdad95b905b1b1bddd95902815250600c0182600160a060020a0316600160a060020a0316606060020a0281526014019150506040516020818303038152906040526040518082805190602001908083835b602083106134675780518252601f199092019160209182019101613448565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529283016000908120805460ff191696151596909617909555505051600160a060020a038416927fbeceb48aeaa805aeae57be163cca6249077a18734e408a85aa74e875c4373809925090a250565b6134f381610e078585611c02565b60008085856040516020018080608060020a6f746f74616c5370656e745065724461790281525060100183600160a060020a0316600160a060020a0316606060020a028152601401828152602001925050506040516020818303038152906040526040518082805190602001908083835b602083106135835780518252601f199092019160209182019101613564565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002093909355505050505050565b80600080846040516020018080608860020a6e6d65646961746f7242616c616e636502815250600f0182600160a060020a0316600160a060020a0316606060020a028152601401915050604051602081830303815290604052604051808280519060200190808383602083106109135780518252601f1990920191602091820191016108f4565b806002600084604051602001808060a160020a6b36b2b9b9b0b3b2aa37b5b2b702815250600c0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106136c35780518252601f1990920191602091820191016136a4565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000208054600160a060020a031916600160a060020a0395909516949094179093555050505050565b8060008084604051602001808060a060020a6b6d65737361676556616c756502815250600c018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106109135780518252601f1990920191602091820191016108f4565b8060026000846040516020018080608260020a6f1b595cdcd859d9549958da5c1a595b9d028152506010018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106136c35780518252601f1990920191602091820191016136a4565b613816816123d4565b151561382157600080fd5b61382a81613b6d565b151561383557600080fd5b60006004600083604051602001808060a260020a6b1d1bdad95b905b1b1bddd95902815250600c0182600160a060020a0316600160a060020a0316606060020a0281526014019150506040516020818303038152906040526040518082805190602001908083835b602083106138bc5780518252601f19909201916020918201910161389d565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529283016000908120805460ff191696151596909617909555505051600160a060020a038416927feaa9136602e3b70a4e689b5b6f55bda25ca62b917d839c0ff87f5902387f77b9925090a250565b6000805160206144478339815191526000526004602052600080516020614327833981519152805460ff1916911515919091179055565b60008282111561397d57fe5b50900390565b600060026000836040516020018080608260020a6f1b595cdcd859d9549958da5c1a595b9d028152506010018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106127bb5780518252601f19909201916020918201910161279c565b600080600083604051602001808060a060020a6b6d65737361676556616c756502815250600c018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106109d75780518252601f1990920191602091820191016109b8565b60016004600083604051602001808060a260020a6b1b595cdcd859d9519a5e195902815250600c0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310613ae95780518252601f199092019160209182019101613aca565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805460ff19169415159490941790935550505050565b613b5383611ef683613b4787610f53565b9063ffffffff61397116565b610ecd600160a060020a038416838363ffffffff61410516565b6000903b1190565b613b8381610e078585612273565b60008085856040516020018080606860020a72746f74616c45786563757465645065724461790281525060130183600160a060020a0316600160a060020a0316606060020a02815260140182815260200192505050604051602081830303815290604052604051808280519060200190808383602083106135835780518252601f199092019160209182019101613564565b6000613c1f61419a565b9050613c3b600160a060020a038516848463ffffffff61410516565b613c4c84611ef684613b4788610f53565b6040805183815290518291600160a060020a0380871692908816917f9afd47907e25028cdaca89d193518c302bbb128617d5a992c5abd45815526593919081900360200190a450505050565b6000613ca2611d32565b600160a060020a031663e5789d036040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561292957600080fd5b303161083482826141e1565b6040805160e060020a6370a0823102815230600482015290518391600091600160a060020a038416916370a0823191602480830192602092919082900301818787803b158015613d3a57600080fd5b505af1158015613d4e573d6000803e3d6000fd5b505050506040513d6020811015613d6457600080fd5b50519050613d82600160a060020a038516848363ffffffff61410516565b50505050565b60405160e060020a6306fdde03028152606090600082602083600481885afa1515613dc55760e160020a6351fa6fbf028352602083600485885afa505b3d830160405260203d1160018114613ddf573d9250613ded565b6020806040513e6040515192505b50816040519080825280601f01601f191660200182016040528015613e1c578160200160208202803883390190505b50905060203d1115613e3557816040602083013e610e5e565b60003d1115610e5e576000835193508360208301525b6000841115613e635760089390931b92600101613e4b565b8152949350505050565b60405160e060020a6395d89b41028152606090600082602083600481885afa1515613dc55760e360020a631eedf1af028352602083600485885afa503d830160405260203d1160018114613ddf573d9250613ded565b6000806040516020810160405260e060020a63313ce567028152602081600483875afa1515613f0d5760e060020a632e0f2625028152602081600483875afa1515613f0d57600081525b519392505050565b600080600080600080601287101561400a5786601203600a0a9550613f4a86613f3e6000611b57565b9063ffffffff61424216565b9450613f5a86613f3e6000610955565b9350613f6a86613f3e6000612351565b9250613f7a86613f3e6000610ed2565b9150613f8a86613f3e600061138b565b9050841515613fc25760019450848411613fc25760649350606491508383111580613fb55750818111155b15613fc257506127109150815b613fe788606060405190810160405280868152602001878152602001888152506129dc565b61400588604080519081016040528084815260200185815250612c6c565b6140a1565b60128703600a0a955061406a8860606040519081016040528061403d8a6140316000612351565b9063ffffffff61425716565b81526020016140508a6140316000610955565b81526020016140638a6140316000611b57565b90526129dc565b6140a18860408051908101604052806140878a614031600061138b565b815260200161409a8a6140316000610ed2565b9052612c6c565b5050505050505050565b8051829060001015611cd25781516014146140c557600080fd5b6140ce82614280565b9050600160a060020a03811615156140e557600080fd5b6140ed614287565b600160a060020a0382811691161415611cd257600080fd5b82600160a060020a031663a9059cbb83836040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050600060405180830381600087803b15801561416857600080fd5b505af115801561417c573d6000803e3d6000fd5b505050503d15610ecd5760206000803e6000511515610ecd57600080fd5b60006141a4611d32565b600160a060020a031663669f618b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561292957600080fd5b604051600160a060020a0383169082156108fc029083906000818181858888f193505050501515610834578082614216614296565b600160a060020a039091168152604051908190036020019082f080158015611b45573d6000803e3d6000fd5b6000818381151561424f57fe5b049392505050565b600082151561426857506000611cd2565b5081810281838281151561427857fe5b0414611cd257fe5b6014015190565b60006142916117c0565b905090565b6040516021806142a6833901905600608060405260405160208060218339810160405251600160a060020a038116ff00657865637574696f6e4461696c794c696d697400000000000000000000000000ca0b3dabefdbd8c72c0a9cf4a6e9d107da897abf036ef3f3f3b010cdd2594159078d888f9b66f3f8bfa10909e31f1e16240db73449f0500afdbbe3a70da457cccb8d022f2163402334a4962e3279c5def3417d3d8dab9e27ba26e81e3f833784b7802e97e87ef2842a6cce7da7ffaeaedaa2f61a6a7870b23d9d01fc9b73712e02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c00a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba2de0d2cdc19d356cb53b5984f91bfd3b31fe0c678a0d190a6db39274bb34753f4c177b42dbe934b3abbc0208c11a42e46589983431616f1710ab19969c5ed62e98aa806e31e94a687a31c65769cb99670064dd7f5a87526da075c5fb4eab9880811bbb11e8899da471f0e69a3ed55090fc90215227fc5fb1cb0d6e962ea7b74f0c1206883be66049a02d4937078367c00b3d71dd1a9465df969363c6ddeac96d6168652c307c1e813ca11cfb3a601f1cf3b22452021a5052d8b05f1f1f8a3e922dfd6c9f781bb6bbb5369c114e949b69ebb440ef3d4dd6b2836225eb1dc3a2beb4ed64697d3ef8518241966f7c6f28b0d72f20f51198717d198d2d55076c593d657865637574696f6e4d61785065725478000000000000000000000000000000746f6b656e526567697374726174696f6e4d6573736167654964000000000000a165627a7a723058203f04eb68ba625d53c01d3c1380a6b082ba393badba220072f5746c73a0b554ad0029",
"opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH2 0x1F5 JUMPI PUSH4 0xFFFFFFFF PUSH1 0xE0 PUSH1 0x2 EXP PUSH1 0x0 CALLDATALOAD DIV AND PUSH4 0x1E4F53A DUP2 EQ PUSH2 0x1FA JUMPI DUP1 PUSH4 0x1FCC1D3 EQ PUSH2 0x220 JUMPI DUP1 PUSH4 0x32F693F EQ PUSH2 0x244 JUMPI DUP1 PUSH4 0x950D515 EQ PUSH2 0x277 JUMPI DUP1 PUSH4 0xB26CF66 EQ PUSH2 0x28F JUMPI DUP1 PUSH4 0x10775238 EQ PUSH2 0x2B0 JUMPI DUP1 PUSH4 0x125E4CFB EQ PUSH2 0x2E8 JUMPI DUP1 PUSH4 0x16EF1913 EQ PUSH2 0x312 JUMPI DUP1 PUSH4 0x194153D3 EQ PUSH2 0x333 JUMPI DUP1 PUSH4 0x26AA101F EQ PUSH2 0x354 JUMPI DUP1 PUSH4 0x2803212F EQ PUSH2 0x375 JUMPI DUP1 PUSH4 0x351A8264 EQ PUSH2 0x399 JUMPI DUP1 PUSH4 0x392E53CD EQ PUSH2 0x3D1 JUMPI DUP1 PUSH4 0x3A50BC87 EQ PUSH2 0x3E6 JUMPI DUP1 PUSH4 0x3E6968B6 EQ PUSH2 0x40A JUMPI DUP1 PUSH4 0x40F8DD86 EQ PUSH2 0x41F JUMPI DUP1 PUSH4 0x437764DF EQ PUSH2 0x440 JUMPI DUP1 PUSH4 0x59339982 EQ PUSH2 0x472 JUMPI DUP1 PUSH4 0x69FFA08A EQ PUSH2 0x48A JUMPI DUP1 PUSH4 0x6E5D6BEA EQ PUSH2 0x4B1 JUMPI DUP1 PUSH4 0x7610722F EQ PUSH2 0x4D2 JUMPI DUP1 PUSH4 0x7837CF91 EQ PUSH2 0x4F3 JUMPI DUP1 PUSH4 0x8190D906 EQ PUSH2 0x517 JUMPI DUP1 PUSH4 0x871C0760 EQ PUSH2 0x538 JUMPI DUP1 PUSH4 0x8DA5CB5B EQ PUSH2 0x569 JUMPI DUP1 PUSH4 0x9A4A4395 EQ PUSH2 0x57E JUMPI DUP1 PUSH4 0x9CB7595A EQ PUSH2 0x596 JUMPI DUP1 PUSH4 0xA4B1C243 EQ PUSH2 0x5D7 JUMPI DUP1 PUSH4 0xA4C0ED36 EQ PUSH2 0x5F8 JUMPI DUP1 PUSH4 0xAB3A25D9 EQ PUSH2 0x661 JUMPI DUP1 PUSH4 0xAD58BDD1 EQ PUSH2 0x685 JUMPI DUP1 PUSH4 0xB53472EF EQ PUSH2 0x6AF JUMPI DUP1 PUSH4 0xBE3B625B EQ PUSH2 0x6D0 JUMPI DUP1 PUSH4 0xCD596583 EQ PUSH2 0x6E5 JUMPI DUP1 PUSH4 0xD0342ACD EQ PUSH2 0x6FA JUMPI DUP1 PUSH4 0xDB6FFF8C EQ PUSH2 0x721 JUMPI DUP1 PUSH4 0xE79767AF EQ PUSH2 0x745 JUMPI DUP1 PUSH4 0xEC47DE2A EQ PUSH2 0x766 JUMPI DUP1 PUSH4 0xF2C54FE8 EQ PUSH2 0x78A JUMPI DUP1 PUSH4 0xF2FDE38B EQ PUSH2 0x7AE JUMPI DUP1 PUSH4 0xF3B83791 EQ PUSH2 0x7CF JUMPI DUP1 PUSH4 0xF3F51415 EQ PUSH2 0x7E7 JUMPI DUP1 PUSH4 0xF9EAEE0D EQ PUSH2 0x808 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x206 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x829 JUMP JUMPDEST STOP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x22C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x838 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x250 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x955 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x283 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x4 CALLDATALOAD PUSH2 0xA18 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x29B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0xDC7 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x2BC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x2D4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0xDEF JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 ISZERO ISZERO DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x2F4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x24 CALLDATALOAD AND PUSH1 0x44 CALLDATALOAD PUSH2 0xE66 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x31E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0xED2 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x33F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0xF53 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x360 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x2D4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0xFDB JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x381 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0xFEE JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x3A5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x2D4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x24 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x44 SWAP1 PUSH1 0xA4 SWAP1 PUSH1 0xE4 CALLDATALOAD SWAP1 PUSH2 0x104 CALLDATALOAD AND PUSH2 0x112D JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x3DD JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x2D4 PUSH2 0x12FF JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x3F2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x2D4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x132C JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x416 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH2 0x1382 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x42B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x138B JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x44C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x455 PUSH2 0x140C JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 PUSH1 0xE0 PUSH1 0x2 EXP SUB NOT SWAP1 SWAP3 AND DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x47E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x2D4 PUSH1 0x4 CALLDATALOAD PUSH2 0x141A JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x496 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x24 CALLDATALOAD AND PUSH2 0x14D5 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x4BD JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x1584 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x4DE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x15A9 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x4FF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x1602 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x523 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x173F JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x544 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x54D PUSH2 0x17C0 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB SWAP1 SWAP3 AND DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x575 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x54D PUSH2 0x17F3 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x58A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x4 CALLDATALOAD PUSH2 0x1826 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x5A2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x5AB PUSH2 0x1B4C JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF SWAP5 DUP6 AND DUP2 MSTORE SWAP3 DUP5 AND PUSH1 0x20 DUP5 ADD MSTORE SWAP3 AND DUP2 DUP4 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x60 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x5E3 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x1B57 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x604 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 DUP1 MLOAD PUSH1 0x20 PUSH1 0x4 PUSH1 0x44 CALLDATALOAD DUP2 DUP2 ADD CALLDATALOAD PUSH1 0x1F DUP2 ADD DUP5 SWAP1 DIV DUP5 MUL DUP6 ADD DUP5 ADD SWAP1 SWAP6 MSTORE DUP5 DUP5 MSTORE PUSH2 0x2D4 SWAP5 DUP3 CALLDATALOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND SWAP5 PUSH1 0x24 DUP1 CALLDATALOAD SWAP6 CALLDATASIZE SWAP6 SWAP5 PUSH1 0x64 SWAP5 SWAP3 ADD SWAP2 SWAP1 DUP2 SWAP1 DUP5 ADD DUP4 DUP3 DUP1 DUP3 DUP5 CALLDATACOPY POP SWAP5 SWAP8 POP PUSH2 0x1BD8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x66D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x1C02 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x691 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x24 CALLDATALOAD AND PUSH1 0x44 CALLDATALOAD PUSH2 0x1CD8 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x6BB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x1CE3 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x6DC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH2 0x1D08 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x6F1 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x54D PUSH2 0x1D32 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x706 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x24 CALLDATALOAD AND PUSH2 0x1D65 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x72D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x2088 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x751 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x2169 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x772 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x218E JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x796 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x2273 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x7BA JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x2307 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x7DB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x21E PUSH1 0x4 CALLDATALOAD PUSH2 0x232C JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x7F3 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x265 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x2351 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x814 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x2D4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB PUSH1 0x4 CALLDATALOAD AND PUSH2 0x23D4 JUMP JUMPDEST PUSH2 0x834 DUP3 CALLER DUP4 PUSH2 0x245A JUMP JUMPDEST POP POP JUMP JUMPDEST PUSH2 0x840 PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x854 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x85D DUP3 PUSH2 0xFDB JUMP JUMPDEST ISZERO ISZERO PUSH2 0x868 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 ISZERO DUP1 PUSH2 0x887 JUMPI POP PUSH1 0x0 DUP2 GT DUP1 ISZERO PUSH2 0x887 JUMPI POP PUSH2 0x884 DUP3 PUSH2 0x138B JUMP JUMPDEST DUP2 LT JUMPDEST ISZERO ISZERO PUSH2 0x892 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x0 DUP1 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x44A7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP2 MSTORE POP PUSH1 0x11 ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x913 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x8F4 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 KECCAK256 SWAP4 SWAP1 SWAP4 SSTORE POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xC3 PUSH1 0x2 EXP PUSH8 0xDAC2F0A0CAE4A8F MUL DUP2 MSTORE POP PUSH1 0x8 ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x9D7 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x9B8 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 KECCAK256 SLOAD SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0xA23 DUP3 PUSH2 0x265C JUMP JUMPDEST PUSH2 0xA2C DUP3 PUSH2 0x2744 JUMP JUMPDEST SWAP1 POP PUSH2 0xA37 DUP2 PUSH2 0x173F JUMP JUMPDEST DUP3 EQ ISZERO PUSH2 0x834 JUMPI PUSH1 0x0 DUP1 DUP3 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xB2 PUSH1 0x2 EXP PUSH10 0x19185A5B1E531A5B5A5D MUL DUP2 MSTORE POP PUSH1 0xA ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0xAC0 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0xAA1 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 DUP2 ADD SWAP7 SWAP1 SWAP7 MSTORE POP SWAP3 DUP4 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 DUP2 SWAP1 SSTORE DUP4 MLOAD PUSH1 0xC3 PUSH1 0x2 EXP PUSH8 0xDAC2F0A0CAE4A8F MUL DUP2 DUP8 ADD MSTORE PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND PUSH1 0x60 PUSH1 0x2 EXP MUL PUSH1 0x28 DUP3 ADD MSTORE DUP5 MLOAD DUP1 DUP3 SUB PUSH1 0x1C ADD DUP2 MSTORE PUSH1 0x3C SWAP1 SWAP2 ADD SWAP5 DUP6 SWAP1 MSTORE DUP1 MLOAD SWAP2 SWAP6 DUP7 SWAP6 SWAP2 SWAP5 POP SWAP1 SWAP3 POP DUP3 SWAP2 SWAP1 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0xB6F JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0xB50 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 DUP2 ADD SWAP7 SWAP1 SWAP7 MSTORE POP SWAP3 DUP4 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 DUP2 SWAP1 SSTORE DUP4 MLOAD PUSH1 0xC3 PUSH1 0x2 EXP PUSH8 0xDAD2DCA0CAE4A8F MUL DUP2 DUP8 ADD MSTORE PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND PUSH1 0x60 PUSH1 0x2 EXP MUL PUSH1 0x28 DUP3 ADD MSTORE DUP5 MLOAD DUP1 DUP3 SUB PUSH1 0x1C ADD DUP2 MSTORE PUSH1 0x3C SWAP1 SWAP2 ADD SWAP5 DUP6 SWAP1 MSTORE DUP1 MLOAD SWAP2 SWAP6 DUP7 SWAP6 SWAP2 SWAP5 POP SWAP1 SWAP3 POP DUP3 SWAP2 SWAP1 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0xC1E JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0xBFF JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 DUP2 ADD SWAP7 SWAP1 SWAP7 MSTORE POP SWAP3 DUP4 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 DUP2 SWAP1 SSTORE DUP4 MLOAD PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x42C7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP2 DUP8 ADD MSTORE PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND PUSH1 0x60 PUSH1 0x2 EXP MUL PUSH1 0x33 DUP3 ADD MSTORE DUP5 MLOAD DUP1 DUP3 SUB PUSH1 0x27 ADD DUP2 MSTORE PUSH1 0x47 SWAP1 SWAP2 ADD SWAP5 DUP6 SWAP1 MSTORE DUP1 MLOAD SWAP2 SWAP6 DUP7 SWAP6 SWAP2 SWAP5 POP SWAP1 SWAP3 POP DUP3 SWAP2 SWAP1 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0xCCD JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0xCAE JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 DUP2 ADD SWAP7 SWAP1 SWAP7 MSTORE POP SWAP3 DUP4 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 DUP2 SWAP1 SSTORE DUP4 MLOAD PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x44A7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP2 DUP8 ADD MSTORE PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND PUSH1 0x60 PUSH1 0x2 EXP MUL PUSH1 0x31 DUP3 ADD MSTORE DUP5 MLOAD DUP1 DUP3 SUB PUSH1 0x25 ADD DUP2 MSTORE PUSH1 0x45 SWAP1 SWAP2 ADD SWAP5 DUP6 SWAP1 MSTORE DUP1 MLOAD SWAP2 SWAP6 DUP7 SWAP6 SWAP2 SWAP5 POP SWAP1 SWAP3 POP DUP3 SWAP2 SWAP1 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0xD7C JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0xD5D JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 DUP2 SWAP1 SSTORE PUSH2 0x834 SWAP4 POP DUP5 SWAP3 POP SWAP1 POP PUSH2 0x2805 JUMP JUMPDEST PUSH2 0xDCF PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0xDE3 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xDEC DUP2 PUSH2 0x287B JUMP JUMPDEST POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH2 0xE13 DUP4 PUSH2 0xE07 DUP7 PUSH2 0xE02 PUSH2 0x1382 JUMP JUMPDEST PUSH2 0x1C02 JUMP JUMPDEST SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x28D5 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0xE21 PUSH1 0x0 PUSH2 0x2351 JUMP JUMPDEST GT DUP1 ISZERO PUSH2 0xE36 JUMPI POP DUP1 PUSH2 0xE33 DUP6 PUSH2 0x2351 JUMP JUMPDEST LT ISZERO JUMPDEST DUP1 ISZERO PUSH2 0xE4A JUMPI POP PUSH2 0xE46 DUP5 PUSH2 0x955 JUMP JUMPDEST DUP4 GT ISZERO JUMPDEST DUP1 ISZERO PUSH2 0xE5E JUMPI POP PUSH2 0xE5A DUP5 PUSH2 0x1B57 JUMP JUMPDEST DUP4 LT ISZERO JUMPDEST SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH2 0xE6E PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0xE82 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xE8A PUSH2 0x17C0 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH2 0xE9B PUSH2 0x28E2 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND EQ PUSH2 0xEAE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xEB7 DUP4 PUSH2 0xFDB JUMP JUMPDEST ISZERO ISZERO PUSH2 0xEC2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xECD DUP4 DUP4 DUP4 PUSH2 0x295A JUMP JUMPDEST POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x44A7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP2 MSTORE POP PUSH1 0x11 ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x9D7 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x9B8 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x88 PUSH1 0x2 EXP PUSH15 0x6D65646961746F7242616C616E6365 MUL DUP2 MSTORE POP PUSH1 0xF ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x9D7 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x9B8 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH2 0xFE7 DUP4 PUSH2 0x1B57 JUMP JUMPDEST GT SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH2 0xFF6 PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x100A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1013 DUP3 PUSH2 0xFDB JUMP JUMPDEST ISZERO ISZERO PUSH2 0x101E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1027 DUP3 PUSH2 0x955 JUMP JUMPDEST DUP2 GT DUP1 PUSH2 0x1032 JUMPI POP DUP1 ISZERO JUMPDEST ISZERO ISZERO PUSH2 0x103D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x0 DUP1 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xB2 PUSH1 0x2 EXP PUSH10 0x19185A5B1E531A5B5A5D MUL DUP2 MSTORE POP PUSH1 0xA ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x10C0 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x10A1 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 DUP2 ADD SWAP7 SWAP1 SWAP7 MSTORE POP SWAP3 DUP4 ADD PUSH1 0x0 KECCAK256 SWAP5 SWAP1 SWAP5 SSTORE POP DUP1 MLOAD DUP5 DUP2 MSTORE SWAP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP7 AND SWAP4 POP PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x42E7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SWAP3 SWAP2 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG2 POP POP JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x4 DUP2 MSTORE PUSH1 0x24 DUP2 ADD DUP3 MSTORE PUSH1 0x20 DUP2 ADD DUP1 MLOAD PUSH1 0x1 PUSH1 0xE0 PUSH1 0x2 EXP SUB AND PUSH1 0xE1 PUSH1 0x2 EXP PUSH4 0x37EF4101 MUL OR DUP2 MSTORE SWAP2 MLOAD DUP2 MLOAD PUSH1 0x0 SWAP4 ADDRESS SWAP4 SWAP3 SWAP2 DUP3 SWAP2 SWAP1 DUP1 DUP4 DUP4 DUP10 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1183 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x116B JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x11B0 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP2 POP POP PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP7 GAS CALL SWAP2 POP POP ISZERO DUP1 PUSH2 0x1242 JUMPI POP ADDRESS PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0x6FDE8202 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x120A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x121E JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1234 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ JUMPDEST DUP1 PUSH2 0x124C JUMPI POP CALLER ADDRESS EQ JUMPDEST ISZERO ISZERO PUSH2 0x1257 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x125F PUSH2 0x12FF JUMP JUMPDEST ISZERO PUSH2 0x1269 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1272 DUP8 PUSH2 0x287B JUMP JUMPDEST PUSH2 0x127B DUP7 PUSH2 0x2996 JUMP JUMPDEST PUSH2 0x12A9 PUSH1 0x0 DUP7 PUSH1 0x3 DUP1 PUSH1 0x20 MUL PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP3 SWAP2 SWAP1 DUP3 PUSH1 0x3 PUSH1 0x20 MUL DUP1 DUP3 DUP5 CALLDATACOPY POP PUSH2 0x29DC SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD DUP3 MSTORE PUSH2 0x12D2 SWAP2 PUSH1 0x0 SWAP2 SWAP1 DUP8 SWAP1 PUSH1 0x2 SWAP1 DUP4 SWAP1 DUP4 SWAP1 DUP1 DUP3 DUP5 CALLDATACOPY POP PUSH2 0x2C6C SWAP4 POP POP POP POP JUMP JUMPDEST PUSH2 0x12DB DUP4 PUSH2 0x2E09 JUMP JUMPDEST PUSH2 0x12E4 DUP3 PUSH2 0x2E46 JUMP JUMPDEST PUSH2 0x12EC PUSH2 0x2EEC JUMP JUMPDEST PUSH2 0x12F4 PUSH2 0x12FF JUMP JUMPDEST SWAP8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4387 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x4 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4307 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SLOAD PUSH1 0xFF AND SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH2 0x1344 DUP4 PUSH2 0xE07 DUP7 PUSH2 0x133F PUSH2 0x1382 JUMP JUMPDEST PUSH2 0x2273 JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x1352 PUSH1 0x0 PUSH2 0x138B JUMP JUMPDEST GT DUP1 ISZERO PUSH2 0x1367 JUMPI POP DUP1 PUSH2 0x1364 DUP6 PUSH2 0x138B JUMP JUMPDEST LT ISZERO JUMPDEST DUP1 ISZERO PUSH2 0xE5E JUMPI POP PUSH2 0x1377 DUP5 PUSH2 0xED2 JUMP JUMPDEST SWAP1 SWAP3 GT ISZERO SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH3 0x15180 TIMESTAMP DIV SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x42C7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP2 MSTORE POP PUSH1 0x13 ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x9D7 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x9B8 JUMP JUMPDEST PUSH1 0xE1 PUSH1 0x2 EXP PUSH4 0x58A8B613 MUL SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x4 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xA2 PUSH1 0x2 EXP PUSH12 0x1B595CDCD859D9519A5E1959 MUL DUP2 MSTORE POP PUSH1 0xC ADD DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x1491 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x1472 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 KECCAK256 SLOAD PUSH1 0xFF AND SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST ADDRESS PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0x6FDE8202 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1513 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x1527 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x153D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x1553 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP3 AND ISZERO DUP1 PUSH2 0x156F JUMPI POP PUSH2 0x156D DUP3 PUSH2 0xFDB JUMP JUMPDEST ISZERO JUMPDEST ISZERO ISZERO PUSH2 0x157A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x834 DUP3 DUP3 PUSH2 0x2F1F JUMP JUMPDEST PUSH2 0x158C PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x15A0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xDEC DUP2 PUSH2 0x2996 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x0 PUSH2 0x15BA DUP7 PUSH2 0x955 JUMP JUMPDEST SWAP4 POP PUSH2 0x15C5 DUP7 PUSH2 0x2351 JUMP JUMPDEST SWAP3 POP PUSH2 0x15D3 DUP7 PUSH2 0xE02 PUSH2 0x1382 JUMP JUMPDEST SWAP2 POP DUP2 DUP4 GT PUSH2 0x15E3 JUMPI PUSH1 0x0 PUSH2 0x15E7 JUMP JUMPDEST DUP2 DUP4 SUB JUMPDEST SWAP1 POP DUP1 DUP5 LT PUSH2 0x15F6 JUMPI DUP1 PUSH2 0x15F8 JUMP JUMPDEST DUP4 JUMPDEST SWAP7 SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH2 0x160A PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x161E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1627 DUP3 PUSH2 0xFDB JUMP JUMPDEST ISZERO ISZERO PUSH2 0x1632 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x163B DUP3 PUSH2 0xED2 JUMP JUMPDEST DUP2 GT DUP1 PUSH2 0x1646 JUMPI POP DUP1 ISZERO JUMPDEST ISZERO ISZERO PUSH2 0x1651 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x0 DUP1 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x42C7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP2 MSTORE POP PUSH1 0x13 ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x16D2 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x16B3 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 DUP2 ADD SWAP7 SWAP1 SWAP7 MSTORE POP SWAP3 DUP4 ADD PUSH1 0x0 KECCAK256 SWAP5 SWAP1 SWAP5 SSTORE POP DUP1 MLOAD DUP5 DUP2 MSTORE SWAP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP7 AND SWAP4 POP PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x43C7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SWAP3 SWAP2 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x44C7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP2 MSTORE POP PUSH1 0x1A ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x9D7 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x9B8 JUMP JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x43E7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x2 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4427 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4367 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x2 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4347 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x60 PUSH2 0x1832 PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0xCB08A10C DUP5 PUSH1 0x40 MLOAD DUP3 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1882 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x1896 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x18AC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD ISZERO PUSH2 0x18B8 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST ADDRESS PUSH2 0x18C1 PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0x3F9A8E7E DUP6 PUSH1 0x40 MLOAD DUP3 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1911 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x1925 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x193B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND EQ PUSH2 0x1950 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1958 PUSH2 0x17C0 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH2 0x1969 PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0x4A610B04 DUP6 PUSH1 0x40 MLOAD DUP3 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x19B9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x19CD JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x19E3 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND EQ PUSH2 0x19F8 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP POP PUSH1 0x40 DUP1 MLOAD PUSH1 0x24 DUP1 DUP3 ADD DUP5 SWAP1 MSTORE DUP3 MLOAD DUP1 DUP4 SUB SWAP1 SWAP2 ADD DUP2 MSTORE PUSH1 0x44 SWAP1 SWAP2 ADD SWAP1 SWAP2 MSTORE PUSH1 0x20 DUP2 ADD DUP1 MLOAD PUSH1 0x1 PUSH1 0xE0 PUSH1 0x2 EXP SUB AND PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x950D515 MUL SWAP1 DUP2 OR SWAP1 SWAP2 MSTORE SWAP1 PUSH2 0x1A41 PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0xDC8601B3 PUSH2 0x1A57 PUSH2 0x17C0 JUMP JUMPDEST DUP4 PUSH2 0x1A60 PUSH2 0x1D08 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP5 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP5 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH1 0x20 ADD DUP4 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP5 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1ACD JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x1AB5 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x1AFA JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP5 POP POP POP POP POP PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1B1B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x1B2F JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1B45 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP POP POP POP POP JUMP JUMPDEST PUSH1 0x1 PUSH1 0x2 PUSH1 0x0 SWAP1 SWAP2 SWAP3 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xC3 PUSH1 0x2 EXP PUSH8 0xDAD2DCA0CAE4A8F MUL DUP2 MSTORE POP PUSH1 0x8 ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x9D7 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x9B8 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH2 0x1BE3 PUSH2 0x2F58 JUMP JUMPDEST ISZERO ISZERO PUSH2 0x1BF7 JUMPI POP CALLER PUSH2 0x1BF7 DUP2 DUP7 DUP7 DUP7 PUSH2 0x2F85 JUMP JUMPDEST POP PUSH1 0x1 SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP5 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x80 PUSH1 0x2 EXP PUSH16 0x746F74616C5370656E74506572446179 MUL DUP2 MSTORE POP PUSH1 0x10 ADD DUP4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP3 POP POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x1C94 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x1C75 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 KECCAK256 SLOAD SWAP4 POP POP POP POP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH2 0xECD DUP4 DUP4 DUP4 PUSH2 0x245A JUMP JUMPDEST PUSH2 0x1CEB PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x1CFF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xDEC DUP2 PUSH2 0x33B9 JUMP JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4467 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x43A7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SLOAD SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4407 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x2 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4487 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x60 PUSH1 0x0 ADDRESS PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0x6FDE8202 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1DAD JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x1DC1 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1DD7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x1DED JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP7 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP2 AND ISZERO ISZERO PUSH2 0x1E03 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1E0C DUP10 PUSH2 0xFDB JUMP JUMPDEST ISZERO ISZERO PUSH2 0x1E17 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x70A08231 MUL DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP12 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1E62 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x1E76 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1E8C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP7 POP PUSH2 0x1E99 DUP10 PUSH2 0xF53 JUMP JUMPDEST SWAP6 POP DUP6 DUP8 GT PUSH2 0x1EA7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP6 DUP8 SUB SWAP5 POP PUSH2 0x1EB5 DUP10 PUSH2 0x15A9 JUMP JUMPDEST SWAP4 POP PUSH1 0x0 DUP5 GT PUSH2 0x1EC4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP4 DUP6 GT ISZERO PUSH2 0x1ED0 JUMPI DUP4 SWAP5 POP JUMPDEST PUSH2 0x1EE2 DUP10 PUSH2 0x1EDC PUSH2 0x1382 JUMP JUMPDEST DUP8 PUSH2 0x34E5 JUMP JUMPDEST PUSH2 0x1EFB DUP10 PUSH2 0x1EF6 DUP9 DUP9 PUSH4 0xFFFFFFFF PUSH2 0x28D5 AND JUMP JUMPDEST PUSH2 0x35C6 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP1 DUP13 AND PUSH1 0x24 DUP4 ADD MSTORE DUP11 AND PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 DUP1 DUP3 ADD DUP9 SWAP1 MSTORE DUP3 MLOAD DUP1 DUP4 SUB SWAP1 SWAP2 ADD DUP2 MSTORE PUSH1 0x84 SWAP1 SWAP2 ADD SWAP1 SWAP2 MSTORE PUSH1 0x20 DUP2 ADD DUP1 MLOAD PUSH1 0x1 PUSH1 0xE0 PUSH1 0x2 EXP SUB AND PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x125E4CFB MUL OR SWAP1 MSTORE SWAP3 POP PUSH2 0x1F57 PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0xDC8601B3 PUSH2 0x1F6D PUSH2 0x17C0 JUMP JUMPDEST DUP6 PUSH2 0x1F76 PUSH2 0x1D08 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP5 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP5 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH1 0x20 ADD DUP4 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP5 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1FE3 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x1FCB JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x2010 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP5 POP POP POP POP POP PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x2031 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x2045 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x205B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP2 POP PUSH2 0x2069 DUP3 DUP11 PUSH2 0x364D JUMP JUMPDEST PUSH2 0x2073 DUP3 DUP7 PUSH2 0x3720 JUMP JUMPDEST PUSH2 0x207D DUP3 DUP10 PUSH2 0x3794 JUMP JUMPDEST POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH2 0x2090 PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x20A4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x20AD DUP3 PUSH2 0xFDB JUMP JUMPDEST ISZERO ISZERO PUSH2 0x20B8 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 ISZERO DUP1 PUSH2 0x20DE JUMPI POP PUSH2 0x20C9 DUP3 PUSH2 0x1B57 JUMP JUMPDEST DUP2 GT DUP1 ISZERO PUSH2 0x20DE JUMPI POP PUSH2 0x20DB DUP3 PUSH2 0x2351 JUMP JUMPDEST DUP2 LT JUMPDEST ISZERO ISZERO PUSH2 0x20E9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x0 DUP1 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xC3 PUSH1 0x2 EXP PUSH8 0xDAC2F0A0CAE4A8F MUL DUP2 MSTORE POP PUSH1 0x8 ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x913 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x8F4 JUMP JUMPDEST PUSH2 0x2171 PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x2185 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xDEC DUP2 PUSH2 0x380D JUMP JUMPDEST PUSH2 0x2196 PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x21AA JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x21B3 DUP3 PUSH2 0xFDB JUMP JUMPDEST ISZERO ISZERO PUSH2 0x21BE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 DUP2 GT DUP1 ISZERO PUSH2 0x21D5 JUMPI POP PUSH2 0x21D2 DUP3 PUSH2 0x2351 JUMP JUMPDEST DUP2 LT JUMPDEST DUP1 ISZERO PUSH2 0x21E8 JUMPI POP PUSH2 0x21E5 DUP3 PUSH2 0x955 JUMP JUMPDEST DUP2 LT JUMPDEST ISZERO ISZERO PUSH2 0x21F3 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x0 DUP1 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xC3 PUSH1 0x2 EXP PUSH8 0xDAD2DCA0CAE4A8F MUL DUP2 MSTORE POP PUSH1 0x8 ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x913 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x8F4 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP5 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x68 PUSH1 0x2 EXP PUSH19 0x746F74616C4578656375746564506572446179 MUL DUP2 MSTORE POP PUSH1 0x13 ADD DUP4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP3 POP POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x1C94 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x1C75 JUMP JUMPDEST PUSH2 0x230F PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x2323 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xDEC DUP2 PUSH2 0x2E46 JUMP JUMPDEST PUSH2 0x2334 PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x2348 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xDEC DUP2 PUSH2 0x2E09 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xB2 PUSH1 0x2 EXP PUSH10 0x19185A5B1E531A5B5A5D MUL DUP2 MSTORE POP PUSH1 0xA ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x9D7 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x9B8 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x4 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xA2 PUSH1 0x2 EXP PUSH12 0x1D1BDAD95B905B1B1BDDD959 MUL DUP2 MSTORE POP PUSH1 0xC ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x1491 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x1472 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH2 0x2465 PUSH2 0x2F58 JUMP JUMPDEST ISZERO PUSH2 0x246F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x70A08231 MUL DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x24BA JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x24CE JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x24E4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP2 POP PUSH2 0x24F2 PUSH1 0x1 PUSH2 0x393A JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x23B872DD MUL DUP2 MSTORE CALLER PUSH1 0x4 DUP3 ADD MSTORE ADDRESS PUSH1 0x24 DUP3 ADD MSTORE PUSH1 0x44 DUP2 ADD DUP6 SWAP1 MSTORE SWAP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND SWAP2 PUSH4 0x23B872DD SWAP2 PUSH1 0x64 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x254A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x255E JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x2574 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x2581 SWAP1 POP PUSH1 0x0 PUSH2 0x393A JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x70A08231 MUL DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD PUSH2 0x260A SWAP2 DUP5 SWAP2 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP10 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x25D2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x25E6 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x25FC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x3971 AND JUMP JUMPDEST SWAP1 POP DUP3 DUP2 GT ISZERO PUSH2 0x2619 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1B45 DUP6 CALLER DUP4 DUP8 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH2 0x2F85 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 PUSH2 0x2669 PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND CALLER EQ PUSH2 0x267D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x2685 PUSH2 0x17C0 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH2 0x2696 PUSH2 0x28E2 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND EQ PUSH2 0x26A9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x26B2 DUP5 PUSH2 0x141A JUMP JUMPDEST ISZERO PUSH2 0x26BC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x26C5 DUP5 PUSH2 0x2744 JUMP JUMPDEST SWAP3 POP PUSH2 0x26D0 DUP5 PUSH2 0x3983 JUMP JUMPDEST SWAP2 POP PUSH2 0x26DB DUP5 PUSH2 0x39FD JUMP JUMPDEST SWAP1 POP PUSH2 0x26E6 DUP5 PUSH2 0x3A72 JUMP JUMPDEST PUSH2 0x26F1 DUP4 DUP4 DUP4 PUSH2 0x3B36 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP1 DUP7 AND DUP3 MSTORE DUP5 AND PUSH1 0x20 DUP3 ADD MSTORE DUP1 DUP3 ADD DUP4 SWAP1 MSTORE SWAP1 MLOAD DUP6 SWAP2 PUSH32 0x7B5483B8E4BD8EA240A474D5117738350E7D431E3668C48A97910B0B397796A SWAP2 SWAP1 DUP2 SWAP1 SUB PUSH1 0x60 ADD SWAP1 LOG2 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x2 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xA1 PUSH1 0x2 EXP PUSH12 0x36B2B9B9B0B3B2AA37B5B2B7 MUL DUP2 MSTORE POP PUSH1 0xC ADD DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x27BB JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x279C JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 KECCAK256 SLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x44C7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x20 DUP1 DUP4 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x60 PUSH1 0x2 EXP PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP7 AND MUL PUSH1 0x3A DUP4 ADD MSTORE DUP3 MLOAD PUSH1 0x2E DUP2 DUP5 SUB ADD DUP2 MSTORE PUSH1 0x4E SWAP1 SWAP3 ADD SWAP3 DUP4 SWAP1 MSTORE DUP2 MLOAD DUP5 SWAP4 PUSH1 0x0 SWAP4 DUP5 SWAP4 SWAP1 SWAP3 DUP3 SWAP2 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x913 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x8F4 JUMP JUMPDEST PUSH2 0x2884 DUP2 PUSH2 0x3B6D JUMP JUMPDEST ISZERO ISZERO PUSH2 0x288F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4407 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x2 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4487 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP1 SLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB NOT AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB SWAP3 SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE JUMP JUMPDEST DUP2 DUP2 ADD DUP3 DUP2 LT ISZERO PUSH2 0x1CD2 JUMPI INVALID JUMPDEST PUSH1 0x0 PUSH2 0x28EC PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0xD67BDD25 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x2929 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x293D JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x2953 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP1 POP SWAP1 JUMP JUMPDEST PUSH2 0x2964 DUP4 DUP3 PUSH2 0x132C JUMP JUMPDEST ISZERO PUSH2 0x298B JUMPI PUSH2 0x297B DUP4 PUSH2 0x2975 PUSH2 0x1382 JUMP JUMPDEST DUP4 PUSH2 0x3B75 JUMP JUMPDEST PUSH2 0x2986 DUP4 DUP4 DUP4 PUSH2 0x3C15 JUMP JUMPDEST PUSH2 0xECD JUMP JUMPDEST PUSH2 0xECD DUP4 DUP4 DUP4 PUSH2 0x1F5 JUMP JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x43E7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x2 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4427 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP1 SLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB NOT AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB SWAP3 SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE JUMP JUMPDEST PUSH1 0x40 DUP2 ADD MLOAD PUSH1 0x0 LT DUP1 ISZERO PUSH2 0x29F7 JUMPI POP PUSH1 0x40 DUP2 ADD MLOAD PUSH1 0x20 DUP3 ADD MLOAD GT JUMPDEST DUP1 ISZERO PUSH2 0x2A07 JUMPI POP PUSH1 0x20 DUP2 ADD MLOAD DUP2 MLOAD GT JUMPDEST ISZERO ISZERO PUSH2 0x2A12 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 MLOAD PUSH1 0x40 DUP1 MLOAD PUSH1 0xB2 PUSH1 0x2 EXP PUSH10 0x19185A5B1E531A5B5A5D MUL PUSH1 0x20 DUP3 DUP2 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x60 PUSH1 0x2 EXP PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND MUL PUSH1 0x2A DUP4 ADD MSTORE DUP3 MLOAD PUSH1 0x1E DUP2 DUP5 SUB ADD DUP2 MSTORE PUSH1 0x3E SWAP1 SWAP3 ADD SWAP3 DUP4 SWAP1 MSTORE DUP2 MLOAD PUSH1 0x0 SWAP4 DUP5 SWAP4 SWAP3 SWAP1 SWAP2 DUP3 SWAP2 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x2A8C JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x2A6D JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 DUP2 ADD SWAP7 SWAP1 SWAP7 MSTORE POP SWAP3 DUP4 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 SWAP6 SWAP1 SWAP6 SSTORE POP POP DUP4 DUP3 ADD MLOAD DUP2 MLOAD PUSH1 0xC3 PUSH1 0x2 EXP PUSH8 0xDAC2F0A0CAE4A8F MUL DUP2 DUP6 ADD MSTORE PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND PUSH1 0x60 PUSH1 0x2 EXP MUL PUSH1 0x28 DUP3 ADD MSTORE DUP3 MLOAD DUP1 DUP3 SUB PUSH1 0x1C ADD DUP2 MSTORE PUSH1 0x3C SWAP1 SWAP2 ADD SWAP3 DUP4 SWAP1 MSTORE DUP1 MLOAD SWAP2 SWAP5 SWAP4 DUP5 SWAP4 SWAP2 SWAP3 DUP3 SWAP2 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x2B3E JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x2B1F JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 DUP2 ADD SWAP7 SWAP1 SWAP7 MSTORE POP SWAP3 DUP4 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 SWAP6 SWAP1 SWAP6 SSTORE POP POP DUP4 DUP2 ADD MLOAD DUP2 MLOAD PUSH1 0xC3 PUSH1 0x2 EXP PUSH8 0xDAD2DCA0CAE4A8F MUL DUP2 DUP6 ADD MSTORE PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND PUSH1 0x60 PUSH1 0x2 EXP MUL PUSH1 0x28 DUP3 ADD MSTORE DUP3 MLOAD DUP1 DUP3 SUB PUSH1 0x1C ADD DUP2 MSTORE PUSH1 0x3C SWAP1 SWAP2 ADD SWAP3 DUP4 SWAP1 MSTORE DUP1 MLOAD SWAP2 SWAP5 SWAP4 DUP5 SWAP4 SWAP2 SWAP3 DUP3 SWAP2 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x2BF0 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x2BD1 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 SWAP5 SWAP1 SWAP5 SSTORE POP POP POP PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP4 AND SWAP1 PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x42E7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SWAP1 DUP4 SWAP1 JUMPDEST PUSH1 0x20 MUL ADD MLOAD PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG2 POP POP JUMP JUMPDEST DUP1 MLOAD PUSH1 0x20 DUP3 ADD MLOAD LT PUSH2 0x2C7D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 MLOAD PUSH1 0x40 DUP1 MLOAD PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x42C7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x20 DUP3 DUP2 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x60 PUSH1 0x2 EXP PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND MUL PUSH1 0x33 DUP4 ADD MSTORE DUP3 MLOAD PUSH1 0x27 DUP2 DUP5 SUB ADD DUP2 MSTORE PUSH1 0x47 SWAP1 SWAP3 ADD SWAP3 DUP4 SWAP1 MSTORE DUP2 MLOAD PUSH1 0x0 SWAP4 DUP5 SWAP4 SWAP3 SWAP1 SWAP2 DUP3 SWAP2 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x2CF5 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x2CD6 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 DUP2 ADD SWAP7 SWAP1 SWAP7 MSTORE POP SWAP3 DUP4 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 SWAP6 SWAP1 SWAP6 SSTORE POP POP DUP4 DUP3 ADD MLOAD DUP2 MLOAD PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x44A7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP2 DUP6 ADD MSTORE PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP8 AND PUSH1 0x60 PUSH1 0x2 EXP MUL PUSH1 0x31 DUP3 ADD MSTORE DUP3 MLOAD DUP1 DUP3 SUB PUSH1 0x25 ADD DUP2 MSTORE PUSH1 0x45 SWAP1 SWAP2 ADD SWAP3 DUP4 SWAP1 MSTORE DUP1 MLOAD SWAP2 SWAP5 SWAP4 DUP5 SWAP4 SWAP2 SWAP3 DUP3 SWAP2 DUP5 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x2DA7 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x2D88 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 SWAP5 SWAP1 SWAP5 SSTORE POP POP POP PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP4 AND SWAP1 PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x43C7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SWAP1 DUP4 SWAP1 PUSH2 0x2C4E JUMP JUMPDEST PUSH2 0x2E11 PUSH2 0x3C98 JUMP JUMPDEST DUP2 GT ISZERO PUSH2 0x2E1D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4467 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x43A7 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SSTORE JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP2 AND ISZERO ISZERO PUSH2 0x2E5B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH32 0x8BE0079C531659141344CD1FD0A4F28419497F9722A3DAAFE3B4186F6B6457E0 PUSH2 0x2E84 PUSH2 0x17F3 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB SWAP3 DUP4 AND DUP2 MSTORE SWAP2 DUP5 AND PUSH1 0x20 DUP4 ADD MSTORE DUP1 MLOAD SWAP2 DUP3 SWAP1 SUB ADD SWAP1 LOG1 PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4367 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x2 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4347 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP1 SLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB NOT AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB SWAP3 SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE JUMP JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4387 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x4 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4307 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP1 SLOAD PUSH1 0xFF NOT AND PUSH1 0x1 OR SWAP1 SSTORE JUMP JUMPDEST DUP1 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP2 AND ISZERO ISZERO PUSH2 0x2F35 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP4 AND ISZERO ISZERO PUSH2 0x2F4E JUMPI PUSH2 0x2986 DUP3 PUSH2 0x3CDF JUMP JUMPDEST PUSH2 0xECD DUP4 DUP4 PUSH2 0x3CEB JUMP JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4447 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x4 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4327 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE SLOAD PUSH1 0xFF AND SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x60 DUP1 PUSH1 0x0 PUSH1 0x60 PUSH1 0x0 DUP1 PUSH2 0x2F99 PUSH2 0x2F58 JUMP JUMPDEST ISZERO PUSH2 0x2FA3 JUMPI PUSH2 0x33AC JUMP JUMPDEST PUSH2 0x2FAC DUP12 PUSH2 0x23D4 JUMP JUMPDEST ISZERO ISZERO PUSH2 0x2FB7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x2FC0 DUP12 PUSH2 0xFDB JUMP JUMPDEST SWAP7 POP DUP7 ISZERO ISZERO PUSH2 0x3013 JUMPI PUSH2 0x2FD2 DUP12 PUSH2 0x3D88 JUMP JUMPDEST SWAP6 POP PUSH2 0x2FDD DUP12 PUSH2 0x3E6D JUMP JUMPDEST SWAP5 POP PUSH2 0x2FE8 DUP12 PUSH2 0x3EC3 JUMP JUMPDEST SWAP4 POP PUSH1 0x0 DUP7 MLOAD GT DUP1 PUSH2 0x2FFB JUMPI POP PUSH1 0x0 DUP6 MLOAD GT JUMPDEST ISZERO ISZERO PUSH2 0x3006 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x3013 DUP12 DUP6 PUSH1 0xFF AND PUSH2 0x3F15 JUMP JUMPDEST PUSH2 0x301D DUP12 DUP11 PUSH2 0xDEF JUMP JUMPDEST ISZERO ISZERO PUSH2 0x3028 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x303A DUP12 PUSH2 0x3034 PUSH2 0x1382 JUMP JUMPDEST DUP12 PUSH2 0x34E5 JUMP JUMPDEST PUSH2 0x3044 DUP11 DUP10 PUSH2 0x40AB JUMP JUMPDEST SWAP2 POP DUP7 ISZERO PUSH2 0x30A5 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP1 DUP15 AND PUSH1 0x24 DUP4 ADD MSTORE DUP5 AND PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 DUP1 DUP3 ADD DUP13 SWAP1 MSTORE DUP3 MLOAD DUP1 DUP4 SUB SWAP1 SWAP2 ADD DUP2 MSTORE PUSH1 0x84 SWAP1 SWAP2 ADD SWAP1 SWAP2 MSTORE PUSH1 0x20 DUP2 ADD DUP1 MLOAD PUSH1 0x1 PUSH1 0xE0 PUSH1 0x2 EXP SUB AND PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x125E4CFB MUL OR SWAP1 MSTORE SWAP3 POP PUSH2 0x3215 JUMP JUMPDEST ADDRESS PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0x2AE87CDD SWAP1 POP PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP12 DUP8 DUP8 DUP8 DUP7 DUP15 PUSH1 0x40 MLOAD PUSH1 0x24 ADD DUP1 DUP8 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH1 0x20 ADD DUP1 PUSH1 0x20 ADD DUP7 PUSH1 0xFF AND PUSH1 0xFF AND DUP2 MSTORE PUSH1 0x20 ADD DUP6 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND DUP2 MSTORE PUSH1 0x20 ADD DUP5 DUP2 MSTORE PUSH1 0x20 ADD DUP4 DUP2 SUB DUP4 MSTORE DUP9 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x3148 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x3130 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x3175 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP DUP4 DUP2 SUB DUP3 MSTORE DUP8 MLOAD DUP2 MSTORE DUP8 MLOAD PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 DUP10 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x31A8 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x3190 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x31D5 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP PUSH1 0x40 DUP1 MLOAD PUSH1 0x1F NOT DUP2 DUP5 SUB ADD DUP2 MSTORE SWAP2 SWAP1 MSTORE PUSH1 0x20 DUP2 ADD DUP1 MLOAD PUSH1 0x1 PUSH1 0xE0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xE0 PUSH1 0x2 EXP SUB NOT SWAP1 SWAP13 AND SWAP12 SWAP1 SWAP12 OR SWAP1 SWAP11 MSTORE POP SWAP8 SWAP11 POP POP POP POP POP POP POP POP POP JUMPDEST PUSH2 0x3226 DUP12 PUSH2 0x1EF6 DUP12 PUSH2 0xE07 DUP16 PUSH2 0xF53 JUMP JUMPDEST PUSH2 0x322E PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0xDC8601B3 PUSH2 0x3244 PUSH2 0x17C0 JUMP JUMPDEST DUP6 PUSH2 0x324D PUSH2 0x1D08 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP5 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP5 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH1 0x20 ADD DUP4 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP5 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x32BA JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x32A2 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x32E7 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP5 POP POP POP POP POP PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x3308 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x331C JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x3332 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP1 POP PUSH2 0x3340 DUP2 DUP13 PUSH2 0x364D JUMP JUMPDEST PUSH2 0x334A DUP2 DUP11 PUSH2 0x3720 JUMP JUMPDEST PUSH2 0x3354 DUP2 DUP12 PUSH2 0x3794 JUMP JUMPDEST DUP7 ISZERO ISZERO PUSH2 0x3365 JUMPI PUSH2 0x3365 DUP12 DUP3 PUSH2 0x2805 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP11 DUP2 MSTORE SWAP1 MLOAD DUP3 SWAP2 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP1 DUP15 AND SWAP3 SWAP1 DUP16 AND SWAP2 PUSH32 0x59A9A8027B9C87B961E254899821C9A276B5EFC35D1F7409EA4F291470F1629A SWAP2 SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 LOG4 JUMPDEST POP POP POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH2 0x33C2 DUP2 PUSH2 0x23D4 JUMP JUMPDEST ISZERO PUSH2 0x33CC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x33D5 DUP2 PUSH2 0x3B6D JUMP JUMPDEST ISZERO ISZERO PUSH2 0x33E0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x1 PUSH1 0x4 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xA2 PUSH1 0x2 EXP PUSH12 0x1D1BDAD95B905B1B1BDDD959 MUL DUP2 MSTORE POP PUSH1 0xC ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x3467 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x3448 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 DUP4 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 DUP1 SLOAD PUSH1 0xFF NOT AND SWAP7 ISZERO ISZERO SWAP7 SWAP1 SWAP7 OR SWAP1 SWAP6 SSTORE POP POP MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP5 AND SWAP3 PUSH32 0xBECEB48AEAA805AEAE57BE163CCA6249077A18734E408A85AA74E875C4373809 SWAP3 POP SWAP1 LOG2 POP JUMP JUMPDEST PUSH2 0x34F3 DUP2 PUSH2 0xE07 DUP6 DUP6 PUSH2 0x1C02 JUMP JUMPDEST PUSH1 0x0 DUP1 DUP6 DUP6 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x80 PUSH1 0x2 EXP PUSH16 0x746F74616C5370656E74506572446179 MUL DUP2 MSTORE POP PUSH1 0x10 ADD DUP4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP3 POP POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x3583 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x3564 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 KECCAK256 SWAP4 SWAP1 SWAP4 SSTORE POP POP POP POP POP POP JUMP JUMPDEST DUP1 PUSH1 0x0 DUP1 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x88 PUSH1 0x2 EXP PUSH15 0x6D65646961746F7242616C616E6365 MUL DUP2 MSTORE POP PUSH1 0xF ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x913 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x8F4 JUMP JUMPDEST DUP1 PUSH1 0x2 PUSH1 0x0 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xA1 PUSH1 0x2 EXP PUSH12 0x36B2B9B9B0B3B2AA37B5B2B7 MUL DUP2 MSTORE POP PUSH1 0xC ADD DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x36C3 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x36A4 JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 KECCAK256 DUP1 SLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB NOT AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB SWAP6 SWAP1 SWAP6 AND SWAP5 SWAP1 SWAP5 OR SWAP1 SWAP4 SSTORE POP POP POP POP POP JUMP JUMPDEST DUP1 PUSH1 0x0 DUP1 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xA0 PUSH1 0x2 EXP PUSH12 0x6D65737361676556616C7565 MUL DUP2 MSTORE POP PUSH1 0xC ADD DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x913 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x8F4 JUMP JUMPDEST DUP1 PUSH1 0x2 PUSH1 0x0 DUP5 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x82 PUSH1 0x2 EXP PUSH16 0x1B595CDCD859D9549958DA5C1A595B9D MUL DUP2 MSTORE POP PUSH1 0x10 ADD DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x36C3 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x36A4 JUMP JUMPDEST PUSH2 0x3816 DUP2 PUSH2 0x23D4 JUMP JUMPDEST ISZERO ISZERO PUSH2 0x3821 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x382A DUP2 PUSH2 0x3B6D JUMP JUMPDEST ISZERO ISZERO PUSH2 0x3835 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 PUSH1 0x4 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xA2 PUSH1 0x2 EXP PUSH12 0x1D1BDAD95B905B1B1BDDD959 MUL DUP2 MSTORE POP PUSH1 0xC ADD DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x38BC JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x389D JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 DUP4 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 DUP1 SLOAD PUSH1 0xFF NOT AND SWAP7 ISZERO ISZERO SWAP7 SWAP1 SWAP7 OR SWAP1 SWAP6 SSTORE POP POP MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP5 AND SWAP3 PUSH32 0xEAA9136602E3B70A4E689B5B6F55BDA25CA62B917D839C0FF87F5902387F77B9 SWAP3 POP SWAP1 LOG2 POP JUMP JUMPDEST PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4447 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE PUSH1 0x0 MSTORE PUSH1 0x4 PUSH1 0x20 MSTORE PUSH1 0x0 DUP1 MLOAD PUSH1 0x20 PUSH2 0x4327 DUP4 CODECOPY DUP2 MLOAD SWAP2 MSTORE DUP1 SLOAD PUSH1 0xFF NOT AND SWAP2 ISZERO ISZERO SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE JUMP JUMPDEST PUSH1 0x0 DUP3 DUP3 GT ISZERO PUSH2 0x397D JUMPI INVALID JUMPDEST POP SWAP1 SUB SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x2 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x82 PUSH1 0x2 EXP PUSH16 0x1B595CDCD859D9549958DA5C1A595B9D MUL DUP2 MSTORE POP PUSH1 0x10 ADD DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x27BB JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x279C JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xA0 PUSH1 0x2 EXP PUSH12 0x6D65737361676556616C7565 MUL DUP2 MSTORE POP PUSH1 0xC ADD DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x9D7 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x9B8 JUMP JUMPDEST PUSH1 0x1 PUSH1 0x4 PUSH1 0x0 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0xA2 PUSH1 0x2 EXP PUSH12 0x1B595CDCD859D9519A5E1959 MUL DUP2 MSTORE POP PUSH1 0xC ADD DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x3AE9 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x3ACA JUMP JUMPDEST MLOAD DUP2 MLOAD PUSH1 0x20 SWAP4 DUP5 SUB PUSH2 0x100 EXP PUSH1 0x0 NOT ADD DUP1 NOT SWAP1 SWAP3 AND SWAP2 AND OR SWAP1 MSTORE PUSH1 0x40 DUP1 MLOAD SWAP3 SWAP1 SWAP5 ADD DUP3 SWAP1 SUB SWAP1 SWAP2 KECCAK256 DUP7 MSTORE DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE SWAP3 SWAP1 SWAP3 ADD PUSH1 0x0 KECCAK256 DUP1 SLOAD PUSH1 0xFF NOT AND SWAP5 ISZERO ISZERO SWAP5 SWAP1 SWAP5 OR SWAP1 SWAP4 SSTORE POP POP POP POP JUMP JUMPDEST PUSH2 0x3B53 DUP4 PUSH2 0x1EF6 DUP4 PUSH2 0x3B47 DUP8 PUSH2 0xF53 JUMP JUMPDEST SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x3971 AND JUMP JUMPDEST PUSH2 0xECD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP5 AND DUP4 DUP4 PUSH4 0xFFFFFFFF PUSH2 0x4105 AND JUMP JUMPDEST PUSH1 0x0 SWAP1 EXTCODESIZE GT SWAP1 JUMP JUMPDEST PUSH2 0x3B83 DUP2 PUSH2 0xE07 DUP6 DUP6 PUSH2 0x2273 JUMP JUMPDEST PUSH1 0x0 DUP1 DUP6 DUP6 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP1 PUSH1 0x68 PUSH1 0x2 EXP PUSH19 0x746F74616C4578656375746564506572446179 MUL DUP2 MSTORE POP PUSH1 0x13 ADD DUP4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x60 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x14 ADD DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP3 POP POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 DUP3 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x20 DUP4 LT PUSH2 0x3583 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH1 0x1F NOT SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x3564 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x3C1F PUSH2 0x419A JUMP JUMPDEST SWAP1 POP PUSH2 0x3C3B PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP6 AND DUP5 DUP5 PUSH4 0xFFFFFFFF PUSH2 0x4105 AND JUMP JUMPDEST PUSH2 0x3C4C DUP5 PUSH2 0x1EF6 DUP5 PUSH2 0x3B47 DUP9 PUSH2 0xF53 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP4 DUP2 MSTORE SWAP1 MLOAD DUP3 SWAP2 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP1 DUP8 AND SWAP3 SWAP1 DUP9 AND SWAP2 PUSH32 0x9AFD47907E25028CDACA89D193518C302BBB128617D5A992C5ABD45815526593 SWAP2 SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 LOG4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x3CA2 PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0xE5789D03 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x2929 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST ADDRESS BALANCE PUSH2 0x834 DUP3 DUP3 PUSH2 0x41E1 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x70A08231 MUL DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD DUP4 SWAP2 PUSH1 0x0 SWAP2 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP5 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP8 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x3D3A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x3D4E JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x3D64 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP1 POP PUSH2 0x3D82 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP6 AND DUP5 DUP4 PUSH4 0xFFFFFFFF PUSH2 0x4105 AND JUMP JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x6FDDE03 MUL DUP2 MSTORE PUSH1 0x60 SWAP1 PUSH1 0x0 DUP3 PUSH1 0x20 DUP4 PUSH1 0x4 DUP2 DUP9 GAS STATICCALL ISZERO ISZERO PUSH2 0x3DC5 JUMPI PUSH1 0xE1 PUSH1 0x2 EXP PUSH4 0x51FA6FBF MUL DUP4 MSTORE PUSH1 0x20 DUP4 PUSH1 0x4 DUP6 DUP9 GAS STATICCALL POP JUMPDEST RETURNDATASIZE DUP4 ADD PUSH1 0x40 MSTORE PUSH1 0x20 RETURNDATASIZE GT PUSH1 0x1 DUP2 EQ PUSH2 0x3DDF JUMPI RETURNDATASIZE SWAP3 POP PUSH2 0x3DED JUMP JUMPDEST PUSH1 0x20 DUP1 PUSH1 0x40 MLOAD RETURNDATACOPY PUSH1 0x40 MLOAD MLOAD SWAP3 POP JUMPDEST POP DUP2 PUSH1 0x40 MLOAD SWAP1 DUP1 DUP3 MSTORE DUP1 PUSH1 0x1F ADD PUSH1 0x1F NOT AND PUSH1 0x20 ADD DUP3 ADD PUSH1 0x40 MSTORE DUP1 ISZERO PUSH2 0x3E1C JUMPI DUP2 PUSH1 0x20 ADD PUSH1 0x20 DUP3 MUL DUP1 CODESIZE DUP4 CODECOPY ADD SWAP1 POP JUMPDEST POP SWAP1 POP PUSH1 0x20 RETURNDATASIZE GT ISZERO PUSH2 0x3E35 JUMPI DUP2 PUSH1 0x40 PUSH1 0x20 DUP4 ADD RETURNDATACOPY PUSH2 0xE5E JUMP JUMPDEST PUSH1 0x0 RETURNDATASIZE GT ISZERO PUSH2 0xE5E JUMPI PUSH1 0x0 DUP4 MLOAD SWAP4 POP DUP4 PUSH1 0x20 DUP4 ADD MSTORE JUMPDEST PUSH1 0x0 DUP5 GT ISZERO PUSH2 0x3E63 JUMPI PUSH1 0x8 SWAP4 SWAP1 SWAP4 SHL SWAP3 PUSH1 0x1 ADD PUSH2 0x3E4B JUMP JUMPDEST DUP2 MSTORE SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x95D89B41 MUL DUP2 MSTORE PUSH1 0x60 SWAP1 PUSH1 0x0 DUP3 PUSH1 0x20 DUP4 PUSH1 0x4 DUP2 DUP9 GAS STATICCALL ISZERO ISZERO PUSH2 0x3DC5 JUMPI PUSH1 0xE3 PUSH1 0x2 EXP PUSH4 0x1EEDF1AF MUL DUP4 MSTORE PUSH1 0x20 DUP4 PUSH1 0x4 DUP6 DUP9 GAS STATICCALL POP RETURNDATASIZE DUP4 ADD PUSH1 0x40 MSTORE PUSH1 0x20 RETURNDATASIZE GT PUSH1 0x1 DUP2 EQ PUSH2 0x3DDF JUMPI RETURNDATASIZE SWAP3 POP PUSH2 0x3DED JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 ADD PUSH1 0x40 MSTORE PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x313CE567 MUL DUP2 MSTORE PUSH1 0x20 DUP2 PUSH1 0x4 DUP4 DUP8 GAS STATICCALL ISZERO ISZERO PUSH2 0x3F0D JUMPI PUSH1 0xE0 PUSH1 0x2 EXP PUSH4 0x2E0F2625 MUL DUP2 MSTORE PUSH1 0x20 DUP2 PUSH1 0x4 DUP4 DUP8 GAS STATICCALL ISZERO ISZERO PUSH2 0x3F0D JUMPI PUSH1 0x0 DUP2 MSTORE JUMPDEST MLOAD SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x12 DUP8 LT ISZERO PUSH2 0x400A JUMPI DUP7 PUSH1 0x12 SUB PUSH1 0xA EXP SWAP6 POP PUSH2 0x3F4A DUP7 PUSH2 0x3F3E PUSH1 0x0 PUSH2 0x1B57 JUMP JUMPDEST SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x4242 AND JUMP JUMPDEST SWAP5 POP PUSH2 0x3F5A DUP7 PUSH2 0x3F3E PUSH1 0x0 PUSH2 0x955 JUMP JUMPDEST SWAP4 POP PUSH2 0x3F6A DUP7 PUSH2 0x3F3E PUSH1 0x0 PUSH2 0x2351 JUMP JUMPDEST SWAP3 POP PUSH2 0x3F7A DUP7 PUSH2 0x3F3E PUSH1 0x0 PUSH2 0xED2 JUMP JUMPDEST SWAP2 POP PUSH2 0x3F8A DUP7 PUSH2 0x3F3E PUSH1 0x0 PUSH2 0x138B JUMP JUMPDEST SWAP1 POP DUP5 ISZERO ISZERO PUSH2 0x3FC2 JUMPI PUSH1 0x1 SWAP5 POP DUP5 DUP5 GT PUSH2 0x3FC2 JUMPI PUSH1 0x64 SWAP4 POP PUSH1 0x64 SWAP2 POP DUP4 DUP4 GT ISZERO DUP1 PUSH2 0x3FB5 JUMPI POP DUP2 DUP2 GT ISZERO JUMPDEST ISZERO PUSH2 0x3FC2 JUMPI POP PUSH2 0x2710 SWAP2 POP DUP2 JUMPDEST PUSH2 0x3FE7 DUP9 PUSH1 0x60 PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 DUP7 DUP2 MSTORE PUSH1 0x20 ADD DUP8 DUP2 MSTORE PUSH1 0x20 ADD DUP9 DUP2 MSTORE POP PUSH2 0x29DC JUMP JUMPDEST PUSH2 0x4005 DUP9 PUSH1 0x40 DUP1 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 DUP5 DUP2 MSTORE PUSH1 0x20 ADD DUP6 DUP2 MSTORE POP PUSH2 0x2C6C JUMP JUMPDEST PUSH2 0x40A1 JUMP JUMPDEST PUSH1 0x12 DUP8 SUB PUSH1 0xA EXP SWAP6 POP PUSH2 0x406A DUP9 PUSH1 0x60 PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 PUSH2 0x403D DUP11 PUSH2 0x4031 PUSH1 0x0 PUSH2 0x2351 JUMP JUMPDEST SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x4257 AND JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x4050 DUP11 PUSH2 0x4031 PUSH1 0x0 PUSH2 0x955 JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x4063 DUP11 PUSH2 0x4031 PUSH1 0x0 PUSH2 0x1B57 JUMP JUMPDEST SWAP1 MSTORE PUSH2 0x29DC JUMP JUMPDEST PUSH2 0x40A1 DUP9 PUSH1 0x40 DUP1 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 PUSH2 0x4087 DUP11 PUSH2 0x4031 PUSH1 0x0 PUSH2 0x138B JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x409A DUP11 PUSH2 0x4031 PUSH1 0x0 PUSH2 0xED2 JUMP JUMPDEST SWAP1 MSTORE PUSH2 0x2C6C JUMP JUMPDEST POP POP POP POP POP POP POP POP JUMP JUMPDEST DUP1 MLOAD DUP3 SWAP1 PUSH1 0x0 LT ISZERO PUSH2 0x1CD2 JUMPI DUP2 MLOAD PUSH1 0x14 EQ PUSH2 0x40C5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x40CE DUP3 PUSH2 0x4280 JUMP JUMPDEST SWAP1 POP PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP2 AND ISZERO ISZERO PUSH2 0x40E5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x40ED PUSH2 0x4287 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP3 DUP2 AND SWAP2 AND EQ ISZERO PUSH2 0x1CD2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0xA9059CBB DUP4 DUP4 PUSH1 0x40 MLOAD DUP4 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP4 PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP3 POP POP POP PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x4168 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x417C JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP RETURNDATASIZE ISZERO PUSH2 0xECD JUMPI PUSH1 0x20 PUSH1 0x0 DUP1 RETURNDATACOPY PUSH1 0x0 MLOAD ISZERO ISZERO PUSH2 0xECD JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 PUSH2 0x41A4 PUSH2 0x1D32 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND PUSH4 0x669F618B PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 PUSH1 0x2 EXP MUL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x2929 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP4 AND SWAP1 DUP3 ISZERO PUSH2 0x8FC MUL SWAP1 DUP4 SWAP1 PUSH1 0x0 DUP2 DUP2 DUP2 DUP6 DUP9 DUP9 CALL SWAP4 POP POP POP POP ISZERO ISZERO PUSH2 0x834 JUMPI DUP1 DUP3 PUSH2 0x4216 PUSH2 0x4296 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x40 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 DUP3 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0x1B45 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST PUSH1 0x0 DUP2 DUP4 DUP2 ISZERO ISZERO PUSH2 0x424F JUMPI INVALID JUMPDEST DIV SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 ISZERO ISZERO PUSH2 0x4268 JUMPI POP PUSH1 0x0 PUSH2 0x1CD2 JUMP JUMPDEST POP DUP2 DUP2 MUL DUP2 DUP4 DUP3 DUP2 ISZERO ISZERO PUSH2 0x4278 JUMPI INVALID JUMPDEST DIV EQ PUSH2 0x1CD2 JUMPI INVALID JUMPDEST PUSH1 0x14 ADD MLOAD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4291 PUSH2 0x17C0 JUMP JUMPDEST SWAP1 POP SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x21 DUP1 PUSH2 0x42A6 DUP4 CODECOPY ADD SWAP1 JUMP STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD PUSH1 0x20 DUP1 PUSH1 0x21 DUP4 CODECOPY DUP2 ADD PUSH1 0x40 MSTORE MLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB DUP2 AND SELFDESTRUCT STOP PUSH6 0x786563757469 PUSH16 0x6E4461696C794C696D69740000000000 STOP STOP STOP STOP STOP STOP STOP STOP 0xca SIGNEXTEND RETURNDATASIZE 0xab 0xef 0xdb 0xd8 0xc7 0x2c EXP SWAP13 DELEGATECALL 0xa6 0xe9 0xd1 SMOD 0xda DUP10 PUSH27 0xBF036EF3F3F3B010CDD2594159078D888F9B66F3F8BFA10909E31F 0x1e AND 0x24 0xd 0xb7 CALLVALUE 0x49 CREATE POP EXP REVERT 0xbb 0xe3 0xa7 0xd LOG4 JUMPI 0xcc 0xcb DUP14 MUL 0x2f 0x21 PUSH4 0x402334A4 SWAP7 0x2e ORIGIN PUSH26 0xC5DEF3417D3D8DAB9E27BA26E81E3F833784B7802E97E87EF284 0x2a PUSH13 0xCE7DA7FFAEAEDAA2F61A6A7870 0xb2 RETURNDATASIZE SWAP14 ADD 0xfc SWAP12 PUSH20 0x712E02016836A56B71F0D02689E69E326F4F4C1B SWAP1 JUMPI AND 0x4e 0xf5 SWAP3 PUSH8 0x1CF0D37C8040C00A PUSH16 0x646CD611241D8073675E00D1A1FF700F 0xbf SHL MSTORE8 0xfc DELEGATECALL PUSH20 0xDE56D1E6E4B714BA2DE0D2CDC19D356CB53B5984 0xf9 SHL REVERT EXTCODESIZE BALANCE INVALID 0xc PUSH8 0x8A0D190A6DB39274 0xbb CALLVALUE PUSH22 0x3F4C177B42DBE934B3ABBC0208C11A42E46589983431 PUSH2 0x6F17 LT 0xab NOT SWAP7 SWAP13 0x5e 0xd6 0x2e SWAP9 0xaa DUP1 PUSH15 0x31E94A687A31C65769CB99670064DD PUSH32 0x5A87526DA075C5FB4EAB9880811BBB11E8899DA471F0E69A3ED55090FC902152 0x27 0xfc 0x5f 0xb1 0xcb 0xd PUSH15 0x962EA7B74F0C1206883BE66049A02D 0x49 CALLDATACOPY SMOD DUP4 PUSH8 0xC00B3D71DD1A9465 0xdf SWAP7 SWAP4 PUSH4 0xC6DDEAC9 PUSH14 0x6168652C307C1E813CA11CFB3A60 0x1f SHR RETURN 0xb2 0x24 MSTORE MUL BYTE POP MSTORE 0xd8 0xb0 0x5f 0x1f 0x1f DUP11 RETURNDATACOPY SWAP3 0x2d REVERT PUSH13 0x9F781BB6BBB5369C114E949B69 0xeb 0xb4 BLOCKHASH 0xef RETURNDATASIZE 0x4d 0xd6 0xb2 DUP4 PUSH3 0x25EB1D 0xc3 LOG2 0xbe 0xb4 0xed PUSH5 0x697D3EF851 DUP3 COINBASE SWAP7 PUSH16 0x7C6F28B0D72F20F51198717D198D2D55 SMOD PUSH13 0x593D657865637574696F6E4D61 PUSH25 0x5065725478000000000000000000000000000000746F6B656E MSTORE PUSH6 0x676973747261 PUSH21 0x696F6E4D6573736167654964000000000000A16562 PUSH27 0x7A723058203F04EB68BA625D53C01D3C1380A6B082BA393BADBA22 STOP PUSH19 0xF5746C73A0B554AD0029000000000000000000 ",
"sourceMap": "514:12464:24:-;;;;;;;;;-1:-1:-1;;;514:12464:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1820:116:22;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1820:116:22;-1:-1:-1;;;;;1820:116:22;;;;;;;;;7400:321:23;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;7400:321:23;-1:-1:-1;;;;;7400:321:23;;;;;;;2896:148;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;2896:148:23;-1:-1:-1;;;;;2896:148:23;;;;;;;;;;;;;;;;;;;;;7671:712:24;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;7671:712:24;;;;;1265:123:12;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1265:123:12;-1:-1:-1;;;;;1265:123:12;;;;;4180:372:23;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;4180:372:23;-1:-1:-1;;;;;4180:372:23;;;;;;;;;;;;;;;;;;;;;;;;;3721:211:24;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;3721:211:24;-1:-1:-1;;;;;3721:211:24;;;;;;;;;;;;3341:166:23;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;3341:166:23;-1:-1:-1;;;;;3341:166:23;;;;;10604:162:24;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;10604:162:24;-1:-1:-1;;;;;10604:162:24;;;;;733:114:23;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;733:114:23;-1:-1:-1;;;;;733:114:23;;;;;5835:338;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;5835:338:23;-1:-1:-1;;;;;5835:338:23;;;;;;;1386:852:24;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1386:852:24;-1:-1:-1;;;;;1386:852:24;;;;;;;;;;;;;;;;;;;;;;369:100:15;;8:9:-1;5:2;;;30:1;27;20:12;5:2;369:100:15;;;;4834:364:23;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;4834:364:23;-1:-1:-1;;;;;4834:364:23;;;;;;;5284:157;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5284:157:23;;;;2458:170;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;2458:170:23;-1:-1:-1;;;;;2458:170:23;;;;;2431:159:22;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2431:159:22;;;;;;;;-1:-1:-1;;;;;;2431:159:22;;;;;;;;;;;;;;1924:161:19;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1924:161:19;;;;;2887:304:22;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;2887:304:22;-1:-1:-1;;;;;2887:304:22;;;;;;;;;;1585:153:12;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1585:153:12;-1:-1:-1;;;;;1585:153:12;;;;;9419:416:23;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;9419:416:23;-1:-1:-1;;;;;9419:416:23;;;;;6588:374;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;6588:374:23;-1:-1:-1;;;;;6588:374:23;;;;;;;10991:193:24;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;10991:193:24;-1:-1:-1;;;;;10991:193:24;;;;;2593:126:12;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2593:126:12;;;;;;;;-1:-1:-1;;;;;2593:126:12;;;;;;;;;;;;;;1732:92:16;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1732:92:16;;;;2576:569:27;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;2576:569:27;;;;;2155:136:22;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2155:136:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3775:148:23;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;3775:148:23;-1:-1:-1;;;;;3775:148:23;;;;;3102:278:24;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;3102:278:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;3102:278:24;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3102:278:24;;-1:-1:-1;3102:278:24;;-1:-1:-1;;;;;;;3102:278:24;1145:184:23;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1145:184:23;-1:-1:-1;;;;;1145:184:23;;;;;;;1352:134:22;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1352:134:22;-1:-1:-1;;;;;1352:134:22;;;;;;;;;;;;12143:91:24;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;12143:91:24;-1:-1:-1;;;;;12143:91:24;;;;;2902:111:12;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2902:111:12;;;;2335:114;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2335:114:12;;;;9281:1129:24;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;9281:1129:24;-1:-1:-1;;;;;9281:1129:24;;;;;;;;;;8154:309:23;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;8154:309:23;-1:-1:-1;;;;;8154:309:23;;;;;;;12554:97:24;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;12554:97:24;-1:-1:-1;;;;;12554:97:24;;;;;8800:306:23;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;8800:306:23;-1:-1:-1;;;;;8800:306:23;;;;;;;1633:190;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1633:190:23;-1:-1:-1;;;;;1633:190:23;;;;;;;1992:100:16;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1992:100:16;-1:-1:-1;;;;;1992:100:16;;;;;2062:127:12;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;2062:127:12;;;;;2050:152:23;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;2050:152:23;-1:-1:-1;;;;;2050:152:23;;;;;11982:155:24;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;11982:155:24;-1:-1:-1;;;;;11982:155:24;;;;;1820:116:22;1890:39;1903:5;1910:10;1922:6;1890:12;:39::i;:::-;1820:116;;:::o;7400:321:23:-;783:7:16;:5;:7::i;:::-;-1:-1:-1;;;;;769:21:16;:10;:21;761:30;;;;;;7502:25:23;7520:6;7502:17;:25::i;:::-;7494:34;;;;;;;;7546:14;;;:76;;;7577:1;7565:9;:13;:56;;;;;7594:27;7614:6;7594:19;:27::i;:::-;7582:9;:39;7565:56;7538:85;;;;;;;;7705:9;7633:11;:69;7693:6;7655:45;;;;;;-1:-1:-1;;;;;;;;;;;7655:45:23;;;;;;-1:-1:-1;;;;;7655:45:23;-1:-1:-1;;;;;7655:45:23;-1:-1:-1;;;7655:45:23;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;7655:45:23;;;7645:56;;;;;;;;;;;;;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;7645:56:23;;;;;;;;;;;;;7633:69;;;;;;;;;;;;-1:-1:-1;7633:69:23;:81;;;;-1:-1:-1;;;;;7400:321:23:o;2896:148::-;2951:7;2977:11;:60;3028:6;2999:36;;;;;;-1:-1:-1;;;;;2999:36:23;;;;;;-1:-1:-1;;;;;2999:36:23;-1:-1:-1;;;;;2999:36:23;-1:-1:-1;;;2999:36:23;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;2999:36:23;;;2989:47;;;;;;;;;;;;;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;2989:47:23;;;;;;;;;;;;;2977:60;;;;;;;;;;;;-1:-1:-1;2977:60:23;;;2896:148;-1:-1:-1;;;;;2896:148:23:o;7671:712:24:-;7778:13;7734:34;7757:10;7734:22;:34::i;:::-;7794:24;7807:10;7794:12;:24::i;:::-;7778:40;;7846:33;7873:5;7846:26;:33::i;:::-;7832:47;;7828:549;;;7902:11;:61;7955:5;7924:37;;;;;;-1:-1:-1;;;;;7924:37:24;;;;;;-1:-1:-1;;;;;7924:37:24;-1:-1:-1;;;;;7924:37:24;-1:-1:-1;;;7924:37:24;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;7924:37:24;;;7914:48;;;;;;;;;;;;;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;7914:48:24;;;;;;;;;;;;;7902:61;;;;;;;;;-1:-1:-1;7902:61:24;;;-1:-1:-1;7902:61:24;;;7895:68;;;8006:35;;-1:-1:-1;;;;;8006:35:24;;;;-1:-1:-1;;;;;8006:35:24;;-1:-1:-1;;;8006:35:24;;;;;;;26:21:-1;;;22:32;;6:49;;8006:35:24;;;;;;;;7996:46;;-1:-1:-1;;;;8006:35:24;;-1:-1:-1;8006:35:24;;-1:-1:-1;8006:35:24;;7996:46;;;;;8006:35;7996:46;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;7996:46:24;;;;;;;;;;;;;7984:59;;;;;;;;;-1:-1:-1;7984:59:24;;;-1:-1:-1;7984:59:24;;;7977:66;;;8086:35;;-1:-1:-1;;;;;8086:35:24;;;;-1:-1:-1;;;;;8086:35:24;;-1:-1:-1;;;8086:35:24;;;;;;;26:21:-1;;;22:32;;6:49;;8086:35:24;;;;;;;;8076:46;;-1:-1:-1;;;;8086:35:24;;-1:-1:-1;8086:35:24;;-1:-1:-1;8086:35:24;;8076:46;;;;;8086:35;8076:46;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;8076:46:24;;;;;;;;;;;;;8064:59;;;;;;;;;-1:-1:-1;8064:59:24;;;-1:-1:-1;8064:59:24;;;8057:66;;;8166:46;;-1:-1:-1;;;;;;;;;;;8166:46:24;;;;-1:-1:-1;;;;;8166:46:24;;-1:-1:-1;;;8166:46:24;;;;;;;26:21:-1;;;22:32;;6:49;;8166:46:24;;;;;;;;8156:57;;-1:-1:-1;;;;8166:46:24;;-1:-1:-1;8166:46:24;;-1:-1:-1;8166:46:24;;8156:57;;;;;8166:46;8156:57;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;8156:57:24;;;;;;;;;;;;;8144:70;;;;;;;;;-1:-1:-1;8144:70:24;;;-1:-1:-1;8144:70:24;;;8137:77;;;8257:44;;-1:-1:-1;;;;;;;;;;;8257:44:24;;;;-1:-1:-1;;;;;8257:44:24;;-1:-1:-1;;;8257:44:24;;;;;;;26:21:-1;;;22:32;;6:49;;8257:44:24;;;;;;;;8247:55;;-1:-1:-1;;;;8257:44:24;;-1:-1:-1;8257:44:24;;-1:-1:-1;8257:44:24;;8247:55;;;;;8257:44;8247:55;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;8247:55:24;;;;;;;;;;;;;8235:68;;;;;;;;;;;;-1:-1:-1;8235:68:24;;;8228:75;;;8317:49;;-1:-1:-1;8348:5:24;;-1:-1:-1;;;8317:30:24;:49::i;1265:123:12:-;783:7:16;:5;:7::i;:::-;-1:-1:-1;;;;;769:21:16;:10;:21;761:30;;;;;;1346:35:12;1365:15;1346:18;:35::i;:::-;1265:123;:::o;4180:372:23:-;4255:4;4271:17;4291:54;4337:7;4291:41;4308:6;4316:15;:13;:15::i;:::-;4291:16;:41::i;:::-;:45;:54;:45;:54;:::i;:::-;4271:74;;4399:1;4374:22;4393:1;4374:10;:22::i;:::-;:26;:77;;;;;4442:9;4420:18;4431:6;4420:10;:18::i;:::-;:31;;4374:77;:124;;;;;4482:16;4491:6;4482:8;:16::i;:::-;4471:7;:27;;4374:124;:171;;;;;4529:16;4538:6;4529:8;:16::i;:::-;4518:7;:27;;4374:171;4355:190;4180:372;-1:-1:-1;;;;4180:372:23:o;3721:211:24:-;990:16:12;:14;:16::i;:::-;-1:-1:-1;;;;;968:39:12;:10;:39;960:48;;;;;;1045:29;:27;:29::i;:::-;-1:-1:-1;;;;;1026:48:12;:15;:13;:15::i;:::-;-1:-1:-1;;;;;1026:48:12;;1018:57;;;;;;3841:25:24;3859:6;3841:17;:25::i;:::-;3833:34;;;;;;;;3877:48;3898:6;3906:10;3918:6;3877:20;:48::i;:::-;3721:211;;;:::o;3341:166:23:-;3405:7;3431:11;:69;3491:6;3453:45;;;;;;-1:-1:-1;;;;;;;;;;;3453:45:23;;;;;;-1:-1:-1;;;;;3453:45:23;-1:-1:-1;;;;;3453:45:23;-1:-1:-1;;;3453:45:23;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;3453:45:23;;;3443:56;;;;;;;;;;;;;66:2:-1;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;10604:162:24;10666:7;10692:11;:67;10750:6;10714:43;;;;;;-1:-1:-1;;;;;10714:43:24;;;;;;-1:-1:-1;;;;;10714:43:24;-1:-1:-1;;;;;10714:43:24;-1:-1:-1;;;10714:43:24;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;10714:43:24;;;10704:54;;;;;;;;;;;;;66:2:-1;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;733:114:23;797:4;839:1;820:16;829:6;820:8;:16::i;:::-;:20;;733:114;-1:-1:-1;;733:114:23:o;5835:338::-;783:7:16;:5;:7::i;:::-;-1:-1:-1;;;;;769:21:16;:10;:21;761:30;;;;;;5932:25:23;5950:6;5932:17;:25::i;:::-;5924:34;;;;;;;;5990:16;5999:6;5990:8;:16::i;:::-;5976:11;:30;:50;;;-1:-1:-1;6010:16:23;;5976:50;5968:59;;;;;;;;6102:11;6037;:62;6090:6;6059:38;;;;;;-1:-1:-1;;;;;6059:38:23;;;;;;-1:-1:-1;;;;;6059:38:23;-1:-1:-1;;;;;6059:38:23;-1:-1:-1;;;6059:38:23;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;6059:38:23;;;6049:49;;;;;;;;;;;;;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;6049:49:23;;;;;;;;;;;;;6037:62;;;;;;;;;-1:-1:-1;6037:62:23;;;-1:-1:-1;6037:62:23;:76;;;;-1:-1:-1;6128:38:23;;;;;;;-1:-1:-1;;;;;6128:38:23;;;-1:-1:-1;;;;;;;;;;;;6128:38:23;;;;;;;;;;5835:338;;:::o;1386:852:24:-;1091:44:16;;;22:32:-1;6:49;;1091:44:16;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;;;179:29;160:49;;1072:64:16;;;;1800:4:24;;1080::16;;1091:44;1072:64;;;25:18:-1;1072:64:16;;25:18:-1;1800:4:24;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;1072:64:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1071:65;:208;;;;1252:4;-1:-1:-1;;;;;1224:53:16;;:55;;;;;-1:-1:-1;;;1224:55:16;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1224:55:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1224:55:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1224:55:16;-1:-1:-1;;;;;1210:69:16;:10;:69;1071:208;:299;;;-1:-1:-1;1343:10:16;1365:4;1343:27;1071:299;1050:382;;;;;;;;1825:15:24;:13;:15::i;:::-;1824:16;1816:25;;;;;;1852:35;1871:15;1852:18;:35::i;:::-;1897:50;1929:17;1897:31;:50::i;:::-;1957:56;1976:1;1980:32;1957:56;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1957:10:24;;-1:-1:-1;;;;1957:56:24:i;:::-;2023:75;;;;;;;;;;2051:1;;2023:75;2055:42;;2023:75;;;;2055:42;;2023:75;2055:42;2023:75;;-1:-1:-1;2023:19:24;;-1:-1:-1;;;;2023:75:24:i;:::-;2108:37;2128:16;2108:19;:37::i;:::-;2155:17;2165:6;2155:9;:17::i;:::-;2183:15;:13;:15::i;:::-;2216;:13;:15::i;:::-;2209:22;1386:852;-1:-1:-1;;;;;;;1386:852:24:o;369:100:15:-;-1:-1:-1;;;;;;;;;;;415:4:15;438:24;:11;:24;;-1:-1:-1;;;;;;;;;;;438:24:15;;;369:100;:::o;4834:364:23:-;4918:4;4934:17;4954:57;5003:7;4954:44;4974:6;4982:15;:13;:15::i;:::-;4954:19;:44::i;:57::-;4934:77;;5074:1;5040:31;5068:1;5040:19;:31::i;:::-;:35;:95;;;;;5126:9;5095:27;5115:6;5095:19;:27::i;:::-;:40;;5040:95;:151;;;;;5166:25;5184:6;5166:17;:25::i;:::-;5155:36;;;;;4834:364;-1:-1:-1;;;4834:364:23:o;5284:157::-;5428:6;5410:15;:24;;5284:157::o;2458:170::-;2524:7;2550:11;:71;2612:6;2572:47;;;;;;-1:-1:-1;;;;;;;;;;;2572:47:23;;;;;;-1:-1:-1;;;;;2572:47:23;-1:-1:-1;;;;;2572:47:23;-1:-1:-1;;;2572:47:23;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;2572:47:23;;;2562:58;;;;;;;;;;;;;66:2:-1;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;2431:159:22;-1:-1:-1;;;;;2431:159:22;:::o;1924:161:19:-;1987:4;2010:11;:68;2065:10;2032:44;;;;;;-1:-1:-1;;;;;2032:44:19;;;;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;2032:44:19;;;2022:55;;;;;;;;;;;;;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;2022:55:19;;;;;;;;;;;;;2010:68;;;;;;;;;;;;-1:-1:-1;2010:68:19;;;;;1924:161;-1:-1:-1;;;;;1924:161:19:o;2887:304:22:-;312:4:20;-1:-1:-1;;;;;284:53:20;;:55;;;;;-1:-1:-1;;;284:55:20;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;284:55:20;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;284:55:20;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;284:55:20;-1:-1:-1;;;;;270:69:20;:10;:69;262:78;;;;;;-1:-1:-1;;;;;3099:20:22;;;;:50;;;3124:25;3142:6;3124:17;:25::i;:::-;3123:26;3099:50;3091:59;;;;;;;;3160:24;3172:6;3180:3;3160:11;:24::i;1585:153:12:-;783:7:16;:5;:7::i;:::-;-1:-1:-1;;;;;769:21:16;:10;:21;761:30;;;;;;1681:50:12;1713:17;1681:31;:50::i;9419:416:23:-;9483:7;9502:17;9548:19;9598:14;9666:28;9522:16;9531:6;9522:8;:16::i;:::-;9502:36;;9570:18;9581:6;9570:10;:18::i;:::-;9548:40;;9615:41;9632:6;9640:15;:13;:15::i;9615:41::-;9598:58;;9711:6;9697:11;:20;:47;;9743:1;9697:47;;;9734:6;9720:11;:20;9697:47;9666:78;;9773:20;9761:9;:32;:67;;9808:20;9761:67;;;9796:9;9761:67;9754:74;9419:416;-1:-1:-1;;;;;;9419:416:23:o;6588:374::-;783:7:16;:5;:7::i;:::-;-1:-1:-1;;;;;769:21:16;:10;:21;761:30;;;;;;6694:25:23;6712:6;6694:17;:25::i;:::-;6686:34;;;;;;;;6752:25;6770:6;6752:17;:25::i;:::-;6738:11;:39;:59;;;-1:-1:-1;6781:16:23;;6738:59;6730:68;;;;;;;;6882:11;6808;:71;6870:6;6830:47;;;;;;-1:-1:-1;;;;;;;;;;;6830:47:23;;;;;;-1:-1:-1;;;;;6830:47:23;-1:-1:-1;;;;;6830:47:23;-1:-1:-1;;;6830:47:23;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;6830:47:23;;;6820:58;;;;;;;;;;;;;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;6820:58:23;;;;;;;;;;;;;6808:71;;;;;;;;;-1:-1:-1;6808:71:23;;;-1:-1:-1;6808:71:23;:85;;;;-1:-1:-1;6908:47:23;;;;;;;-1:-1:-1;;;;;6908:47:23;;;-1:-1:-1;;;;;;;;;;;;6908:47:23;;;;;;;;;;6588:374;;:::o;10991:193:24:-;11064:7;11098:11;:78;11167:6;11120:54;;;;;;-1:-1:-1;;;;;;;;;;;11120:54:24;;;;;;-1:-1:-1;;;;;11120:54:24;-1:-1:-1;;;;;11120:54:24;-1:-1:-1;;;11120:54:24;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;11120:54:24;;;11110:65;;;;;;;;;;;;;66:2:-1;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;2593:126:12;-1:-1:-1;;;;;;;;;;;2653:7:12;2679:33;:14;:33;;-1:-1:-1;;;;;;;;;;;2679:33:12;-1:-1:-1;;;;;2679:33:12;2593:126;:::o;1732:92:16:-;-1:-1:-1;;;;;;;;;;;1770:7:16;1796:21;:14;:21;;-1:-1:-1;;;;;;;;;;;1796:21:16;-1:-1:-1;;;;;1796:21:16;1732:92;:::o;2576:569:27:-;2901:21;2965:17;2657:16;:14;:16::i;:::-;-1:-1:-1;;;;;2657:34:27;;2692:10;2657:46;;;;;-1:-1:-1;;;2657:46:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2657:46:27;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;2657:46:27;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;2657:46:27;2656:47;2648:56;;;;;;2784:4;2722:16;:14;:16::i;:::-;-1:-1:-1;;;;;2722:38:27;;2761:10;2722:50;;;;;-1:-1:-1;;;2722:50:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2722:50:27;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;2722:50:27;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;2722:50:27;-1:-1:-1;;;;;2722:67:27;;2714:76;;;;;;2860:29;:27;:29::i;:::-;-1:-1:-1;;;;;2808:81:27;:16;:14;:16::i;:::-;-1:-1:-1;;;;;2808:36:27;;2845:10;2808:48;;;;;-1:-1:-1;;;2808:48:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2808:48:27;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;2808:48:27;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;2808:48:27;-1:-1:-1;;;;;2808:81:27;;2800:90;;;;;;-1:-1:-1;;2985:50:27;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;2985:50:27;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;;;179:29;;;160:49;;;2925:30:27;3045:16;:14;:16::i;:::-;-1:-1:-1;;;;;3045:37:27;;3083:29;:27;:29::i;:::-;3114:4;3120:17;:15;:17::i;:::-;3045:93;;;;;-1:-1:-1;;;3045:93:27;;;;;;;-1:-1:-1;;;;;3045:93:27;-1:-1:-1;;;;;3045:93:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;3045:93:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3045:93:27;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;3045:93:27;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;2576:569:27:o;2155:136:22:-;2276:1;2279;2216:12;2155:136;;;:::o;3775:148:23:-;3830:7;3856:11;:60;3907:6;3878:36;;;;;;-1:-1:-1;;;;;3878:36:23;;;;;;-1:-1:-1;;;;;3878:36:23;-1:-1:-1;;;;;3878:36:23;-1:-1:-1;;;3878:36:23;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;3878:36:23;;;3868:47;;;;;;;;;;;;;66:2:-1;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;3102:278:24;3187:4;3230:12;3208:6;:4;:6::i;:::-;3207:7;3203:150;;;-1:-1:-1;3252:10:24;3277:65;3252:10;3321:5;3328:6;3336:5;3277:36;:65::i;:::-;-1:-1:-1;3369:4:24;;3102:278;-1:-1:-1;;;;3102:278:24:o;1145:184:23:-;1222:7;1248:11;:74;1307:6;1315:4;1270:50;;;;;;-1:-1:-1;;;;;1270:50:23;;;;;;-1:-1:-1;;;;;1270:50:23;-1:-1:-1;;;;;1270:50:23;-1:-1:-1;;;1270:50:23;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;1270:50:23;;;1260:61;;;;;;;;;;;;;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;1260:61:23;;;;;;;;;;;;;1248:74;;;;;;;;;;;;-1:-1:-1;1248:74:23;;;-1:-1:-1;;;;1145:184:23;;;;;:::o;1352:134:22:-;1441:38;1454:5;1461:9;1472:6;1441:12;:38::i;12143:91:24:-;783:7:16;:5;:7::i;:::-;-1:-1:-1;;;;;769:21:16;:10;:21;761:30;;;;;;12208:19:24;12220:6;12208:11;:19::i;2902:111:12:-;-1:-1:-1;;;;;;;;;;;2950:7:12;2976:30;;;;;-1:-1:-1;;;;;;;;;;;2976:30:12;2902:111;:::o;2335:114::-;-1:-1:-1;;;;;;;;;;;2382:4:12;2410:31;:14;:31;;-1:-1:-1;;;;;;;;;;;2410:31:12;-1:-1:-1;;;;;2410:31:12;2335:114;:::o;9281:1129:24:-;9485:15;9552:23;9655:12;9705:17;9989;10102:18;312:4:20;-1:-1:-1;;;;;284:53:20;;:55;;;;;-1:-1:-1;;;284:55:20;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;284:55:20;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;284:55:20;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;284:55:20;-1:-1:-1;;;;;270:69:20;:10;:69;262:78;;;;;;9416:9:24;-1:-1:-1;;;;;455:17:14;;;;447:26;;;;;;9449:25:24;9467:6;9449:17;:25::i;:::-;9441:34;;;;;;;;9503:39;;;-1:-1:-1;;;;;9503:39:24;;9536:4;9503:39;;;;;;-1:-1:-1;;;;;9503:24:24;;;;;:39;;;;;;;;;;;;;;-1:-1:-1;9503:24:24;:39;;;5:2:-1;;;;30:1;27;20:12;5:2;9503:39:24;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;9503:39:24;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;9503:39:24;;-1:-1:-1;9578:23:24;9594:6;9578:15;:23::i;:::-;9552:49;-1:-1:-1;9619:25:24;;;9611:34;;;;;;9680:15;9670:7;:25;9655:40;;9725:25;9743:6;9725:17;:25::i;:::-;9705:45;-1:-1:-1;9780:1:24;9768:13;;9760:22;;;;;;9803:9;9796:4;:16;9792:63;;;9835:9;9828:16;;9792:63;9864:50;9884:6;9892:15;:13;:15::i;:::-;9909:4;9864:19;:50::i;:::-;9924:54;9944:6;9952:25;:15;9972:4;9952:25;:19;:25;:::i;:::-;9924:19;:54::i;:::-;10009:82;;;-1:-1:-1;;;;;10009:82:24;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;10009:82:24;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;;;179:29;160:49;;10009:82:24;-1:-1:-1;10123:16:24;:14;:16::i;:::-;-1:-1:-1;;;;;10123:37:24;;10174:29;:27;:29::i;:::-;10217:4;10235:17;:15;:17::i;:::-;10123:139;;;;;-1:-1:-1;;;10123:139:24;;;;;;;-1:-1:-1;;;;;10123:139:24;-1:-1:-1;;;;;10123:139:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;10123:139:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;10123:139:24;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;10123:139:24;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;10123:139:24;;-1:-1:-1;10273:35:24;10123:139;10301:6;10273:15;:35::i;:::-;10318:33;10334:10;10346:4;10318:15;:33::i;:::-;10361:42;10381:10;10393:9;10361:19;:42::i;:::-;383:1:20;9281:1129:24;;;;;;;;:::o;8154:309:23:-;783:7:16;:5;:7::i;:::-;-1:-1:-1;;;;;769:21:16;:10;:21;761:30;;;;;;8247:25:23;8265:6;8247:17;:25::i;:::-;8239:34;;;;;;;;8291:14;;;:82;;;8322:16;8331:6;8322:8;:16::i;:::-;8310:9;:28;:62;;;;;8354:18;8365:6;8354:10;:18::i;:::-;8342:9;:30;8310:62;8283:91;;;;;;;;8447:9;8384:11;:60;8435:6;8406:36;;;;;;-1:-1:-1;;;;;8406:36:23;;;;;;-1:-1:-1;;;;;8406:36:23;-1:-1:-1;;;;;8406:36:23;-1:-1:-1;;;8406:36:23;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;8406:36:23;;;8396:47;;;;;;;;;;;;;66:2:-1;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;12554:97:24;783:7:16;:5;:7::i;:::-;-1:-1:-1;;;;;769:21:16;:10;:21;761:30;;;;;;12622:22:24;12637:6;12622:14;:22::i;8800:306:23:-;783:7:16;:5;:7::i;:::-;-1:-1:-1;;;;;769:21:16;:10;:21;761:30;;;;;;8893:25:23;8911:6;8893:17;:25::i;:::-;8885:34;;;;;;;;8949:1;8937:9;:13;:47;;;;;8966:18;8977:6;8966:10;:18::i;:::-;8954:9;:30;8937:47;:79;;;;;9000:16;9009:6;9000:8;:16::i;:::-;8988:9;:28;8937:79;8929:88;;;;;;;;9090:9;9027:11;:60;9078:6;9049:36;;;;;;-1:-1:-1;;;;;9049:36:23;;;;;;-1:-1:-1;;;;;9049:36:23;-1:-1:-1;;;;;9049:36:23;-1:-1:-1;;;9049:36:23;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;9049:36:23;;;9039:47;;;;;;;;;;;;;66:2:-1;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;1633:190:23;1713:7;1739:11;:77;1801:6;1809:4;1761:53;;;;;;-1:-1:-1;;;;;1761:53:23;;;;;;-1:-1:-1;;;;;1761:53:23;-1:-1:-1;;;;;1761:53:23;-1:-1:-1;;;1761:53:23;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;1761:53:23;;;1751:64;;;;;;;;;;;;;66:2:-1;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;1992:100:16;783:7;:5;:7::i;:::-;-1:-1:-1;;;;;769:21:16;:10;:21;761:30;;;;;;2066:19;2076:8;2066:9;:19::i;2062:127:12:-;783:7:16;:5;:7::i;:::-;-1:-1:-1;;;;;769:21:16;:10;:21;761:30;;;;;;2145:37:12;2165:16;2145:19;:37::i;2050:152:23:-;2107:7;2133:11;:62;2186:6;2155:38;;;;;;-1:-1:-1;;;;;2155:38:23;;;;;;-1:-1:-1;;;;;2155:38:23;-1:-1:-1;;;;;2155:38:23;-1:-1:-1;;;2155:38:23;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;2155:38:23;;;2145:49;;;;;;;;;;;;;66:2:-1;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;11982:155:24;12043:4;12066:11;:64;12121:6;12088:40;;;;;;-1:-1:-1;;;;;12088:40:24;;;;;;-1:-1:-1;;;;;12088:40:24;-1:-1:-1;;;;;12088:40:24;-1:-1:-1;;;12088:40:24;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;12088:40:24;;;12078:51;;;;;;;;;;;;;66:2:-1;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;4463:767:24;4830:21;5004:19;4812:6;:4;:6::i;:::-;4811:7;4803:16;;;;;;4854:30;;;-1:-1:-1;;;;;4854:30:24;;4878:4;4854:30;;;;;;-1:-1:-1;;;;;4854:15:24;;;;;:30;;;;;;;;;;;;;;-1:-1:-1;4854:15:24;:30;;;5:2:-1;;;;30:1;27;20:12;5:2;4854:30:24;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;4854:30:24;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;4854:30:24;;-1:-1:-1;4894:13:24;4902:4;4894:7;:13::i;:::-;4917:53;;;-1:-1:-1;;;;;4917:53:24;;4936:10;4917:53;;;;4956:4;4917:53;;;;;;;;;;;;-1:-1:-1;;;;;4917:18:24;;;;;:53;;;;;;;;;;;;;;-1:-1:-1;4917:18:24;:53;;;5:2:-1;;;;30:1;27;20:12;5:2;4917:53:24;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;4917:53:24;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;4980:14:24;;-1:-1:-1;4988:5:24;4980:7;:14::i;:::-;5026:30;;;-1:-1:-1;;;;;5026:30:24;;5050:4;5026:30;;;;;;:49;;5061:13;;-1:-1:-1;;;;;5026:15:24;;;;;:30;;;;;;;;;;;;;;-1:-1:-1;5026:15:24;:30;;;5:2:-1;;;;30:1;27;20:12;5:2;5026:30:24;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;5026:30:24;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5026:30:24;;:49;:34;:49;:::i;:::-;5004:71;-1:-1:-1;5093:21:24;;;;5085:30;;;;;;5126:97;5163:5;5170:10;5182:11;5212:9;5195:27;;;;;;-1:-1:-1;;;;;5195:27:24;-1:-1:-1;;;;;5195:27:24;-1:-1:-1;;;5195:27:24;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;5195:27:24;;;5126:36;:97::i;3473:444:27:-;3594:13;3644:17;3702:13;990:16:12;:14;:16::i;:::-;-1:-1:-1;;;;;968:39:12;:10;:39;960:48;;;;;;1045:29;:27;:29::i;:::-;-1:-1:-1;;;;;1026:48:12;:15;:13;:15::i;:::-;-1:-1:-1;;;;;1026:48:12;;1018:57;;;;;;3558:24:27;3571:10;3558:12;:24::i;:::-;3557:25;3549:34;;;;;;3610:24;3623:10;3610:12;:24::i;:::-;3594:40;;3664:28;3681:10;3664:16;:28::i;:::-;3644:48;;3718:24;3731:10;3718:12;:24::i;:::-;3702:40;;3752:27;3768:10;3752:15;:27::i;:::-;3789:51;3816:5;3823:9;3834:5;3789:26;:51::i;:::-;3855:55;;;-1:-1:-1;;;;;3855:55:27;;;;;;;;;;;;;;;;;;;3874:10;;3855:55;;;;;;;;;;3473:444;;;;:::o;1398:169::-;1463:7;1489:14;:71;1547:10;1514:44;;;;;;-1:-1:-1;;;;;1514:44:27;;;;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;1514:44:27;;;1504:55;;;;;;;;;;;;;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;1504:55:27;;;;;;;;;;;;;1489:71;;;;;;;;;;;;-1:-1:-1;1489:71:27;;-1:-1:-1;;;;;1489:71:27;;1398:169;-1:-1:-1;;;;;1398:169:27:o;11774:202:24:-;11891:54;;;-1:-1:-1;;;;;;;;;;;11891:54:24;;;;;;;;-1:-1:-1;;;;;;;;11891:54:24;;;;;;;;;22:32:-1;26:21;;;22:32;6:49;;11891:54:24;;;;;;;;11881:65;;11958:10;;11869:11;;;;11891:54;;;;11881:65;;;;11891:54;11881:65;66:2:-1;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;3154:187:12;3234:40;3258:15;3234:23;:40::i;:::-;3226:49;;;;;;;;-1:-1:-1;;;;;;;;;;;3285:31:12;;:14;:31;;-1:-1:-1;;;;;;;;;;;3285:49:12;;-1:-1:-1;;;;;;3285:49:12;-1:-1:-1;;;;;3285:49:12;;;;;;;;;;3154:187::o;1238:128:31:-;1319:7;;;1339;;;;1332:15;;;4237:113:12;4285:7;4311:16;:14;:16::i;:::-;-1:-1:-1;;;;;4311:30:12;;:32;;;;;-1:-1:-1;;;4311:32:12;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4311:32:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;4311:32:12;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;4311:32:12;;-1:-1:-1;4237:113:12;:::o;1912:395:27:-;2016:36;2037:6;2045;2016:20;:36::i;:::-;2012:289;;;2068:55;2091:6;2099:15;:13;:15::i;:::-;2116:6;2068:22;:55::i;:::-;2137:56;2166:6;2174:10;2186:6;2137:28;:56::i;:::-;2012:289;;;2224:66;2263:6;2271:10;2283:6;2224:38;:66::i;3503:147:12:-;-1:-1:-1;;;;;;;;;;;3590:33:12;;:14;:33;;-1:-1:-1;;;;;;;;;;;3590:53:12;;-1:-1:-1;;;;;;3590:53:12;-1:-1:-1;;;;;3590:53:12;;;;;;;;;;3503:147::o;11053:582:23:-;11149:10;;;;11162:1;-1:-1:-1;11149:73:23;;;;-1:-1:-1;11212:10:23;;;;;11199;;;:23;11149:73;:139;;;;-1:-1:-1;11278:10:23;;;;11265;;:23;11149:139;11128:195;;;;;;;;11399:10;;11356:38;;;-1:-1:-1;;;;;11399:10:23;11356:38;;;;;;;-1:-1:-1;;;;;;;;11356:38:23;;;;;;;;;22:32:-1;26:21;;;22:32;6:49;;11356:38:23;;;;;;;;11346:49;;11407:1;;;;11356:38;;;;;11346:49;;;;11356:38;11346:49;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;11346:49:23;;;;;;;;;;;;;11334:62;;;;;;;;;-1:-1:-1;11334:62:23;;;-1:-1:-1;11334:62:23;;;:75;;;;-1:-1:-1;;11482:10:23;;;;11441:36;;-1:-1:-1;;;;;11441:36:23;;;;-1:-1:-1;;;;;11441:36:23;;-1:-1:-1;;;11441:36:23;;;;;;;26:21:-1;;;22:32;;6:49;;11441:36:23;;;;;;;;11431:47;;11482:10;;-1:-1:-1;;;11441:36:23;;;;11431:47;;;;11441:36;11431:47;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;11431:47:23;;;;;;;;;;;;;11419:60;;;;;;;;;-1:-1:-1;11419:60:23;;;-1:-1:-1;11419:60:23;;;:73;;;;-1:-1:-1;;11565:10:23;;;;11524:36;;-1:-1:-1;;;;;11524:36:23;;;;-1:-1:-1;;;;;11524:36:23;;-1:-1:-1;;;11524:36:23;;;;;;;26:21:-1;;;22:32;;6:49;;11524:36:23;;;;;;;;11514:47;;11565:10;;-1:-1:-1;;;11524:36:23;;;;11514:47;;;;11524:36;11514:47;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;11514:47:23;;;;;;;;;;;;;11502:60;;;;;;;;;;;;-1:-1:-1;11502:60:23;;;:73;;;;-1:-1:-1;;;;;;;;11591:37:23;;;-1:-1:-1;;;;;;;;;;;11591:37:23;11617:7;;:10;;;;;11591:37;;;;;;;;;;;;;;;;;;11053:582;;:::o;11859:411::-;11964:10;;;11951;;;:23;11943:32;;;;;;12099:10;;12047:47;;;-1:-1:-1;;;;;;;;;;;12099:10:23;12047:47;;;;;;;-1:-1:-1;;;;;;;;12047:47:23;;;;;;;;;22:32:-1;26:21;;;22:32;6:49;;12047:47:23;;;;;;;;12037:58;;12107:1;;;;12047:47;;;;;12037:58;;;;12047:47;12037:58;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;12037:58:23;;;;;;;;;;;;;12025:71;;;;;;;;;-1:-1:-1;12025:71:23;;;-1:-1:-1;12025:71:23;;;:84;;;;-1:-1:-1;;12191:10:23;;;;12141:45;;-1:-1:-1;;;;;;;;;;;12141:45:23;;;;-1:-1:-1;;;;;12141:45:23;;-1:-1:-1;;;12141:45:23;;;;;;;26:21:-1;;;22:32;;6:49;;12141:45:23;;;;;;;;12131:56;;12191:10;;-1:-1:-1;;;12141:45:23;;;;12131:56;;;;12141:45;12131:56;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;12131:56:23;;;;;;;;;;;;;12119:69;;;;;;;;;;;;-1:-1:-1;12119:69:23;;;:82;;;;-1:-1:-1;;;;;;;;12217:46:23;;;-1:-1:-1;;;;;;;;;;;12217:46:23;12252:7;;:10;;3850:182:12;3952:13;:11;:13::i;:::-;3932:33;;;3924:42;;;;;;-1:-1:-1;;;;;;;;;;;3976:11:12;:30;;;;;-1:-1:-1;;;;;;;;;;;3976:49:12;3850:182::o;2149:190:16:-;-1:-1:-1;;;;;2213:22:16;;;;2205:31;;;;;;2251:39;2272:7;:5;:7::i;:::-;2251:39;;;-1:-1:-1;;;;;2251:39:16;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;2300:21:16;;:14;:21;;-1:-1:-1;;;;;;;;;;;2300:32:16;;-1:-1:-1;;;;;;2300:32:16;-1:-1:-1;;;;;2300:32:16;;;;;;;;;;2149:190::o;281:82:15:-;-1:-1:-1;;;;;;;;;;;325:24:15;;:11;:24;;-1:-1:-1;;;;;;;;;;;325:31:15;;-1:-1:-1;;325:31:15;352:4;325:31;;;281:82::o;892:225:14:-;964:3;-1:-1:-1;;;;;455:17:14;;;;447:26;;;;;;-1:-1:-1;;;;;983:20:14;;;979:132;;;1019:21;1036:3;1019:16;:21::i;979:132::-;1071:29;1088:6;1096:3;1071:16;:29::i;267:81:17:-;-1:-1:-1;;;;;;;;;;;301:4:17;324:17;:11;:17;;-1:-1:-1;;;;;;;;;;;324:17:17;;;267:81;:::o;5515:1828:24:-;5710:17;5798:18;5861:20;5928:14;6249:17;6276:16;6859:18;5643:6;:4;:6::i;:::-;5639:19;;;5651:7;;5639:19;5676:22;5691:6;5676:14;:22::i;:::-;5668:31;;;;;;;;5730:25;5748:6;5730:17;:25::i;:::-;5710:45;;5770:12;5769:13;5765:365;;;5819:28;5840:6;5819:20;:28::i;:::-;5798:49;;5884:30;5907:6;5884:22;:30::i;:::-;5861:53;;5951:32;5976:6;5951:24;:32::i;:::-;5928:56;;6028:1;6013:4;6007:18;:22;:50;;;;6056:1;6039:6;6033:20;:24;6007:50;5999:59;;;;;;;;6073:46;6102:6;6110:8;6073:46;;:28;:46::i;:::-;6148:27;6160:6;6168;6148:11;:27::i;:::-;6140:36;;;;;;;;6186:52;6206:6;6214:15;:13;:15::i;:::-;6231:6;6186:19;:52::i;:::-;6295:28;6310:5;6317;6295:14;:28::i;:::-;6276:47;;6338:12;6334:440;;;6373:83;;;-1:-1:-1;;;;;6373:83:24;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;6373:83:24;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;;;179:29;160:49;;6373:83:24;-1:-1:-1;6334:440:24;;;6560:4;-1:-1:-1;;;;;6534:60:24;;:69;;-1:-1:-1;;;6534:69:24;6621:6;6645:4;6667:6;6691:8;6717;6743:6;6494:269;;;;;;-1:-1:-1;;;;;6494:269:24;-1:-1:-1;;;;;6494:269:24;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;6494:269:24;-1:-1:-1;;;;;6494:269:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;6494:269:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6494:269:24;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;6494:269:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6494:269:24;;;-1:-1:-1;;26:21;;;22:32;6:49;;6494:269:24;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;;;;6494:269:24;;;179:29:-1;;;;160:49;;;-1:-1;6494:269:24;;-1:-1:-1;;;;;;;;;6334:440:24;6784:64;6804:6;6812:35;6840:6;6812:23;6828:6;6812:15;:23::i;6784:64::-;6880:16;:14;:16::i;:::-;-1:-1:-1;;;;;6880:37:24;;6931:29;:27;:29::i;:::-;6974:4;6992:17;:15;:17::i;:::-;6880:139;;;;;-1:-1:-1;;;6880:139:24;;;;;;;-1:-1:-1;;;;;6880:139:24;-1:-1:-1;;;;;6880:139:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;6880:139:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;6880:139:24;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;6880:139:24;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;6880:139:24;;-1:-1:-1;7030:35:24;6880:139;7058:6;7030:15;:35::i;:::-;7075;7091:10;7103:6;7075:15;:35::i;:::-;7120:38;7140:10;7152:5;7120:19;:38::i;:::-;7174:12;7173:13;7169:94;;;7202:50;7233:6;7241:10;7202:30;:50::i;:::-;7278:58;;;;;;;;7325:10;;-1:-1:-1;;;;;7278:58:24;;;;;;;;;;;;;;;;;;5515:1828;;;;;;;;;;;;:::o;12287:261::-;12352:22;12367:6;12352:14;:22::i;:::-;12351:23;12343:32;;;;;;12393:31;12417:6;12393:23;:31::i;:::-;12385:40;;;;;;;;12502:4;12435:11;:64;12490:6;12457:40;;;;;;-1:-1:-1;;;;;12457:40:24;;;;;;-1:-1:-1;;;;;12457:40:24;-1:-1:-1;;;;;12457:40:24;-1:-1:-1;;;12457:40:24;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;12457:40:24;;;12447:51;;;;;;;;;;;;;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;12447:51:24;;;;;;;;;;;;;12435:64;;;;;;;;;;;-1:-1:-1;12435:64:24;;;:71;;-1:-1:-1;;12435:71:24;;;;;;;;;;;-1:-1:-1;;12521:20:24;-1:-1:-1;;;;;12521:20:24;;;;;-1:-1:-1;;12521:20:24;12287:261;:::o;10078:242:23:-;10249:64;10297:6;10249:30;10266:6;10274:4;10249:16;:30::i;:64::-;10172:11;:74;10231:6;10239:4;10194:50;;;;;;-1:-1:-1;;;;;10194:50:23;;;;;;-1:-1:-1;;;;;10194:50:23;-1:-1:-1;;;;;10194:50:23;-1:-1:-1;;;10194:50:23;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;10194:50:23;;;10184:61;;;;;;;;;;;;;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;10184:61:23;;;;;;;;;;;;;10172:74;;;;;;;;;;;;-1:-1:-1;10172:74:23;:141;;;;-1:-1:-1;;;;;;10078:242:23:o;11372:167:24:-;11524:8;11454:11;:67;11512:6;11476:43;;;;;;-1:-1:-1;;;;;11476:43:24;;;;;;-1:-1:-1;;;;;11476:43:24;-1:-1:-1;;;;;11476:43:24;-1:-1:-1;;;11476:43:24;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;11476:43:24;;;11466:54;;;;;;;;;;;;;66:2:-1;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;1087:167:27;1241:6;1167:14;:71;1225:10;1192:44;;;;;;-1:-1:-1;;;;;1192:44:27;;;;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;1192:44:27;;;1182:55;;;;;;;;;;;;;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;1182:55:27;;;;;;;;;;;;;1167:71;;;;;;;;;;;;-1:-1:-1;1167:71:27;:80;;-1:-1:-1;;;;;;1167:80:27;-1:-1:-1;;;;;1167:80:27;;;;;;;;;;;-1:-1:-1;;;;;1087:167:27:o;311:164:19:-;462:6;391:11;:68;446:10;413:44;;;;;;-1:-1:-1;;;;;413:44:19;;;;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;413:44:19;;;403:55;;;;;;;;;;;;;66:2:-1;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;992:183:19;1158:10;1080:14;:75;1142:10;1105:48;;;;;;-1:-1:-1;;;;;1105:48:19;;;;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;1105:48:19;;;1095:59;;;;;;;;;;;;;66:2:-1;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;12708:267:24;12775:22;12790:6;12775:14;:22::i;:::-;12767:31;;;;;;;;12816;12840:6;12816:23;:31::i;:::-;12808:40;;;;;;;;12925:5;12858:11;:64;12913:6;12880:40;;;;;;-1:-1:-1;;;;;12880:40:24;;;;;;-1:-1:-1;;;;;12880:40:24;-1:-1:-1;;;;;12880:40:24;-1:-1:-1;;;12880:40:24;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;12880:40:24;;;12870:51;;;;;;;;;;;;;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;12870:51:24;;;;;;;;;;;;;12858:64;;;;;;;;;;;-1:-1:-1;12858:64:24;;;:72;;-1:-1:-1;;12858:72:24;;;;;;;;;;;-1:-1:-1;;12945:23:24;-1:-1:-1;;;;;12945:23:24;;;;;-1:-1:-1;;12945:23:24;12708:267;:::o;354:80:17:-;-1:-1:-1;;;;;;;;;;;402:17:17;;:11;:17;;-1:-1:-1;;;;;;;;;;;402:25:17;;-1:-1:-1;;402:25:17;;;;;;;;;;354:80::o;1060:116:31:-;1120:7;1142:8;;;;1135:16;;;;-1:-1:-1;1164:7:31;;;1060:116::o;1302:177:19:-;1371:7;1397:14;:75;1459:10;1422:48;;;;;;-1:-1:-1;;;;;1422:48:19;;;;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;1422:48:19;;;1412:59;;;;;;;;;;;;;66:2:-1;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;622:166:19;687:7;713:11;:68;768:10;735:44;;;;;;-1:-1:-1;;;;;735:44:19;;;;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;735:44:19;;;725:55;;;;;;;;;;;;;66:2:-1;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;1631:146:19;1766:4;1695:11;:68;1750:10;1717:44;;;;;;-1:-1:-1;;;;;1717:44:19;;;;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;1717:44:19;;;1707:55;;;;;;;;;;;;;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;1707:55:19;;;;;;;;;;;;;1695:68;;;;;;;;;;;;-1:-1:-1;1695:68:19;:75;;-1:-1:-1;;1695:75:19;;;;;;;;;;;-1:-1:-1;;;;1631:146:19:o;8671:227:24:-;8778:64;8798:6;8806:35;8834:6;8806:23;8822:6;8806:15;:23::i;:::-;:27;:35;:27;:35;:::i;8778:64::-;8852:39;-1:-1:-1;;;;;8852:19:24;;8872:10;8884:6;8852:39;:19;:39;:::i;438:578:30:-;496:4;971:18;;1003:8;;438:578::o;10567:276:23:-;10744:92;10829:6;10744:67;10777:6;10797:4;10744:19;:67::i;:92::-;10664:11;:77;10726:6;10734:4;10686:53;;;;;;-1:-1:-1;;;;;10686:53:23;;;;;;-1:-1:-1;;;;;10686:53:23;-1:-1:-1;;;;;10686:53:23;-1:-1:-1;;;10686:53:23;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;10686:53:23;;;10676:64;;;;;;;;;;;;;66:2:-1;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;2502:339:24;2611:18;2632:11;:9;:11::i;:::-;2611:32;-1:-1:-1;2653:39:24;-1:-1:-1;;;;;2653:19:24;;2673:10;2685:6;2653:39;:19;:39;:::i;:::-;2702:64;2722:6;2730:35;2758:6;2730:23;2746:6;2730:15;:23::i;2702:64::-;2781:53;;;;;;;;2823:10;;-1:-1:-1;;;;;2781:53:24;;;;;;;;;;;;;;;;;;2502:339;;;;:::o;4800:109:12:-;4846:7;4872:16;:14;:16::i;:::-;-1:-1:-1;;;;;4872:28:12;;:30;;;;;-1:-1:-1;;;4872:30:12;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;1270:145:14;1352:4;1344:21;1375:33;1397:3;1344:21;1375;:33::i;1656:210::-;1795:21;;;-1:-1:-1;;;;;1795:21:14;;1811:4;1795:21;;;;;;1760:6;;1730:16;;-1:-1:-1;;;;;1795:15:14;;;;;:21;;;;;;;;;;;;;;1730:16;1795:15;:21;;;5:2:-1;;;;30:1;27;20:12;5:2;1795:21:14;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1795:21:14;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1795:21:14;;-1:-1:-1;1826:33:14;-1:-1:-1;;;;;1826:19:14;;1846:3;1795:21;1826:33;:19;:33;:::i;:::-;1656:210;;;;:::o;488:1682:8:-;642:4;636:11;-1:-1:-1;;;;;660:79:8;;545:6;;563:11;545:6;809:2;636:11;801:1;636:11;788:6;783:3;772:40;765:48;762:2;;;-1:-1:-1;;;;;839:3:8;832:79;975:2;970:3;967:1;962:3;954:6;949:3;938:40;995:3;762:2;1048:14;1043:3;1039:24;1033:4;1026:38;1104:2;1088:14;1085:22;1129:1;1124:146;;;;1325:14;1317:22;;1078:290;;1124:146;1185:2;1181;1174:4;1168:11;1153:35;1246:4;1240:11;1234:18;1226:26;;1078:290;;1418:4;1407:16;;;;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;1407:16:8;;1387:36;;1478:2;1462:14;1459:22;1456:2;;;1567:4;1563:2;1558;1553:3;1549:12;1534:38;1594:4;1589:10;1456:2;1682:1;1666:14;1663:21;1660:2;;;1712:1;1743:3;1737:10;1730:17;;1807:3;1802:2;1797:3;1793:12;1786:25;1860:149;1876:1;1871:3;1868:10;1860:149;;;1956:1;1952:11;;;;;1893:1;1886:9;1860:149;;;2026:14;;2160:3;488:1682;-1:-1:-1;;;;488:1682:8:o;2496:1688::-;2652:4;2646:11;-1:-1:-1;;;;;2670:79:8;;2555:6;;2573:11;2555:6;2821:2;2646:11;2813:1;2646:11;2800:6;2795:3;2784:40;2777:48;2774:2;;;-1:-1:-1;;;;;2851:3:8;2844:79;2989:2;2984:3;2981:1;2976:3;2968:6;2963:3;2952:40;3009:3;3062:14;3057:3;3053:24;3047:4;3040:38;3118:2;3102:14;3099:22;3143:1;3138:146;;;;3339:14;3331:22;;3092:290;;4440:685;4501:7;4520:16;4586:4;4580:11;4626:2;4621:3;4617:12;4611:4;4604:26;-1:-1:-1;;;;;4650:3:8;4643:79;4796:2;4791:3;4788:1;4783:3;4775:6;4770:3;4759:40;4752:48;4749:2;;;-1:-1:-1;;;;;4826:3:8;4819:79;4976:2;4971:3;4968:1;4963:3;4955:6;4950:3;4939:40;4932:48;4929:2;;;5015:1;5010:3;5003:14;4929:2;5074:10;;4440:685;-1:-1:-1;;;4440:685:8:o;12495:2151:23:-;12587:14;12689:17;12755;12821:19;12891:26;12975:28;12627:2;12615:9;:14;12611:2029;;;12664:9;12659:2;:14;12654:2;:20;12645:29;;12709:32;12734:6;12709:20;12726:1;12709:8;:20::i;:::-;:24;:32;:24;:32;:::i;:::-;12689:52;;12775:32;12800:6;12775:20;12792:1;12775:8;:20::i;:32::-;12755:52;;12843:34;12870:6;12843:22;12862:1;12843:10;:22::i;:34::-;12821:56;;12920:41;12954:6;12920:29;12946:1;12920:17;:29::i;:41::-;12891:70;;13006:43;13042:6;13006:31;13034:1;13006:19;:31::i;:43::-;12975:74;-1:-1:-1;13363:14:23;;13359:696;;;13673:1;;-1:-1:-1;13696:22:23;;;13692:349;;13754:3;13742:15;;13800:3;13779:24;;13844:9;13829:11;:24;;:70;;;;13881:18;13857:20;:42;;13829:70;13825:198;;;-1:-1:-1;13941:5:23;;-1:-1:-1;13941:5:23;13825:198;14068:55;14079:6;14068:55;;;;;;;;;14088:11;14068:55;;;;14101:9;14068:55;;;;14112:9;14068:55;;;:10;:55::i;:::-;14137:71;14157:6;14137:71;;;;;;;;;14166:20;14137:71;;;;14188:18;14137:71;;;:19;:71::i;:::-;12611:2029;;;14265:2;14253:9;:14;14248:2;:20;14239:29;;14282:170;14310:6;14282:170;;;;;;;;;14335:34;14362:6;14335:22;14354:1;14335:10;:22::i;:::-;:26;:34;:26;:34;:::i;:::-;14282:170;;;;14371:32;14396:6;14371:20;14388:1;14371:8;:20::i;:32::-;14282:170;;;;14405:32;14430:6;14405:20;14422:1;14405:8;:20::i;:32::-;14282:170;;:10;:170::i;:::-;14466:163;14503:6;14466:163;;;;;;;;;14528:43;14564:6;14528:31;14556:1;14528:19;:31::i;:43::-;14466:163;;;;14573:41;14607:6;14573:29;14599:1;14573:17;:29::i;:41::-;14466:163;;:19;:163::i;:::-;12495:2151;;;;;;;;:::o;388:373:13:-;523:12;;504:5;;463:17;-1:-1:-1;519:236:13;;;563:12;;579:2;563:18;555:27;;;;;;608;629:5;608:20;:27::i;:::-;596:39;-1:-1:-1;;;;;;657:23:13;;;;649:32;;;;;;716:27;:25;:27::i;:::-;-1:-1:-1;;;;;703:40:13;;;;;;;695:49;;;;;579:339:7;677:6;-1:-1:-1;;;;;665:28:7;;694:3;699:6;665:41;;;;;-1:-1:-1;;;665:41:7;;;;;;;-1:-1:-1;;;;;665:41:7;-1:-1:-1;;;;;665:41:7;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;665:41:7;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;665:41:7;;;;742:14;739:2;;;796;793:1;790;775:24;832:1;826:8;819:16;816:2;;;868:1;865;858:12;4512:105:12;4556:7;4582:16;:14;:16::i;:::-;-1:-1:-1;;;;;4582:26:12;;:28;;;;;-1:-1:-1;;;4582:28:12;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;431:177:5;513:22;;-1:-1:-1;;;;;513:14:5;;;:22;;;;;528:6;;513:22;;;;528:6;513:14;:22;;;;;;;512:23;508:94;;;573:6;581:9;551:40;;:::i;:::-;-1:-1:-1;;;;;551:40:5;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;665:283:31;725:7;941:2;936;:7;;;;;;;;;665:283;-1:-1:-1;;;665:283:31:o;203:380::-;263:9;489:7;;485:36;;;-1:-1:-1;513:1:31;506:8;;485:36;-1:-1:-1;531:7:31;;;536:2;531;:7;551:6;;;;;;;;:12;544:20;;;1216:154:6;1350:2;1338:15;1332:22;;1310:54::o;839:122:22:-;899:7;925:29;:27;:29::i;:::-;918:36;;839:122;:::o;514:12464:24:-;;;;;;;;;;:::o"
},
"gasEstimates": {
"creation": {
"codeDepositCost": "3536400",
"executionCost": "3966",
"totalCost": "3540366"
},
"external": {
"allowToken(address)": "infinite",
"bridgeContract()": "infinite",
"claimTokens(address,address)": "infinite",
"dailyLimit(address)": "2181",
"disallowToken(address)": "infinite",
"executionDailyLimit(address)": "infinite",
"executionMaxPerTx(address)": "infinite",
"fixFailedMessage(bytes32)": "infinite",
"fixMediatorBalance(address,address)": "infinite",
"getBridgeInterfacesVersion()": "888",
"getBridgeMode()": "751",
"getCurrentDay()": "562",
"handleBridgedTokens(address,address,uint256)": "infinite",
"initialize(address,address,uint256[3],uint256[2],uint256,address)": "infinite",
"isInitialized()": "infinite",
"isTokenAllowed(address)": "2300",
"isTokenRegistered(address)": "1529",
"maxAvailablePerTx(address)": "infinite",
"maxPerTx(address)": "1324",
"mediatorBalance(address)": "1549",
"mediatorContractOnOtherSide()": "infinite",
"messageFixed(bytes32)": "infinite",
"minPerTx(address)": "1873",
"onTokenTransfer(address,uint256,bytes)": "infinite",
"owner()": "infinite",
"relayTokens(address,address,uint256)": "infinite",
"relayTokens(address,uint256)": "infinite",
"requestFailedMessageFix(bytes32)": "infinite",
"requestGasLimit()": "infinite",
"setBridgeContract(address)": "22100",
"setDailyLimit(address,uint256)": "infinite",
"setExecutionDailyLimit(address,uint256)": "infinite",
"setExecutionMaxPerTx(address,uint256)": "infinite",
"setMaxPerTx(address,uint256)": "infinite",
"setMediatorContractOnOtherSide(address)": "21671",
"setMinPerTx(address,uint256)": "infinite",
"setRequestGasLimit(uint256)": "infinite",
"tokenRegistrationMessageId(address)": "infinite",
"totalExecutedPerDay(address,uint256)": "infinite",
"totalSpentPerDay(address,uint256)": "infinite",
"transferOwnership(address)": "infinite",
"withinExecutionLimit(address,uint256)": "infinite",
"withinLimit(address,uint256)": "infinite"
},
"internal": {
"_allowToken(address)": "infinite",
"_disallowToken(address)": "infinite",
"_relayTokens(contract ERC677,address,uint256)": "infinite",
"_setMediatorBalance(address,uint256)": "infinite",
"_setTokenRegistrationMessageId(address,bytes32)": "infinite",
"bridgeSpecificActionsOnTokenTransfer(contract ERC677,address,uint256,bytes memory)": "infinite",
"executeActionOnBridgedTokens(address,address,uint256)": "infinite",
"executeActionOnFixedTokens(address,address,uint256)": "infinite"
}
},
"methodIdentifiers": {
"allowToken(address)": "b53472ef",
"bridgeContract()": "cd596583",
"claimTokens(address,address)": "69ffa08a",
"dailyLimit(address)": "f3f51415",
"disallowToken(address)": "e79767af",
"executionDailyLimit(address)": "40f8dd86",
"executionMaxPerTx(address)": "16ef1913",
"fixFailedMessage(bytes32)": "0950d515",
"fixMediatorBalance(address,address)": "d0342acd",
"getBridgeInterfacesVersion()": "9cb7595a",
"getBridgeMode()": "437764df",
"getCurrentDay()": "3e6968b6",
"handleBridgedTokens(address,address,uint256)": "125e4cfb",
"initialize(address,address,uint256[3],uint256[2],uint256,address)": "351a8264",
"isInitialized()": "392e53cd",
"isTokenAllowed(address)": "f9eaee0d",
"isTokenRegistered(address)": "26aa101f",
"maxAvailablePerTx(address)": "7610722f",
"maxPerTx(address)": "032f693f",
"mediatorBalance(address)": "194153d3",
"mediatorContractOnOtherSide()": "871c0760",
"messageFixed(bytes32)": "59339982",
"minPerTx(address)": "a4b1c243",
"onTokenTransfer(address,uint256,bytes)": "a4c0ed36",
"owner()": "8da5cb5b",
"relayTokens(address,address,uint256)": "ad58bdd1",
"relayTokens(address,uint256)": "01e4f53a",
"requestFailedMessageFix(bytes32)": "9a4a4395",
"requestGasLimit()": "be3b625b",
"setBridgeContract(address)": "0b26cf66",
"setDailyLimit(address,uint256)": "2803212f",
"setExecutionDailyLimit(address,uint256)": "7837cf91",
"setExecutionMaxPerTx(address,uint256)": "01fcc1d3",
"setMaxPerTx(address,uint256)": "db6fff8c",
"setMediatorContractOnOtherSide(address)": "6e5d6bea",
"setMinPerTx(address,uint256)": "ec47de2a",
"setRequestGasLimit(uint256)": "f3b83791",
"tokenRegistrationMessageId(address)": "8190d906",
"totalExecutedPerDay(address,uint256)": "f2c54fe8",
"totalSpentPerDay(address,uint256)": "ab3a25d9",
"transferOwnership(address)": "f2fde38b",
"withinExecutionLimit(address,uint256)": "3a50bc87",
"withinLimit(address,uint256)": "10775238"
}
},
"abi": [
{
"constant": false,
"inputs": [
{
"name": "token",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "relayTokens",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_maxPerTx",
"type": "uint256"
}
],
"name": "setExecutionMaxPerTx",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "maxPerTx",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_messageId",
"type": "bytes32"
}
],
"name": "fixFailedMessage",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_bridgeContract",
"type": "address"
}
],
"name": "setBridgeContract",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_amount",
"type": "uint256"
}
],
"name": "withinLimit",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_recipient",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "handleBridgedTokens",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "executionMaxPerTx",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "mediatorBalance",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "isTokenRegistered",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_dailyLimit",
"type": "uint256"
}
],
"name": "setDailyLimit",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_bridgeContract",
"type": "address"
},
{
"name": "_mediatorContract",
"type": "address"
},
{
"name": "_dailyLimitMaxPerTxMinPerTxArray",
"type": "uint256[3]"
},
{
"name": "_executionDailyLimitExecutionMaxPerTxArray",
"type": "uint256[2]"
},
{
"name": "_requestGasLimit",
"type": "uint256"
},
{
"name": "_owner",
"type": "address"
}
],
"name": "initialize",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "isInitialized",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_amount",
"type": "uint256"
}
],
"name": "withinExecutionLimit",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getCurrentDay",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "executionDailyLimit",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getBridgeMode",
"outputs": [
{
"name": "_data",
"type": "bytes4"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_messageId",
"type": "bytes32"
}
],
"name": "messageFixed",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_to",
"type": "address"
}
],
"name": "claimTokens",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_mediatorContract",
"type": "address"
}
],
"name": "setMediatorContractOnOtherSide",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "maxAvailablePerTx",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_dailyLimit",
"type": "uint256"
}
],
"name": "setExecutionDailyLimit",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "tokenRegistrationMessageId",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "mediatorContractOnOtherSide",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "owner",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_messageId",
"type": "bytes32"
}
],
"name": "requestFailedMessageFix",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getBridgeInterfacesVersion",
"outputs": [
{
"name": "major",
"type": "uint64"
},
{
"name": "minor",
"type": "uint64"
},
{
"name": "patch",
"type": "uint64"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "minPerTx",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
},
{
"name": "_data",
"type": "bytes"
}
],
"name": "onTokenTransfer",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_day",
"type": "uint256"
}
],
"name": "totalSpentPerDay",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "token",
"type": "address"
},
{
"name": "_receiver",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "relayTokens",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "allowToken",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "requestGasLimit",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "bridgeContract",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_receiver",
"type": "address"
}
],
"name": "fixMediatorBalance",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_maxPerTx",
"type": "uint256"
}
],
"name": "setMaxPerTx",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "disallowToken",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_minPerTx",
"type": "uint256"
}
],
"name": "setMinPerTx",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_day",
"type": "uint256"
}
],
"name": "totalExecutedPerDay",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_requestGasLimit",
"type": "uint256"
}
],
"name": "setRequestGasLimit",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "dailyLimit",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "isTokenAllowed",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "token",
"type": "address"
}
],
"name": "TokenAllowed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "token",
"type": "address"
}
],
"name": "TokenDisallowed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "messageId",
"type": "bytes32"
},
{
"indexed": false,
"name": "token",
"type": "address"
},
{
"indexed": false,
"name": "recipient",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256"
}
],
"name": "FailedMessageFixed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "token",
"type": "address"
},
{
"indexed": true,
"name": "sender",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256"
},
{
"indexed": true,
"name": "messageId",
"type": "bytes32"
}
],
"name": "TokensBridgingInitiated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "token",
"type": "address"
},
{
"indexed": true,
"name": "recipient",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256"
},
{
"indexed": true,
"name": "messageId",
"type": "bytes32"
}
],
"name": "TokensBridged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "token",
"type": "address"
},
{
"indexed": false,
"name": "newLimit",
"type": "uint256"
}
],
"name": "DailyLimitChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "token",
"type": "address"
},
{
"indexed": false,
"name": "newLimit",
"type": "uint256"
}
],
"name": "ExecutionDailyLimitChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "previousOwner",
"type": "address"
},
{
"indexed": false,
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
}
]
}
{
"compiler": {
"version": "0.4.24+commit.e67f0147"
},
"language": "Solidity",
"output": {
"abi": [
{
"constant": false,
"inputs": [
{
"name": "token",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "relayTokens",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_maxPerTx",
"type": "uint256"
}
],
"name": "setExecutionMaxPerTx",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "maxPerTx",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_messageId",
"type": "bytes32"
}
],
"name": "fixFailedMessage",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_bridgeContract",
"type": "address"
}
],
"name": "setBridgeContract",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_amount",
"type": "uint256"
}
],
"name": "withinLimit",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_recipient",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "handleBridgedTokens",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "executionMaxPerTx",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "mediatorBalance",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "isTokenRegistered",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_dailyLimit",
"type": "uint256"
}
],
"name": "setDailyLimit",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_bridgeContract",
"type": "address"
},
{
"name": "_mediatorContract",
"type": "address"
},
{
"name": "_dailyLimitMaxPerTxMinPerTxArray",
"type": "uint256[3]"
},
{
"name": "_executionDailyLimitExecutionMaxPerTxArray",
"type": "uint256[2]"
},
{
"name": "_requestGasLimit",
"type": "uint256"
},
{
"name": "_owner",
"type": "address"
}
],
"name": "initialize",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "isInitialized",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_amount",
"type": "uint256"
}
],
"name": "withinExecutionLimit",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getCurrentDay",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "executionDailyLimit",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getBridgeMode",
"outputs": [
{
"name": "_data",
"type": "bytes4"
}
],
"payable": false,
"stateMutability": "pure",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_messageId",
"type": "bytes32"
}
],
"name": "messageFixed",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_to",
"type": "address"
}
],
"name": "claimTokens",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_mediatorContract",
"type": "address"
}
],
"name": "setMediatorContractOnOtherSide",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "maxAvailablePerTx",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_dailyLimit",
"type": "uint256"
}
],
"name": "setExecutionDailyLimit",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "tokenRegistrationMessageId",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "mediatorContractOnOtherSide",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "owner",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_messageId",
"type": "bytes32"
}
],
"name": "requestFailedMessageFix",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getBridgeInterfacesVersion",
"outputs": [
{
"name": "major",
"type": "uint64"
},
{
"name": "minor",
"type": "uint64"
},
{
"name": "patch",
"type": "uint64"
}
],
"payable": false,
"stateMutability": "pure",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "minPerTx",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
},
{
"name": "_data",
"type": "bytes"
}
],
"name": "onTokenTransfer",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_day",
"type": "uint256"
}
],
"name": "totalSpentPerDay",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "token",
"type": "address"
},
{
"name": "_receiver",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "relayTokens",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "allowToken",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "requestGasLimit",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "bridgeContract",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_receiver",
"type": "address"
}
],
"name": "fixMediatorBalance",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_maxPerTx",
"type": "uint256"
}
],
"name": "setMaxPerTx",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "disallowToken",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_minPerTx",
"type": "uint256"
}
],
"name": "setMinPerTx",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_day",
"type": "uint256"
}
],
"name": "totalExecutedPerDay",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_requestGasLimit",
"type": "uint256"
}
],
"name": "setRequestGasLimit",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "dailyLimit",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "isTokenAllowed",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "token",
"type": "address"
}
],
"name": "TokenAllowed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "token",
"type": "address"
}
],
"name": "TokenDisallowed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "messageId",
"type": "bytes32"
},
{
"indexed": false,
"name": "token",
"type": "address"
},
{
"indexed": false,
"name": "recipient",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256"
}
],
"name": "FailedMessageFixed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "token",
"type": "address"
},
{
"indexed": true,
"name": "sender",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256"
},
{
"indexed": true,
"name": "messageId",
"type": "bytes32"
}
],
"name": "TokensBridgingInitiated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "token",
"type": "address"
},
{
"indexed": true,
"name": "recipient",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256"
},
{
"indexed": true,
"name": "messageId",
"type": "bytes32"
}
],
"name": "TokensBridged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "token",
"type": "address"
},
{
"indexed": false,
"name": "newLimit",
"type": "uint256"
}
],
"name": "DailyLimitChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "token",
"type": "address"
},
{
"indexed": false,
"name": "newLimit",
"type": "uint256"
}
],
"name": "ExecutionDailyLimitChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "previousOwner",
"type": "address"
},
{
"indexed": false,
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
}
],
"devdoc": {
"methods": {
"bridgeContract()": {
"details": "Get the AMB interface for the bridge contract address",
"return": "AMB interface for the bridge contract address"
},
"claimTokens(address,address)": {
"details": "Claims stucked tokens. Only unsupported tokens can be claimed. When dealing with already supported tokens, fixMediatorBalance can be used instead.",
"params": {
"_to": "address of tokens receiver",
"_token": "address of claimed token, address(0) for native"
}
},
"dailyLimit(address)": {
"details": "Retrieves current daily limit for a particular token contract.",
"params": {
"_token": "address of the token contract."
},
"return": "daily limit on tokens that can be sent through the bridge per day."
},
"executionDailyLimit(address)": {
"details": "Retrieves current execution daily limit for a particular token contract.",
"params": {
"_token": "address of the token contract."
},
"return": "daily limit on tokens that can be received from the bridge on the other side per day."
},
"executionMaxPerTx(address)": {
"details": "Retrieves current maximum execution amount of tokens per one transfer for a particular token contract.",
"params": {
"_token": "address of the token contract."
},
"return": "maximum amount on tokens that can received from the bridge on the other side in one transaction."
},
"fixFailedMessage(bytes32)": {
"details": "Handles the request to fix transferred assets which bridged message execution failed on the other network. It uses the information stored by passMessage method when the assets were initially transferred",
"params": {
"_messageId": "id of the message which execution failed on the other network."
}
},
"fixMediatorBalance(address,address)": {
"details": "Allows to send to the other network the amount of locked tokens that can be forced into the contract without the invocation of the required methods. (e. g. regular transfer without a call to onTokenTransfer)",
"params": {
"_receiver": "the address that will receive the tokens on the other network.",
"_token": "address of the token contract."
}
},
"getBridgeInterfacesVersion()": {
"details": "Tells the bridge interface version that this contract supports.",
"return": "major value of the versionminor value of the versionpatch value of the version"
},
"getBridgeMode()": {
"details": "Tells the bridge mode that this contract supports.",
"return": "_data 4 bytes representing the bridge mode"
},
"getCurrentDay()": {
"details": "Returns current day number.",
"return": "day number."
},
"handleBridgedTokens(address,address,uint256)": {
"details": "Handles the bridged tokens. Checks that the value is inside the execution limits and invokes the method to execute the Mint or Unlock accordingly.",
"params": {
"_recipient": "address that will receive the tokens.",
"_token": "bridged ERC20 token.",
"_value": "amount of tokens to be received."
}
},
"initialize(address,address,uint256[3],uint256[2],uint256,address)": {
"details": "Stores the initial parameters of the mediator.",
"params": {
"_bridgeContract": "the address of the AMB bridge contract.",
"_dailyLimitMaxPerTxMinPerTxArray": "array with limit values for the assets to be bridged to the other network. [ 0 = dailyLimit, 1 = maxPerTx, 2 = minPerTx ]",
"_executionDailyLimitExecutionMaxPerTxArray": "array with limit values for the assets bridged from the other network. [ 0 = executionDailyLimit, 1 = executionMaxPerTx ]",
"_mediatorContract": "the address of the mediator contract on the other network.",
"_owner": "address of the owner of the mediator contract.",
"_requestGasLimit": "the gas limit for the message execution."
}
},
"isTokenRegistered(address)": {
"details": "Checks if specified token was already bridged at least once.",
"params": {
"_token": "address of the token contract."
},
"return": "true, if token address is address(0) or token was already bridged."
},
"maxAvailablePerTx(address)": {
"details": "Retrieves maximum available bridge amount per one transaction taking into account maxPerTx() and dailyLimit() parameters.",
"params": {
"_token": "address of the token contract, or address(0) for the default limit."
},
"return": "minimum of maxPerTx parameter and remaining daily quota."
},
"maxPerTx(address)": {
"details": "Retrieves current maximum amount of tokens per one transfer for a particular token contract.",
"params": {
"_token": "address of the token contract."
},
"return": "maximum amount on tokens that can be sent through the bridge in one transfer."
},
"mediatorBalance(address)": {
"details": "Tells the expected token balance of the contract.",
"params": {
"_token": "address of token contract."
},
"return": "the current tracked token balance of the contract."
},
"mediatorContractOnOtherSide()": {
"details": "Tells the mediator contract address from the other network.",
"return": "the address of the mediator contract."
},
"messageFixed(bytes32)": {
"details": "Tells if a message sent to the AMB bridge has been fixed.",
"return": "bool indicating the status of the message."
},
"minPerTx(address)": {
"details": "Retrieves current minimum amount of tokens per one transfer for a particular token contract.",
"params": {
"_token": "address of the token contract."
},
"return": "minimum amount on tokens that can be sent through the bridge in one transfer."
},
"onTokenTransfer(address,uint256,bytes)": {
"details": "ERC677 transfer callback function.",
"params": {
"_data": "additional transfer data, can be used for passing alternative receiver address.",
"_from": "address of tokens sender.",
"_value": "amount of transferred tokens."
}
},
"owner()": {
"details": "Tells the address of the owner",
"return": "the address of the owner"
},
"relayTokens(address,address,uint256)": {
"details": "Initiate the bridge operation for some amount of tokens from msg.sender. The user should first call Approve method of the ERC677 token.",
"params": {
"_receiver": "address that will receive the native tokens on the other network.",
"_value": "amount of tokens to be transferred to the other network.",
"token": "bridged token contract address."
}
},
"relayTokens(address,uint256)": {
"details": "Initiate the bridge operation for some amount of tokens from msg.sender to msg.sender on the other side. The user should first call Approve method of the ERC677 token.",
"params": {
"_value": "amount of tokens to be transferred to the other network.",
"token": "bridged token contract address."
}
},
"requestFailedMessageFix(bytes32)": {
"details": "Method to be called when a bridged message execution failed. It will generate a new message requesting to fix/roll back the transferred assets on the other network.",
"params": {
"_messageId": "id of the message which execution failed."
}
},
"requestGasLimit()": {
"details": "Tells the gas limit to be used in the message execution by the AMB bridge on the other network.",
"return": "the gas limit for the message execution."
},
"setBridgeContract(address)": {
"details": "Sets the AMB bridge contract address. Only the owner can call this method.",
"params": {
"_bridgeContract": "the address of the bridge contract."
}
},
"setDailyLimit(address,uint256)": {
"details": "Updates daily limit for the particular token. Only owner can call this method.",
"params": {
"_dailyLimit": "daily allowed amount of bridged tokens, should be greater than maxPerTx. 0 value is also allowed, will stop the bridge operations in outgoing direction.",
"_token": "address of the token contract, or address(0) for configuring the efault limit."
}
},
"setExecutionDailyLimit(address,uint256)": {
"details": "Updates execution daily limit for the particular token. Only owner can call this method.",
"params": {
"_dailyLimit": "daily allowed amount of executed tokens, should be greater than executionMaxPerTx. 0 value is also allowed, will stop the bridge operations in incoming direction.",
"_token": "address of the token contract, or address(0) for configuring the default limit."
}
},
"setExecutionMaxPerTx(address,uint256)": {
"details": "Updates execution maximum per transaction for the particular token. Only owner can call this method.",
"params": {
"_maxPerTx": "maximum amount of executed tokens per one transaction, should be less than executionDailyLimit. 0 value is also allowed, will stop the bridge operations in incoming direction.",
"_token": "address of the token contract, or address(0) for configuring the default limit."
}
},
"setMaxPerTx(address,uint256)": {
"details": "Updates maximum per transaction for the particular token. Only owner can call this method.",
"params": {
"_maxPerTx": "maximum amount of tokens per one transaction, should be less than dailyLimit, greater than minPerTx. 0 value is also allowed, will stop the bridge operations in outgoing direction.",
"_token": "address of the token contract, or address(0) for configuring the default limit."
}
},
"setMediatorContractOnOtherSide(address)": {
"details": "Sets the mediator contract address from the other network. Only the owner can call this method.",
"params": {
"_mediatorContract": "the address of the mediator contract."
}
},
"setMinPerTx(address,uint256)": {
"details": "Updates minumum per transaction for the particular token. Only owner can call this method.",
"params": {
"_minPerTx": "minumum amount of tokens per one transaction, should be less than maxPerTx and dailyLimit.",
"_token": "address of the token contract, or address(0) for configuring the default limit."
}
},
"setRequestGasLimit(uint256)": {
"details": "Sets the gas limit to be used in the message execution by the AMB bridge on the other network. This value can't exceed the parameter maxGasPerTx defined on the AMB bridge. Only the owner can call this method.",
"params": {
"_requestGasLimit": "the gas limit for the message execution."
}
},
"tokenRegistrationMessageId(address)": {
"details": "Returns message id where specified token was first seen and deploy on the other side was requested.",
"params": {
"_token": "address of token contract."
},
"return": "message id of the send message."
},
"totalExecutedPerDay(address,uint256)": {
"details": "Retrieves the total executed amount for particular token during specific day.",
"params": {
"_day": "day number for which spent amount if requested.",
"_token": "address of the token contract."
},
"return": "amount of tokens received from the bridge from the other side."
},
"totalSpentPerDay(address,uint256)": {
"details": "Retrieves the total spent amount for particular token during specific day.",
"params": {
"_day": "day number for which spent amount if requested.",
"_token": "address of the token contract."
},
"return": "amount of tokens sent through the bridge to the other side."
},
"transferOwnership(address)": {
"details": "Allows the current owner to transfer control of the contract to a newOwner.",
"params": {
"newOwner": "the address to transfer ownership to."
}
},
"withinExecutionLimit(address,uint256)": {
"details": "Checks that bridged amount of tokens conforms to the configured execution limits.",
"params": {
"_amount": "amount of bridge tokens.",
"_token": "address of the token contract."
},
"return": "true, if specified amount can be processed and executed."
},
"withinLimit(address,uint256)": {
"details": "Checks that bridged amount of tokens conforms to the configured limits.",
"params": {
"_amount": "amount of bridge tokens.",
"_token": "address of the token contract."
},
"return": "true, if specified amount can be bridged."
}
},
"title": "ForeignMultiAMBErc20ToErc677"
},
"userdoc": {
"methods": {}
}
},
"settings": {
"compilationTarget": {
"contracts/upgradeable_contracts/multi_amb_erc20_to_erc677/ForeignMultiAMBErc20ToErc677.sol": "ForeignMultiAMBErc20ToErc677"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 10
},
"remappings": []
},
"sources": {
"contracts/interfaces/ERC677.sol": {
"keccak256": "0xa4252d5b9e3d1b536b6a5edce1b712530827fcc792438ca17fa60fb64d4463ca",
"urls": [
"bzzr://ca1db6e12bc9753410003682a5cb6ebfc87ee238e78ba4a3033f915c66c3c72b"
]
},
"contracts/interfaces/IAMB.sol": {
"keccak256": "0xd95469da5c2b895e9f8b23a864f931f053efd9b22a1c0af1928e5802df74c73f",
"urls": [
"bzzr://ba73b8e65499bb98dba6fbbceb818784cb8122d6901960e2ef61c7a5ab254a69"
]
},
"contracts/interfaces/IBridgeUtils.sol": {
"keccak256": "0x91efda011690272d292caa948a7006def37ce5bfd99a2aae59fa213b4802e857",
"urls": [
"bzzr://1e17e20df57d2b7ee445e237202b2b7ab7b8e1f5077b0948b163580ed542af89"
]
},
"contracts/interfaces/IBurnableMintableERC677Token.sol": {
"keccak256": "0x74fd1c41330140ddd6dc29037ca04ee13a23a44c5c5b3c4ce284a99cc78484a1",
"urls": [
"bzzr://dff872387b862977ce1b000a31d08aaccb1ea3e43bf9b7403911841d1e3aabef"
]
},
"contracts/interfaces/IUpgradeabilityOwnerStorage.sol": {
"keccak256": "0xa6b5c96c8165d49676d227a9b7070faffdb7325906a598797fe66ca5917e76ef",
"urls": [
"bzzr://14c7b605baba9012f1386dce78e5b2665c682ec6a5bae3f4a6ec15f98ba40aa9"
]
},
"contracts/libraries/Address.sol": {
"keccak256": "0x9d5d8f089aedf9dfa743c9bc66bc901db5da5be78892af178340800873e1c722",
"urls": [
"bzzr://97602c15f88d529b68d7929717afa75fd03cd0f23a1363c14cd263dbcc17599e"
]
},
"contracts/libraries/Bytes.sol": {
"keccak256": "0xaac87fcac1962e29a85f577dafccf09d06b413fcc5bf97e821dca0b25183c310",
"urls": [
"bzzr://e1a3e3f8d13a8009d505b4d20029adbbcaf4c20a92ee10a223767fbb6d093dd2"
]
},
"contracts/libraries/SafeERC20.sol": {
"keccak256": "0xb1f0a33f17fee9d600a2269fecce80d79377af3aeb2922e903fe4e3b57dc0c4f",
"urls": [
"bzzr://e3b6f5e2a1e88e69d403cbf2925c92c662b4fe6ea28dee292948187203ac6c98"
]
},
"contracts/libraries/TokenReader.sol": {
"keccak256": "0x5c56cc46d91133104a2f4ded16117b3a9a8c25582dd4d379fc435f080b0f1ad4",
"urls": [
"bzzr://29f6607df1561eb8b3cdfa619d4a5199999fd3fa1a9ebe42703e854c98f4d912"
]
},
"contracts/upgradeability/EternalStorage.sol": {
"keccak256": "0x8f2df79a1cda812d4be25da8f2b138f9b7492e76da1dfba21d87012e649cc51c",
"urls": [
"bzzr://0846d08e1b7a84e541ae31c91d2c0b34d88cf3abbd18891ec6eedeea7e958af2"
]
},
"contracts/upgradeability/Proxy.sol": {
"keccak256": "0x988fcd3b873c98ca9bab506f729188d223622bc1c2955bfd052055cd5a87826f",
"urls": [
"bzzr://a834a880c6eae7a950227d28ea2c495004c71e24ac1e06fb89f1e10d23a1dbf8"
]
},
"contracts/upgradeable_contracts/BaseRewardAddressList.sol": {
"keccak256": "0x7eda3597f59b4d9a147cf597c5747e0d659f97b4d0b2026d19dcb472b6062454",
"urls": [
"bzzr://2009b146020d19f1ebfce25b854dee9e84dac1ac9991178063d8772e98b5d7b7"
]
},
"contracts/upgradeable_contracts/BasicAMBMediator.sol": {
"keccak256": "0x817cdf39d46eed56fdf6fc124b7163d1dc296b8b02fbc0fd34ee1948d8816eab",
"urls": [
"bzzr://02cf31c071d2a58a929d0fa1dae4d647ae1ce881221695a0730b66f6098cfa4a"
]
},
"contracts/upgradeable_contracts/ChooseReceiverHelper.sol": {
"keccak256": "0xed188cae33d353543654b085650def4bf4be21304b0380fa683fbe06dbc4d3ce",
"urls": [
"bzzr://6c4aa7785721d11c9c8c03400e24e0049de3359b9deb55a6d8db6443183b974c"
]
},
"contracts/upgradeable_contracts/Claimable.sol": {
"keccak256": "0xfe020277ad01d6e42674c0906fb33eeec54964e928208fdd7fc0ab68c2967773",
"urls": [
"bzzr://2d1d90cdfb9e0917f83bdfcc4f8398e3f035c4c62da4e79e81ad4c4252b1d979"
]
},
"contracts/upgradeable_contracts/Initializable.sol": {
"keccak256": "0xed94c4128ada87141d6c640d5bf4d0a5227cd68fad16be6304a121847fe6494f",
"urls": [
"bzzr://2dfbb776af73c3cfe3b6d3dd4545dc7cc55694d4636c0d1043d46ace7dd42ab2"
]
},
"contracts/upgradeable_contracts/Ownable.sol": {
"keccak256": "0xa61d31759a177fc38a5dcf34387cfc9870bbe64f946c14c380d13ddcd9aa6113",
"urls": [
"bzzr://7d8b5611ce1d97b28de5d10d5569fe2bd710e851f55b02d628b7a881ca9a9b40"
]
},
"contracts/upgradeable_contracts/ReentrancyGuard.sol": {
"keccak256": "0x8eeae0c6814a239234e23b741950407be18bf86ccca5b1e2a44f53c1c2e678eb",
"urls": [
"bzzr://c189a949f46ce94256fc611ef07a53648519f61d121b95466f4cb4a2ab397465"
]
},
"contracts/upgradeable_contracts/Sacrifice.sol": {
"keccak256": "0x2c8f9b5e39d33552cd16d3fdd84e58f2138042166ae9b351e97fe674f7e3f337",
"urls": [
"bzzr://a438edd320ea1fa8141d54002897c3a50cf6cb13b07b4088d01ffb099bb9e859"
]
},
"contracts/upgradeable_contracts/TransferInfoStorage.sol": {
"keccak256": "0xf284bf49c93b62b92ba14c5eb87c1f94b4893bf7c65499f254dd6a03363071f2",
"urls": [
"bzzr://6cdf94e9fd04016ed2a8d3ada76e413c0aefa1d2346259a4a4c60f5eff3dde1b"
]
},
"contracts/upgradeable_contracts/Upgradeable.sol": {
"keccak256": "0xbfbec6c479103b324cc0c2ab115b3d9d3226abdfa0ab19fccbfdf223a38a6511",
"urls": [
"bzzr://fcde383760b302df8f3a6bf5bb8371d1138c2c7bf6d15e1abf972180c181af8b"
]
},
"contracts/upgradeable_contracts/VersionableBridge.sol": {
"keccak256": "0x20e13a4da2277be92631581b29607b525a6d8a1868d5f0bf43d970408e9b2bc0",
"urls": [
"bzzr://a8c1f803d409d79319f4907066a1e38a811f758142243bef553ae9ad2516814d"
]
},
"contracts/upgradeable_contracts/multi_amb_erc20_to_erc677/BasicMultiAMBErc20ToErc677.sol": {
"keccak256": "0x76229095ac9129a1eb0dddb9f66ffd89e3942cbc273a79579a828f0dffc638bd",
"urls": [
"bzzr://340d77cce79a618cea30224cf1d08a6dcc7e69ebbe54bf0bae384a87eb8e9063"
]
},
"contracts/upgradeable_contracts/multi_amb_erc20_to_erc677/BasicMultiTokenBridge.sol": {
"keccak256": "0x5a4be2e128752ce4bd44abafa214822390dc6eff97acd0d08206f1b9137076e1",
"urls": [
"bzzr://2778b81f3dc702cd03bbd51e976f15fdf722089f6d74f9517e1d63dba126c1e1"
]
},
"contracts/upgradeable_contracts/multi_amb_erc20_to_erc677/ForeignMultiAMBErc20ToErc677.sol": {
"keccak256": "0xf1d040ead6bf1f930ca1f5b48fbb316d555f1f98bcf9b370ff62edccc26997b2",
"urls": [
"bzzr://f6f37f338b9510331d6b2a550903b00b5782806ddbf3f989ebc3d0d836a6077a"
]
},
"contracts/upgradeable_contracts/multi_amb_erc20_to_erc677/HomeFeeManagerMultiAMBErc20ToErc677.sol": {
"keccak256": "0xd5f9cb7f3a48a635f0c2ea4814eeb844e1f3063a9d3653dd9bc859c6cfbbf95b",
"urls": [
"bzzr://e59fc7ee0628044c391465f3075d3a952ce9ebf4a09a75c51239e67ba1214a37"
]
},
"contracts/upgradeable_contracts/multi_amb_erc20_to_erc677/HomeMultiAMBErc20ToErc677.sol": {
"keccak256": "0xc3f350105f7b8f72bc399f07585422c03873cb5b9eff5088419342fc6f66f252",
"urls": [
"bzzr://dc489fe0a551686e66400c0b962177a49fa2d18499c1795c638b6781fbc45a2f"
]
},
"contracts/upgradeable_contracts/multi_amb_erc20_to_erc677/MultiTokenBridgeMediator.sol": {
"keccak256": "0x07f4578829dbd1e9f3d73e1869f5a784173543467c231ade3542648a5abc6761",
"urls": [
"bzzr://40062528aa0a1a276c6adfa6620a208468250b0af2379637a1d13968edae9d37"
]
},
"contracts/upgradeable_contracts/multi_amb_erc20_to_erc677/MultiTokenForwardingRules.sol": {
"keccak256": "0x5d0d90104d8b8a9f808f1ced1d4ac5b31830b8e0e6c7ae4ff1124f482b3a54ef",
"urls": [
"bzzr://9a15a6011d1039d1acec1da44cb415991739b9eff4eded4869ae5a37e2758e74"
]
},
"contracts/upgradeable_contracts/multi_amb_erc20_to_erc677/TokenProxy.sol": {
"keccak256": "0xb4904dedea6c594d71f7c87bfad9f8067191b9c2d42e37b214895c9216dadeee",
"urls": [
"bzzr://67ef1395cb8b8cc14087f8c4b507ab0ede8dfa0027e35886274f643a8fa3869f"
]
},
"openzeppelin-solidity/contracts/AddressUtils.sol": {
"keccak256": "0x5ed3dc711dbb34917afff3c753adf3b0580514d1339cfedaa5a73645d8ac9b56",
"urls": [
"bzzr://d597eeb695a3d64766453239e973ddd65994c258ab8d5cab0d90103033ce85fc"
]
},
"openzeppelin-solidity/contracts/math/SafeMath.sol": {
"keccak256": "0xa1c5e1d9ebbf654d332ca8e7a5c04a6a6a9d142eeaab3b988c2c909c81a62bef",
"urls": [
"bzzr://d062fb4a1b6de1f036ee0e73364a2532c4757eb68e95dd8c5cbb2d17b8732c6a"
]
},
"openzeppelin-solidity/contracts/token/ERC20/DetailedERC20.sol": {
"keccak256": "0xa9927296145433fad9195e7ce0388d6f07cfeb6c1c45df07f1c800f4196dd272",
"urls": [
"bzzr://59df43cea2bdda3527bc27aa56ea1838ead92e1e6ebc8254034b619d6b97003e"
]
},
"openzeppelin-solidity/contracts/token/ERC20/ERC20.sol": {
"keccak256": "0xd5feb2643c87547e65b8d6f1af02539b1dee1ad53046945e237eaa8ba649c93b",
"urls": [
"bzzr://69768215a261b30a376a901b83b1e6716e3916c9fd791ac67450c283e62212ad"
]
},
"openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol": {
"keccak256": "0x516a17244073b518096ced7c8c94924cb29746ef0a4b6cc6cde125ac0406a419",
"urls": [
"bzzr://7addb1b5cad767651b9bcd688ba5b08769c1f3b70a470e34752a7717756d090d"
]
}
},
"version": 1
}
pragma solidity 0.4.24;
import "../../interfaces/IAMB.sol";
import "./MultiTokenBridgeMediator.sol";
import "../Ownable.sol";
import "../Initializable.sol";
import "../ReentrancyGuard.sol";
import "../Upgradeable.sol";
import "../Claimable.sol";
import "../VersionableBridge.sol";
/**
* @title BasicMultiAMBErc20ToErc677
* @dev Common functionality for multi-erc20-to-erc677 mediator intended to work on top of AMB bridge.
*/
contract BasicMultiAMBErc20ToErc677 is
Initializable,
ReentrancyGuard,
Upgradeable,
Claimable,
VersionableBridge,
MultiTokenBridgeMediator
{
/**
* @dev Tells the address of the mediator contract on the other side, used by chooseReceiver method
* to avoid sending the native tokens to that address.
* @return address of the mediator contract con the other side
*/
function bridgeContractOnOtherSide() internal view returns (address) {
return mediatorContractOnOtherSide();
}
/**
* @dev Initiate the bridge operation for some amount of tokens from msg.sender.
* The user should first call Approve method of the ERC677 token.
* @param token bridged token contract address.
* @param _receiver address that will receive the native tokens on the other network.
* @param _value amount of tokens to be transferred to the other network.
*/
function relayTokens(ERC677 token, address _receiver, uint256 _value) external {
_relayTokens(token, _receiver, _value);
}
/**
* @dev Initiate the bridge operation for some amount of tokens from msg.sender to msg.sender on the other side.
* The user should first call Approve method of the ERC677 token.
* @param token bridged token contract address.
* @param _value amount of tokens to be transferred to the other network.
*/
function relayTokens(ERC677 token, uint256 _value) external {
_relayTokens(token, msg.sender, _value);
}
/**
* @dev Tells the bridge interface version that this contract supports.
* @return major value of the version
* @return minor value of the version
* @return patch value of the version
*/
function getBridgeInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) {
return (1, 2, 0);
}
/**
* @dev Tells the bridge mode that this contract supports.
* @return _data 4 bytes representing the bridge mode
*/
function getBridgeMode() external pure returns (bytes4 _data) {
return 0xb1516c26; // bytes4(keccak256(abi.encodePacked("multi-erc-to-erc-amb")))
}
/**
* @dev Claims stucked tokens. Only unsupported tokens can be claimed.
* When dealing with already supported tokens, fixMediatorBalance can be used instead.
* @param _token address of claimed token, address(0) for native
* @param _to address of tokens receiver
*/
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
// Only unregistered tokens and native coins are allowed to be claimed with the use of this function
require(_token == address(0) || !isTokenRegistered(_token));
claimValues(_token, _to);
}
/* solcov ignore next */
function onTokenTransfer(address _from, uint256 _value, bytes _data) public returns (bool);
/* solcov ignore next */
function _relayTokens(ERC677 token, address _receiver, uint256 _value) internal;
/* solcov ignore next */
function bridgeSpecificActionsOnTokenTransfer(ERC677 _token, address _from, uint256 _value, bytes _data) internal;
}
pragma solidity 0.4.24;
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "../../upgradeability/EternalStorage.sol";
import "../Ownable.sol";
contract BasicMultiTokenBridge is EternalStorage, Ownable {
using SafeMath for uint256;
// token == 0x00..00 represents default limits (assuming decimals == 18) for all newly created tokens
event DailyLimitChanged(address indexed token, uint256 newLimit);
event ExecutionDailyLimitChanged(address indexed token, uint256 newLimit);
/**
* @dev Checks if specified token was already bridged at least once.
* @param _token address of the token contract.
* @return true, if token address is address(0) or token was already bridged.
*/
function isTokenRegistered(address _token) public view returns (bool) {
return minPerTx(_token) > 0;
}
/**
* @dev Retrieves the total spent amount for particular token during specific day.
* @param _token address of the token contract.
* @param _day day number for which spent amount if requested.
* @return amount of tokens sent through the bridge to the other side.
*/
function totalSpentPerDay(address _token, uint256 _day) public view returns (uint256) {
return uintStorage[keccak256(abi.encodePacked("totalSpentPerDay", _token, _day))];
}
/**
* @dev Retrieves the total executed amount for particular token during specific day.
* @param _token address of the token contract.
* @param _day day number for which spent amount if requested.
* @return amount of tokens received from the bridge from the other side.
*/
function totalExecutedPerDay(address _token, uint256 _day) public view returns (uint256) {
return uintStorage[keccak256(abi.encodePacked("totalExecutedPerDay", _token, _day))];
}
/**
* @dev Retrieves current daily limit for a particular token contract.
* @param _token address of the token contract.
* @return daily limit on tokens that can be sent through the bridge per day.
*/
function dailyLimit(address _token) public view returns (uint256) {
return uintStorage[keccak256(abi.encodePacked("dailyLimit", _token))];
}
/**
* @dev Retrieves current execution daily limit for a particular token contract.
* @param _token address of the token contract.
* @return daily limit on tokens that can be received from the bridge on the other side per day.
*/
function executionDailyLimit(address _token) public view returns (uint256) {
return uintStorage[keccak256(abi.encodePacked("executionDailyLimit", _token))];
}
/**
* @dev Retrieves current maximum amount of tokens per one transfer for a particular token contract.
* @param _token address of the token contract.
* @return maximum amount on tokens that can be sent through the bridge in one transfer.
*/
function maxPerTx(address _token) public view returns (uint256) {
return uintStorage[keccak256(abi.encodePacked("maxPerTx", _token))];
}
/**
* @dev Retrieves current maximum execution amount of tokens per one transfer for a particular token contract.
* @param _token address of the token contract.
* @return maximum amount on tokens that can received from the bridge on the other side in one transaction.
*/
function executionMaxPerTx(address _token) public view returns (uint256) {
return uintStorage[keccak256(abi.encodePacked("executionMaxPerTx", _token))];
}
/**
* @dev Retrieves current minimum amount of tokens per one transfer for a particular token contract.
* @param _token address of the token contract.
* @return minimum amount on tokens that can be sent through the bridge in one transfer.
*/
function minPerTx(address _token) public view returns (uint256) {
return uintStorage[keccak256(abi.encodePacked("minPerTx", _token))];
}
/**
* @dev Checks that bridged amount of tokens conforms to the configured limits.
* @param _token address of the token contract.
* @param _amount amount of bridge tokens.
* @return true, if specified amount can be bridged.
*/
function withinLimit(address _token, uint256 _amount) public view returns (bool) {
uint256 nextLimit = totalSpentPerDay(_token, getCurrentDay()).add(_amount);
return
dailyLimit(address(0)) > 0 &&
dailyLimit(_token) >= nextLimit &&
_amount <= maxPerTx(_token) &&
_amount >= minPerTx(_token);
}
/**
* @dev Checks that bridged amount of tokens conforms to the configured execution limits.
* @param _token address of the token contract.
* @param _amount amount of bridge tokens.
* @return true, if specified amount can be processed and executed.
*/
function withinExecutionLimit(address _token, uint256 _amount) public view returns (bool) {
uint256 nextLimit = totalExecutedPerDay(_token, getCurrentDay()).add(_amount);
return
executionDailyLimit(address(0)) > 0 &&
executionDailyLimit(_token) >= nextLimit &&
_amount <= executionMaxPerTx(_token);
}
/**
* @dev Returns current day number.
* @return day number.
*/
function getCurrentDay() public view returns (uint256) {
// solhint-disable-next-line not-rely-on-time
return block.timestamp / 1 days;
}
/**
* @dev Updates daily limit for the particular token. Only owner can call this method.
* @param _token address of the token contract, or address(0) for configuring the efault limit.
* @param _dailyLimit daily allowed amount of bridged tokens, should be greater than maxPerTx.
* 0 value is also allowed, will stop the bridge operations in outgoing direction.
*/
function setDailyLimit(address _token, uint256 _dailyLimit) external onlyOwner {
require(isTokenRegistered(_token));
require(_dailyLimit > maxPerTx(_token) || _dailyLimit == 0);
uintStorage[keccak256(abi.encodePacked("dailyLimit", _token))] = _dailyLimit;
emit DailyLimitChanged(_token, _dailyLimit);
}
/**
* @dev Updates execution daily limit for the particular token. Only owner can call this method.
* @param _token address of the token contract, or address(0) for configuring the default limit.
* @param _dailyLimit daily allowed amount of executed tokens, should be greater than executionMaxPerTx.
* 0 value is also allowed, will stop the bridge operations in incoming direction.
*/
function setExecutionDailyLimit(address _token, uint256 _dailyLimit) external onlyOwner {
require(isTokenRegistered(_token));
require(_dailyLimit > executionMaxPerTx(_token) || _dailyLimit == 0);
uintStorage[keccak256(abi.encodePacked("executionDailyLimit", _token))] = _dailyLimit;
emit ExecutionDailyLimitChanged(_token, _dailyLimit);
}
/**
* @dev Updates execution maximum per transaction for the particular token. Only owner can call this method.
* @param _token address of the token contract, or address(0) for configuring the default limit.
* @param _maxPerTx maximum amount of executed tokens per one transaction, should be less than executionDailyLimit.
* 0 value is also allowed, will stop the bridge operations in incoming direction.
*/
function setExecutionMaxPerTx(address _token, uint256 _maxPerTx) external onlyOwner {
require(isTokenRegistered(_token));
require(_maxPerTx == 0 || (_maxPerTx > 0 && _maxPerTx < executionDailyLimit(_token)));
uintStorage[keccak256(abi.encodePacked("executionMaxPerTx", _token))] = _maxPerTx;
}
/**
* @dev Updates maximum per transaction for the particular token. Only owner can call this method.
* @param _token address of the token contract, or address(0) for configuring the default limit.
* @param _maxPerTx maximum amount of tokens per one transaction, should be less than dailyLimit, greater than minPerTx.
* 0 value is also allowed, will stop the bridge operations in outgoing direction.
*/
function setMaxPerTx(address _token, uint256 _maxPerTx) external onlyOwner {
require(isTokenRegistered(_token));
require(_maxPerTx == 0 || (_maxPerTx > minPerTx(_token) && _maxPerTx < dailyLimit(_token)));
uintStorage[keccak256(abi.encodePacked("maxPerTx", _token))] = _maxPerTx;
}
/**
* @dev Updates minumum per transaction for the particular token. Only owner can call this method.
* @param _token address of the token contract, or address(0) for configuring the default limit.
* @param _minPerTx minumum amount of tokens per one transaction, should be less than maxPerTx and dailyLimit.
*/
function setMinPerTx(address _token, uint256 _minPerTx) external onlyOwner {
require(isTokenRegistered(_token));
require(_minPerTx > 0 && _minPerTx < dailyLimit(_token) && _minPerTx < maxPerTx(_token));
uintStorage[keccak256(abi.encodePacked("minPerTx", _token))] = _minPerTx;
}
/**
* @dev Retrieves maximum available bridge amount per one transaction taking into account maxPerTx() and dailyLimit() parameters.
* @param _token address of the token contract, or address(0) for the default limit.
* @return minimum of maxPerTx parameter and remaining daily quota.
*/
function maxAvailablePerTx(address _token) public view returns (uint256) {
uint256 _maxPerTx = maxPerTx(_token);
uint256 _dailyLimit = dailyLimit(_token);
uint256 _spent = totalSpentPerDay(_token, getCurrentDay());
uint256 _remainingOutOfDaily = _dailyLimit > _spent ? _dailyLimit - _spent : 0;
return _maxPerTx < _remainingOutOfDaily ? _maxPerTx : _remainingOutOfDaily;
}
/**
* @dev Internal function for adding spent amount for some token.
* @param _token address of the token contract.
* @param _day day number, when tokens are processed.
* @param _value amount of bridge tokens.
*/
function addTotalSpentPerDay(address _token, uint256 _day, uint256 _value) internal {
uintStorage[keccak256(abi.encodePacked("totalSpentPerDay", _token, _day))] = totalSpentPerDay(_token, _day).add(
_value
);
}
/**
* @dev Internal function for adding execcuted amount for some token.
* @param _token address of the token contract.
* @param _day day number, when tokens are processed.
* @param _value amount of bridge tokens.
*/
function addTotalExecutedPerDay(address _token, uint256 _day, uint256 _value) internal {
uintStorage[keccak256(abi.encodePacked("totalExecutedPerDay", _token, _day))] = totalExecutedPerDay(
_token,
_day
)
.add(_value);
}
/**
* @dev Internal function for initializing limits for some token.
* @param _token address of the token contract.
* @param _limits [ 0 = dailyLimit, 1 = maxPerTx, 2 = minPerTx ].
*/
function _setLimits(address _token, uint256[3] _limits) internal {
require(
_limits[2] > 0 && // minPerTx > 0
_limits[1] > _limits[2] && // maxPerTx > minPerTx
_limits[0] > _limits[1] // dailyLimit > maxPerTx
);
uintStorage[keccak256(abi.encodePacked("dailyLimit", _token))] = _limits[0];
uintStorage[keccak256(abi.encodePacked("maxPerTx", _token))] = _limits[1];
uintStorage[keccak256(abi.encodePacked("minPerTx", _token))] = _limits[2];
emit DailyLimitChanged(_token, _limits[0]);
}
/**
* @dev Internal function for initializing execution limits for some token.
* @param _token address of the token contract.
* @param _limits [ 0 = executionDailyLimit, 1 = executionMaxPerTx ].
*/
function _setExecutionLimits(address _token, uint256[2] _limits) internal {
require(_limits[1] < _limits[0]); // foreignMaxPerTx < foreignDailyLimit
uintStorage[keccak256(abi.encodePacked("executionDailyLimit", _token))] = _limits[0];
uintStorage[keccak256(abi.encodePacked("executionMaxPerTx", _token))] = _limits[1];
emit ExecutionDailyLimitChanged(_token, _limits[0]);
}
/**
* @dev Internal function for initializing limits for some token relative to its decimals parameter.
* @param _token address of the token contract.
* @param _decimals token decimals parameter.
*/
function _initializeTokenBridgeLimits(address _token, uint256 _decimals) internal {
uint256 factor;
if (_decimals < 18) {
factor = 10**(18 - _decimals);
uint256 _minPerTx = minPerTx(address(0)).div(factor);
uint256 _maxPerTx = maxPerTx(address(0)).div(factor);
uint256 _dailyLimit = dailyLimit(address(0)).div(factor);
uint256 _executionMaxPerTx = executionMaxPerTx(address(0)).div(factor);
uint256 _executionDailyLimit = executionDailyLimit(address(0)).div(factor);
// such situation can happen when calculated limits relative to the token decimals are too low
// e.g. minPerTx(address(0)) == 10 ** 14, _decimals == 3. _minPerTx happens to be 0, which is not allowed.
// in this case, limits are raised to the default values
if (_minPerTx == 0) {
// Numbers 1, 100, 10000 are chosen in a semi-random way,
// so that any token with small decimals can still be bridged in some amounts.
// It is possible to override limits for the particular token later if needed.
_minPerTx = 1;
if (_maxPerTx <= _minPerTx) {
_maxPerTx = 100;
_executionMaxPerTx = 100;
if (_dailyLimit <= _maxPerTx || _executionDailyLimit <= _executionMaxPerTx) {
_dailyLimit = 10000;
_executionDailyLimit = 10000;
}
}
}
_setLimits(_token, [_dailyLimit, _maxPerTx, _minPerTx]);
_setExecutionLimits(_token, [_executionDailyLimit, _executionMaxPerTx]);
} else {
factor = 10**(_decimals - 18);
_setLimits(
_token,
[dailyLimit(address(0)).mul(factor), maxPerTx(address(0)).mul(factor), minPerTx(address(0)).mul(factor)]
);
_setExecutionLimits(
_token,
[executionDailyLimit(address(0)).mul(factor), executionMaxPerTx(address(0)).mul(factor)]
);
}
}
}
pragma solidity 0.4.24;
import "openzeppelin-solidity/contracts/token/ERC20/DetailedERC20.sol";
import "./BasicMultiAMBErc20ToErc677.sol";
import "./HomeMultiAMBErc20ToErc677.sol";
import "../../libraries/TokenReader.sol";
import "../../libraries/SafeERC20.sol";
/**
* @title ForeignMultiAMBErc20ToErc677
* @dev Foreign side implementation for multi-erc20-to-erc677 mediator intended to work on top of AMB bridge.
* It is designed to be used as an implementation contract of EternalStorageProxy contract.
*/
contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677 {
using SafeERC20 for address;
using SafeERC20 for ERC677;
/**
* @dev Stores the initial parameters of the mediator.
* @param _bridgeContract the address of the AMB bridge contract.
* @param _mediatorContract the address of the mediator contract on the other network.
* @param _dailyLimitMaxPerTxMinPerTxArray array with limit values for the assets to be bridged to the other network.
* [ 0 = dailyLimit, 1 = maxPerTx, 2 = minPerTx ]
* @param _executionDailyLimitExecutionMaxPerTxArray array with limit values for the assets bridged from the other network.
* [ 0 = executionDailyLimit, 1 = executionMaxPerTx ]
* @param _requestGasLimit the gas limit for the message execution.
* @param _owner address of the owner of the mediator contract.
*/
function initialize(
address _bridgeContract,
address _mediatorContract,
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
uint256[2] _executionDailyLimitExecutionMaxPerTxArray, // [ 0 = _executionDailyLimit, 1 = _executionMaxPerTx ]
uint256 _requestGasLimit,
address _owner
) external onlyRelevantSender returns (bool) {
require(!isInitialized());
_setBridgeContract(_bridgeContract);
_setMediatorContractOnOtherSide(_mediatorContract);
_setLimits(address(0), _dailyLimitMaxPerTxMinPerTxArray);
_setExecutionLimits(address(0), _executionDailyLimitExecutionMaxPerTxArray);
_setRequestGasLimit(_requestGasLimit);
_setOwner(_owner);
setInitialize();
return isInitialized();
}
/**
* @dev Executes action on the request to withdraw tokens relayed from the other network
* @param _token address of the token contract
* @param _recipient address of tokens receiver
* @param _value amount of bridged tokens
*/
function executeActionOnBridgedTokens(address _token, address _recipient, uint256 _value) internal {
bytes32 _messageId = messageId();
_token.safeTransfer(_recipient, _value);
_setMediatorBalance(_token, mediatorBalance(_token).sub(_value));
emit TokensBridged(_token, _recipient, _value, _messageId);
}
/**
* @dev ERC677 transfer callback function.
* @param _from address of tokens sender.
* @param _value amount of transferred tokens.
* @param _data additional transfer data, can be used for passing alternative receiver address.
*/
function onTokenTransfer(address _from, uint256 _value, bytes _data) public returns (bool) {
if (!lock()) {
ERC677 token = ERC677(msg.sender);
bridgeSpecificActionsOnTokenTransfer(token, _from, _value, _data);
}
return true;
}
/**
* @dev Handles the bridged tokens. Checks that the value is inside the execution limits and invokes the method
* to execute the Mint or Unlock accordingly.
* @param _token bridged ERC20 token.
* @param _recipient address that will receive the tokens.
* @param _value amount of tokens to be received.
*/
function handleBridgedTokens(ERC677 _token, address _recipient, uint256 _value) external onlyMediator {
require(isTokenRegistered(_token));
_handleBridgedTokens(_token, _recipient, _value);
}
/**
* @dev Validates that the token amount is inside the limits, calls transferFrom to transfer the tokens to the contract
* and invokes the method to burn/lock the tokens and unlock/mint the tokens on the other network.
* The user should first call Approve method of the ERC677 token.
* @param token bridge token contract address.
* @param _receiver address that will receive the native tokens on the other network.
* @param _value amount of tokens to be transferred to the other network.
*/
function _relayTokens(ERC677 token, address _receiver, uint256 _value) internal {
// This lock is to prevent calling passMessage twice if a ERC677 token is used.
// When transferFrom is called, after the transfer, the ERC677 token will call onTokenTransfer from this contract
// which will call passMessage.
require(!lock());
uint256 balanceBefore = token.balanceOf(address(this));
setLock(true);
token.transferFrom(msg.sender, address(this), _value);
setLock(false);
uint256 balanceDiff = token.balanceOf(address(this)).sub(balanceBefore);
require(balanceDiff <= _value);
bridgeSpecificActionsOnTokenTransfer(token, msg.sender, balanceDiff, abi.encodePacked(_receiver));
}
/**
* @dev Executes action on deposit of bridged tokens
* @param _token address of the token contract
* @param _from address of tokens sender
* @param _value requsted amount of bridged tokens
* @param _data alternative receiver, if specified
*/
function bridgeSpecificActionsOnTokenTransfer(ERC677 _token, address _from, uint256 _value, bytes _data) internal {
if (lock()) return;
require(isTokenAllowed(_token));
bool isKnownToken = isTokenRegistered(_token);
if (!isKnownToken) {
string memory name = TokenReader.readName(_token);
string memory symbol = TokenReader.readSymbol(_token);
uint8 decimals = uint8(TokenReader.readDecimals(_token));
require(bytes(name).length > 0 || bytes(symbol).length > 0);
_initializeTokenBridgeLimits(_token, decimals);
}
require(withinLimit(_token, _value));
addTotalSpentPerDay(_token, getCurrentDay(), _value);
bytes memory data;
address receiver = chooseReceiver(_from, _data);
if (isKnownToken) {
data = abi.encodeWithSelector(this.handleBridgedTokens.selector, _token, receiver, _value);
} else {
data = abi.encodeWithSelector(
HomeMultiAMBErc20ToErc677(this).deployAndHandleBridgedTokens.selector,
_token,
name,
symbol,
decimals,
receiver,
_value
);
}
_setMediatorBalance(_token, mediatorBalance(_token).add(_value));
bytes32 _messageId = bridgeContract().requireToPassMessage(
mediatorContractOnOtherSide(),
data,
requestGasLimit()
);
setMessageToken(_messageId, _token);
setMessageValue(_messageId, _value);
setMessageRecipient(_messageId, _from);
if (!isKnownToken) {
_setTokenRegistrationMessageId(_token, _messageId);
}
emit TokensBridgingInitiated(_token, _from, _value, _messageId);
}
/**
* @dev Handles the request to fix transferred assets which bridged message execution failed on the other network.
* It uses the information stored by passMessage method when the assets were initially transferred
* @param _messageId id of the message which execution failed on the other network.
*/
function fixFailedMessage(bytes32 _messageId) public {
super.fixFailedMessage(_messageId);
address token = messageToken(_messageId);
if (_messageId == tokenRegistrationMessageId(token)) {
delete uintStorage[keccak256(abi.encodePacked("dailyLimit", token))];
delete uintStorage[keccak256(abi.encodePacked("maxPerTx", token))];
delete uintStorage[keccak256(abi.encodePacked("minPerTx", token))];
delete uintStorage[keccak256(abi.encodePacked("executionDailyLimit", token))];
delete uintStorage[keccak256(abi.encodePacked("executionMaxPerTx", token))];
_setTokenRegistrationMessageId(token, bytes32(0));
}
}
/**
* @dev Unlock back the amount of tokens that were bridged to the other network but failed.
* @param _token address that bridged token contract.
* @param _recipient address that will receive the tokens.
* @param _value amount of tokens to be received.
*/
function executeActionOnFixedTokens(address _token, address _recipient, uint256 _value) internal {
_setMediatorBalance(_token, mediatorBalance(_token).sub(_value));
_token.safeTransfer(_recipient, _value);
}
/**
* @dev Allows to send to the other network the amount of locked tokens that can be forced into the contract
* without the invocation of the required methods. (e. g. regular transfer without a call to onTokenTransfer)
* @param _token address of the token contract.
* @param _receiver the address that will receive the tokens on the other network.
*/
function fixMediatorBalance(address _token, address _receiver)
external
onlyIfUpgradeabilityOwner
validAddress(_receiver)
{
require(isTokenRegistered(_token));
uint256 balance = ERC677(_token).balanceOf(address(this));
uint256 expectedBalance = mediatorBalance(_token);
require(balance > expectedBalance);
uint256 diff = balance - expectedBalance;
uint256 available = maxAvailablePerTx(_token);
require(available > 0);
if (diff > available) {
diff = available;
}
addTotalSpentPerDay(_token, getCurrentDay(), diff);
_setMediatorBalance(_token, expectedBalance.add(diff));
bytes memory data = abi.encodeWithSelector(this.handleBridgedTokens.selector, _token, _receiver, diff);
bytes32 _messageId = bridgeContract().requireToPassMessage(
mediatorContractOnOtherSide(),
data,
requestGasLimit()
);
setMessageToken(_messageId, _token);
setMessageValue(_messageId, diff);
setMessageRecipient(_messageId, _receiver);
}
/**
* @dev Tells the expected token balance of the contract.
* @param _token address of token contract.
* @return the current tracked token balance of the contract.
*/
function mediatorBalance(address _token) public view returns (uint256) {
return uintStorage[keccak256(abi.encodePacked("mediatorBalance", _token))];
}
/**
* @dev Returns message id where specified token was first seen and deploy on the other side was requested.
* @param _token address of token contract.
* @return message id of the send message.
*/
function tokenRegistrationMessageId(address _token) public view returns (bytes32) {
return bytes32(uintStorage[keccak256(abi.encodePacked("tokenRegistrationMessageId", _token))]);
}
/**
* @dev Updates expected token balance of the contract.
* @param _token address of token contract.
* @param _balance the new token balance of the contract.
*/
function _setMediatorBalance(address _token, uint256 _balance) internal {
uintStorage[keccak256(abi.encodePacked("mediatorBalance", _token))] = _balance;
}
/**
* @dev Updates message id where specified token was first seen and deploy on the other side was requested.
* @param _token address of token contract.
* @param _messageId message id of the send message.
*/
function _setTokenRegistrationMessageId(address _token, bytes32 _messageId) internal {
uintStorage[keccak256(abi.encodePacked("tokenRegistrationMessageId", _token))] = uint256(_messageId);
}
function isTokenAllowed(address _token) public view returns (bool) {
return boolStorage[keccak256(abi.encodePacked("tokenAllowed", _token))];
}
function allowToken(address _token) external onlyOwner {
_allowToken(_token);
}
event TokenAllowed(address indexed token);
function _allowToken(address _token) internal {
require(!isTokenAllowed(_token));
require(AddressUtils.isContract(_token));
boolStorage[keccak256(abi.encodePacked("tokenAllowed", _token))] = true;
emit TokenAllowed(_token);
}
function disallowToken(address _token) external onlyOwner {
_disallowToken(_token);
}
event TokenDisallowed(address indexed token);
function _disallowToken(address _token) internal {
require(isTokenAllowed(_token));
require(AddressUtils.isContract(_token));
boolStorage[keccak256(abi.encodePacked("tokenAllowed", _token))] = false;
emit TokenDisallowed(_token);
}
}
pragma solidity 0.4.24;
import "./BasicMultiTokenBridge.sol";
import "../BaseRewardAddressList.sol";
import "../Ownable.sol";
import "../../interfaces/ERC677.sol";
import "../../interfaces/IBurnableMintableERC677Token.sol";
/**
* @title HomeFeeManagerMultiAMBErc20ToErc677
* @dev Implements the logic to distribute fees from the multi erc20 to erc677 mediator contract operations.
* The fees are distributed in the form of native tokens to the list of reward accounts.
*/
contract HomeFeeManagerMultiAMBErc20ToErc677 is BaseRewardAddressList, Ownable, BasicMultiTokenBridge {
using SafeMath for uint256;
event FeeUpdated(bytes32 feeType, address indexed token, uint256 fee);
event FeeDistributed(uint256 fee, address indexed token, bytes32 indexed messageId);
// This is not a real fee value but a relative value used to calculate the fee percentage
uint256 internal constant MAX_FEE = 1 ether;
bytes32 public constant HOME_TO_FOREIGN_FEE = 0x741ede137d0537e88e0ea0ff25b1f22d837903dbbee8980b4a06e8523247ee26; // keccak256(abi.encodePacked("homeToForeignFee"))
bytes32 public constant FOREIGN_TO_HOME_FEE = 0x03be2b2875cb41e0e77355e802a16769bb8dfcf825061cde185c73bf94f12625; // keccak256(abi.encodePacked("foreignToHomeFee"))
/**
* @dev Throws if given fee percentage is >= 100%.
*/
modifier validFee(uint256 _fee) {
require(_fee < MAX_FEE);
/* solcov ignore next */
_;
}
/**
* @dev Throws if given fee type is unknown.
*/
modifier validFeeType(bytes32 _feeType) {
require(_feeType == HOME_TO_FOREIGN_FEE || _feeType == FOREIGN_TO_HOME_FEE);
/* solcov ignore next */
_;
}
/**
* @dev Adds a new reward address to the list, which will receive fees collected from the bridge operations.
* Only the owner can call this method.
* @param _addr new reward account.
*/
function addRewardAddress(address _addr) external onlyOwner {
_addRewardAddress(_addr);
}
/**
* @dev Removes a reward address from the rewards list.
* Only the owner can call this method.
* @param _addr old reward account, that should be removed.
*/
function removeRewardAddress(address _addr) external onlyOwner {
_removeRewardAddress(_addr);
}
/**
* @dev Updates the value for the particular fee type.
* Only the owner can call this method.
* @param _feeType type of the updated fee, can be one of [HOME_TO_FOREIGN_FEE, FOREIGN_TO_HOME_FEE].
* @param _token address of the token contract for which fee should apply, 0x00..00 describes the initial fee for newly created tokens.
* @param _fee new fee value, in percentage (1 ether == 10**18 == 100%).
*/
function setFee(bytes32 _feeType, address _token, uint256 _fee) external onlyOwner {
_setFee(_feeType, _token, _fee);
}
/**
* @dev Retrieves the value for the particular fee type.
* @param _feeType type of the updated fee, can be one of [HOME_TO_FOREIGN_FEE, FOREIGN_TO_HOME_FEE].
* @param _token address of the token contract for which fee should apply, 0x00..00 describes the initial fee for newly created tokens.
* @return fee value associated with the requested fee type.
*/
function getFee(bytes32 _feeType, address _token) public view validFeeType(_feeType) returns (uint256) {
return uintStorage[keccak256(abi.encodePacked(_feeType, _token))];
}
/**
* @dev Calculates the amount of fee to pay for the value of the particular fee type.
* @param _feeType type of the updated fee, can be one of [HOME_TO_FOREIGN_FEE, FOREIGN_TO_HOME_FEE].
* @param _token address of the token contract for which fee should apply, 0x00..00 describes the initial fee for newly created tokens.
* @param _value bridged value, for which fee should be evaluated.
* @return amount of fee to be subtracted from the transferred value.
*/
function calculateFee(bytes32 _feeType, address _token, uint256 _value) public view returns (uint256) {
uint256 _fee = getFee(_feeType, _token);
return _value.mul(_fee).div(MAX_FEE);
}
/**
* @dev Internal function for updating the fee value for the given fee type.
* @param _feeType type of the updated fee, can be one of [HOME_TO_FOREIGN_FEE, FOREIGN_TO_HOME_FEE].
* @param _token address of the token contract for which fee should apply, 0x00..00 describes the initial fee for newly created tokens.
* @param _fee new fee value, in percentage (1 ether == 10**18 == 100%).
*/
function _setFee(bytes32 _feeType, address _token, uint256 _fee) internal validFeeType(_feeType) validFee(_fee) {
require(isTokenRegistered(_token));
uintStorage[keccak256(abi.encodePacked(_feeType, _token))] = _fee;
emit FeeUpdated(_feeType, _token, _fee);
}
/**
* @dev Calculates a random number based on the block number.
* @param _count the max value for the random number.
* @return a number between 0 and _count.
*/
function random(uint256 _count) internal view returns (uint256) {
return uint256(blockhash(block.number.sub(1))) % _count;
}
/**
* @dev Calculates and distributes the amount of fee proportionally between registered reward addresses.
* @param _feeType type of the updated fee, can be one of [HOME_TO_FOREIGN_FEE, FOREIGN_TO_HOME_FEE].
* @param _token address of the token contract for which fee should apply, 0x00..00 describes the initial fee for newly created tokens.
* @param _value bridged value, for which fee should be evaluated.
* @return total amount of fee subtracted from the transferred value and distributed between the reward accounts.
*/
function _distributeFee(bytes32 _feeType, address _token, uint256 _value) internal returns (uint256) {
uint256 numOfAccounts = rewardAddressCount();
uint256 _fee = calculateFee(_feeType, _token, _value);
if (numOfAccounts == 0 || _fee == 0) {
return 0;
}
uint256 feePerAccount = _fee.div(numOfAccounts);
uint256 randomAccountIndex;
uint256 diff = _fee.sub(feePerAccount.mul(numOfAccounts));
if (diff > 0) {
randomAccountIndex = random(numOfAccounts);
}
address nextAddr = getNextRewardAddress(F_ADDR);
require(nextAddr != F_ADDR && nextAddr != address(0));
uint256 i = 0;
while (nextAddr != F_ADDR) {
uint256 feeToDistribute = feePerAccount;
if (diff > 0 && randomAccountIndex == i) {
feeToDistribute = feeToDistribute.add(diff);
}
if (_feeType == HOME_TO_FOREIGN_FEE) {
ERC677(_token).transfer(nextAddr, feeToDistribute);
} else {
IBurnableMintableERC677Token(_token).mint(nextAddr, feeToDistribute);
}
nextAddr = getNextRewardAddress(nextAddr);
require(nextAddr != address(0));
i = i + 1;
}
return _fee;
}
}
pragma solidity 0.4.24;
import "./BasicMultiAMBErc20ToErc677.sol";
import "./TokenProxy.sol";
import "./HomeFeeManagerMultiAMBErc20ToErc677.sol";
import "../../interfaces/IBurnableMintableERC677Token.sol";
import "../../interfaces/IBridgeUtils.sol";
import "./MultiTokenForwardingRules.sol";
/**
* @title HomeMultiAMBErc20ToErc677
* @dev Home side implementation for multi-erc20-to-erc677 mediator intended to work on top of AMB bridge.
* It is designed to be used as an implementation contract of EternalStorageProxy contract.
*/
contract HomeMultiAMBErc20ToErc677 is
BasicMultiAMBErc20ToErc677,
HomeFeeManagerMultiAMBErc20ToErc677,
MultiTokenForwardingRules
{
bytes32 internal constant TOKEN_IMAGE_CONTRACT = 0x20b8ca26cc94f39fab299954184cf3a9bd04f69543e4f454fab299f015b8130f; // keccak256(abi.encodePacked("tokenImageContract"))
bytes32 internal constant BRIDGE_UTILS_CONTRACT = 0x174a58966ad4181674ba19a3131ba82f8683cbe56350f1172634244845855e9b; // keccak256(abi.encodePacked("bridgeUtilsContract"))
event NewTokenRegistered(address indexed foreignToken, address indexed homeToken);
event TokensBridgedToSafe(
address indexed token,
address indexed recipient,
address safe,
uint256 value,
bytes32 indexed messageId
);
/**
* @dev Stores the initial parameters of the mediator.
* @param _bridgeContract the address of the AMB bridge contract.
* @param _mediatorContract the address of the mediator contract on the other network.
* @param _dailyLimitMaxPerTxMinPerTxArray array with limit values for the assets to be bridged to the other network.
* [ 0 = dailyLimit, 1 = maxPerTx, 2 = minPerTx ]
* @param _executionDailyLimitExecutionMaxPerTxArray array with limit values for the assets bridged from the other network.
* [ 0 = executionDailyLimit, 1 = executionMaxPerTx ]
* @param _requestGasLimit the gas limit for the message execution.
* @param _owner address of the owner of the mediator contract.
* @param _tokenImage address of the PermittableToken contract that will be used for deploying of new tokens.
* @param _rewardAddresses list of reward addresses, between whom fees will be distributed.
* @param _fees array with initial fees for both bridge directions.
* [ 0 = homeToForeignFee, 1 = foreignToHomeFee ]
*/
function initialize(
address _bridgeContract,
address _mediatorContract,
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
uint256[2] _executionDailyLimitExecutionMaxPerTxArray, // [ 0 = _executionDailyLimit, 1 = _executionMaxPerTx ]
uint256 _requestGasLimit,
address _owner,
address _tokenImage,
address[] _rewardAddresses,
uint256[2] _fees, // [ 0 = homeToForeignFee, 1 = foreignToHomeFee ],
address _bridgeUtilsContract
) external onlyRelevantSender returns (bool) {
require(!isInitialized());
_setBridgeContract(_bridgeContract);
_setBridgeUtilsContract(_bridgeUtilsContract);
_setMediatorContractOnOtherSide(_mediatorContract);
_setLimits(address(0), _dailyLimitMaxPerTxMinPerTxArray);
_setExecutionLimits(address(0), _executionDailyLimitExecutionMaxPerTxArray);
_setRequestGasLimit(_requestGasLimit);
_setOwner(_owner);
_setTokenImage(_tokenImage);
if (_rewardAddresses.length > 0) {
_setRewardAddressList(_rewardAddresses);
}
_setFee(HOME_TO_FOREIGN_FEE, address(0), _fees[0]);
_setFee(FOREIGN_TO_HOME_FEE, address(0), _fees[1]);
setInitialize();
return isInitialized();
}
/**
* @dev Updates an address of the token image contract used for proxifying newly created tokens.
* @param _tokenImage address of PermittableToken contract.
*/
function setTokenImage(address _tokenImage) external onlyOwner {
_setTokenImage(_tokenImage);
}
function setBridgeUtilsContract(address _bridgeUtilsContract) external onlyOwner {
_setBridgeUtilsContract(_bridgeUtilsContract);
}
function _setBridgeUtilsContract(address _bridgeUtilsContract) internal {
require(AddressUtils.isContract(_bridgeUtilsContract));
addressStorage[BRIDGE_UTILS_CONTRACT] = _bridgeUtilsContract;
}
/**
* @dev Retrieves address of the token image contract.
* @return address of block reward contract.
*/
function tokenImage() public view returns (address) {
return addressStorage[TOKEN_IMAGE_CONTRACT];
}
function bridgeUtils() public view returns (address) {
return addressStorage[BRIDGE_UTILS_CONTRACT];
}
/**
* @dev Handles the bridged tokens for the first time, includes deployment of new TokenProxy contract.
* Checks that the value is inside the execution limits and invokes the method
* to execute the Mint or Unlock accordingly.
* @param _token address of the bridged ERC20/ERC677 token on the foreign side.
* @param _name name of the bridged token, "x" will be appended, if empty, symbol will be used instead.
* @param _symbol symbol of the bridged token, "x" will be appended, if empty, name will be used instead.
* @param _decimals decimals of the bridge foreign token.
* @param _recipient address that will receive the tokens.
* @param _value amount of tokens to be received.
*/
function deployAndHandleBridgedTokens(
address _token,
string _name,
string _symbol,
uint8 _decimals,
address _recipient,
uint256 _value
) external onlyMediator {
string memory name = _name;
string memory symbol = _symbol;
require(bytes(name).length > 0 || bytes(symbol).length > 0);
if (bytes(name).length == 0) {
name = symbol;
} else if (bytes(symbol).length == 0) {
symbol = name;
}
name = string(abi.encodePacked(name, ".CPXD"));
address homeToken = new TokenProxy(tokenImage(), name, symbol, _decimals, bridgeContract().sourceChainId());
_setTokenAddressPair(_token, homeToken);
_initializeTokenBridgeLimits(homeToken, _decimals);
_setFee(HOME_TO_FOREIGN_FEE, homeToken, getFee(HOME_TO_FOREIGN_FEE, address(0)));
_setFee(FOREIGN_TO_HOME_FEE, homeToken, getFee(FOREIGN_TO_HOME_FEE, address(0)));
IBridgeUtils bridgeUtilsInstance = IBridgeUtils(bridgeUtils());
bridgeUtilsInstance.addToken(homeToken);
_handleBridgedTokens(ERC677(homeToken), _recipient, _value);
emit NewTokenRegistered(_token, homeToken);
}
/**
* @dev Handles the bridged tokens. Checks that the value is inside the execution limits and invokes the method
* to execute the Mint or Unlock accordingly.
* @param _token bridged ERC20 token.
* @param _recipient address that will receive the tokens.
* @param _value amount of tokens to be received.
*/
function handleBridgedTokens(ERC677 _token, address _recipient, uint256 _value) external onlyMediator {
ERC677 homeToken = ERC677(homeTokenAddress(_token));
require(isTokenRegistered(homeToken));
_handleBridgedTokens(homeToken, _recipient, _value);
}
/**
* @dev ERC677 transfer callback function.
* @param _from address of tokens sender.
* @param _value amount of transferred tokens.
* @param _data additional transfer data, can be used for passing alternative receiver address.
*/
function onTokenTransfer(address _from, uint256 _value, bytes _data) public returns (bool) {
// if onTokenTransfer is called as a part of call to _relayTokens, this callback does nothing
if (!lock()) {
ERC677 token = ERC677(msg.sender);
// if msg.sender if not a valid token contract, this check will fail, since limits are zeros
// so the following check is not needed
// require(isTokenRegistered(token));
require(withinLimit(token, _value));
addTotalSpentPerDay(token, getCurrentDay(), _value);
bridgeSpecificActionsOnTokenTransfer(token, _from, _value, _data);
}
return true;
}
/**
* @dev Validates that the token amount is inside the limits, calls transferFrom to transfer the tokens to the contract
* and invokes the method to burn/lock the tokens and unlock/mint the tokens on the other network.
* The user should first call Approve method of the ERC677 token.
* @param token bridge token contract address.
* @param _receiver address that will receive the native tokens on the other network.
* @param _value amount of tokens to be transferred to the other network.
*/
function _relayTokens(ERC677 token, address _receiver, uint256 _value) internal {
// This lock is to prevent calling passMessage twice if a ERC677 token is used.
// When transferFrom is called, after the transfer, the ERC677 token will call onTokenTransfer from this contract
// which will call passMessage.
require(!lock());
address to = address(this);
// if msg.sender if not a valid token contract, this check will fail, since limits are zeros
// so the following check is not needed
// require(isTokenRegistered(token));
require(withinLimit(token, _value));
addTotalSpentPerDay(token, getCurrentDay(), _value);
setLock(true);
token.transferFrom(msg.sender, to, _value);
setLock(false);
bridgeSpecificActionsOnTokenTransfer(token, msg.sender, _value, abi.encodePacked(_receiver));
}
/**
* @dev Executes action on the request to deposit tokens relayed from the other network
* @param _recipient address of tokens receiver
* @param _value amount of bridged tokens
*/
function executeActionOnBridgedTokens(address _token, address _recipient, uint256 _value) internal {
bytes32 _messageId = messageId();
uint256 valueToMint = _value;
uint256 fee = _distributeFee(FOREIGN_TO_HOME_FEE, _token, valueToMint);
if (fee > 0) {
emit FeeDistributed(fee, _token, _messageId);
valueToMint = valueToMint.sub(fee);
}
address safeAddress;
IBridgeUtils bridgeUtilsInstance = IBridgeUtils(bridgeUtils());
if (bridgeUtilsInstance.isRegistered(_recipient)) {
safeAddress = bridgeUtilsInstance.safeForSupplier(_recipient);
require(safeAddress != address(0));
} else {
safeAddress = bridgeUtilsInstance.registerSupplier(_recipient);
}
IBurnableMintableERC677Token(_token).mint(safeAddress, valueToMint);
emit TokensBridgedToSafe(_token, _recipient, safeAddress, valueToMint, _messageId);
}
/**
* @dev Mints back the amount of tokens that were bridged to the other network but failed.
* @param _token address that bridged token contract.
* @param _recipient address that will receive the tokens.
* @param _value amount of tokens to be received.
*/
function executeActionOnFixedTokens(address _token, address _recipient, uint256 _value) internal {
IBurnableMintableERC677Token(_token).mint(_recipient, _value);
}
/**
* @dev Retrieves address of the home bridged token contract associated with a specific foreign token contract.
* @param _foreignToken address of the created home token contract.
* @return address of the home token contract.
*/
function homeTokenAddress(address _foreignToken) public view returns (address) {
return addressStorage[keccak256(abi.encodePacked("hta", _foreignToken))];
}
/**
* @dev Retrieves address of the foreign bridged token contract associated with a specific home token contract.
* @param _homeToken address of the created home token contract.
* @return address of the foreign token contract.
*/
function foreignTokenAddress(address _homeToken) public view returns (address) {
return addressStorage[keccak256(abi.encodePacked("fta", _homeToken))];
}
/**
* @dev Internal function for updating an address of the token image contract.
* @param _foreignToken address of bridged foreign token contract.
* @param _foreignToken address of created home token contract.
*/
function _setTokenAddressPair(address _foreignToken, address _homeToken) internal {
addressStorage[keccak256(abi.encodePacked("hta", _foreignToken))] = _homeToken;
addressStorage[keccak256(abi.encodePacked("fta", _homeToken))] = _foreignToken;
}
/**
* @dev Internal function for updating an address of the token image contract.
* @param _tokenImage address of deployed PermittableToken contract.
*/
function _setTokenImage(address _tokenImage) internal {
require(AddressUtils.isContract(_tokenImage));
addressStorage[TOKEN_IMAGE_CONTRACT] = _tokenImage;
}
/**
* @dev Executes action on withdrawal of bridged tokens
* @param _token address of token contract
* @param _from address of tokens sender
* @param _value requested amount of bridged tokens
* @param _data alternative receiver, if specified
*/
function bridgeSpecificActionsOnTokenTransfer(ERC677 _token, address _from, uint256 _value, bytes _data) internal {
if (!lock()) {
uint256 valueToBridge = _value;
uint256 fee = 0;
// Next line disables fee collection in case sender is one of the reward addresses.
// It is needed to allow a 100% withdrawal of tokens from the home side.
// If fees are not disabled for reward receivers, small fraction of tokens will always
// be redistributed between the same set of reward addresses, which is not the desired behaviour.
if (!isRewardAddress(_from)) {
fee = _distributeFee(HOME_TO_FOREIGN_FEE, _token, valueToBridge);
valueToBridge = valueToBridge.sub(fee);
}
IBurnableMintableERC677Token(_token).burn(valueToBridge);
bytes32 _messageId = passMessage(_token, _from, chooseReceiver(_from, _data), valueToBridge);
if (fee > 0) {
emit FeeDistributed(fee, _token, _messageId);
}
}
}
/**
* @dev Call AMB bridge to require the invocation of handleBridgedTokens method of the mediator on the other network.
* Store information related to the bridged tokens in case the message execution fails on the other network
* and the action needs to be fixed/rolled back.
* @param _token bridged ERC20 token
* @param _from address of sender, if bridge operation fails, tokens will be returned to this address
* @param _receiver address of receiver on the other side, will eventually receive bridged tokens
* @param _value bridged amount of tokens
* @return id of the created and passed message
*/
function passMessage(ERC677 _token, address _from, address _receiver, uint256 _value) internal returns (bytes32) {
bytes4 methodSelector = this.handleBridgedTokens.selector;
address foreignToken = foreignTokenAddress(_token);
bytes memory data = abi.encodeWithSelector(methodSelector, foreignToken, _receiver, _value);
address executor = mediatorContractOnOtherSide();
uint256 gasLimit = requestGasLimit();
IAMB bridge = bridgeContract();
// Address of the foreign token is used here for determining lane permissions.
// Such decision makes it possible to set rules for tokens that are not bridged yet.
bytes32 _messageId = destinationLane(foreignToken, _from, _receiver) >= 0
? bridge.requireToPassMessage(executor, data, gasLimit)
: bridge.requireToConfirmMessage(executor, data, gasLimit);
setMessageToken(_messageId, _token);
setMessageValue(_messageId, _value);
setMessageRecipient(_messageId, _from);
emit TokensBridgingInitiated(_token, _from, _value, _messageId);
return _messageId;
}
}
pragma solidity 0.4.24;
import "../../interfaces/ERC677.sol";
import "./BasicMultiTokenBridge.sol";
import "../BasicAMBMediator.sol";
import "../ChooseReceiverHelper.sol";
import "../TransferInfoStorage.sol";
/**
* @title MultiTokenBridgeMediator
* @dev Common mediator functionality to handle operations related to multi-token bridge messages sent to AMB bridge.
*/
contract MultiTokenBridgeMediator is
BasicAMBMediator,
BasicMultiTokenBridge,
TransferInfoStorage,
ChooseReceiverHelper
{
event FailedMessageFixed(bytes32 indexed messageId, address token, address recipient, uint256 value);
event TokensBridgingInitiated(
address indexed token,
address indexed sender,
uint256 value,
bytes32 indexed messageId
);
event TokensBridged(address indexed token, address indexed recipient, uint256 value, bytes32 indexed messageId);
/**
* @dev Stores the bridged token of a message sent to the AMB bridge.
* @param _messageId of the message sent to the bridge.
* @param _token bridged token address.
*/
function setMessageToken(bytes32 _messageId, address _token) internal {
addressStorage[keccak256(abi.encodePacked("messageToken", _messageId))] = _token;
}
/**
* @dev Tells the bridged token address of a message sent to the AMB bridge.
* @return address of a token contract.
*/
function messageToken(bytes32 _messageId) internal view returns (address) {
return addressStorage[keccak256(abi.encodePacked("messageToken", _messageId))];
}
/**
* @dev Handles the bridged tokens. Checks that the value is inside the execution limits and invokes the method
* to execute the Mint or Unlock accordingly.
* @param _token bridged ERC20/ERC677 token
* @param _recipient address that will receive the tokens
* @param _value amount of tokens to be received
*/
function _handleBridgedTokens(ERC677 _token, address _recipient, uint256 _value) internal {
if (withinExecutionLimit(_token, _value)) {
addTotalExecutedPerDay(_token, getCurrentDay(), _value);
executeActionOnBridgedTokens(_token, _recipient, _value);
} else {
executeActionOnBridgedTokensOutOfLimit(_token, _recipient, _value);
}
}
/**
* @dev Method to be called when a bridged message execution failed. It will generate a new message requesting to
* fix/roll back the transferred assets on the other network.
* @param _messageId id of the message which execution failed.
*/
function requestFailedMessageFix(bytes32 _messageId) external {
require(!bridgeContract().messageCallStatus(_messageId));
require(bridgeContract().failedMessageReceiver(_messageId) == address(this));
require(bridgeContract().failedMessageSender(_messageId) == mediatorContractOnOtherSide());
bytes4 methodSelector = this.fixFailedMessage.selector;
bytes memory data = abi.encodeWithSelector(methodSelector, _messageId);
bridgeContract().requireToPassMessage(mediatorContractOnOtherSide(), data, requestGasLimit());
}
/**
* @dev Handles the request to fix transferred assets which bridged message execution failed on the other network.
* It uses the information stored by passMessage method when the assets were initially transferred
* @param _messageId id of the message which execution failed on the other network.
*/
function fixFailedMessage(bytes32 _messageId) public onlyMediator {
require(!messageFixed(_messageId));
address token = messageToken(_messageId);
address recipient = messageRecipient(_messageId);
uint256 value = messageValue(_messageId);
setMessageFixed(_messageId);
executeActionOnFixedTokens(token, recipient, value);
emit FailedMessageFixed(_messageId, token, recipient, value);
}
/**
* @dev Execute the action to be performed when the bridge tokens are out of execution limits.
*/
function executeActionOnBridgedTokensOutOfLimit(address, address, uint256) internal {
revert();
}
/* solcov ignore next */
function executeActionOnBridgedTokens(address _token, address _recipient, uint256 _value) internal;
/* solcov ignore next */
function executeActionOnFixedTokens(address _token, address _recipient, uint256 _value) internal;
}
pragma solidity 0.4.24;
import "../../upgradeable_contracts/Ownable.sol";
/**
* @title MultiTokenForwardingRules
* @dev Multi token mediator functionality for managing destination AMB lanes permissions.
*/
contract MultiTokenForwardingRules is Ownable {
address internal constant ANY_ADDRESS = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF;
event ForwardingRuleUpdated(address token, address sender, address receiver, int256 lane);
/**
* @dev Tells the destination lane for a particular bridge operation by checking several wildcard forwarding rules.
* @param _token address of the token contract on the foreign side of the bridge.
* @param _sender address of the tokens sender on the home side of the bridge.
* @param _receiver address of the tokens receiver on the foreign side of the bridge.
* @return destination lane identifier, where the message should be forwarded to.
* 1 - oracle-driven-lane should be used.
* 0 - default behaviour should be applied.
* -1 - manual lane should be used.
*/
function destinationLane(address _token, address _sender, address _receiver) public view returns (int256) {
int256 defaultLane = forwardingRule(_token, ANY_ADDRESS, ANY_ADDRESS); // specific token for all senders and receivers
int256 lane;
if (defaultLane < 0) {
lane = forwardingRule(_token, _sender, ANY_ADDRESS); // specific token for specific sender
if (lane != 0) return lane;
lane = forwardingRule(_token, ANY_ADDRESS, _receiver); // specific token for specific receiver
if (lane != 0) return lane;
return defaultLane;
}
lane = forwardingRule(ANY_ADDRESS, _sender, ANY_ADDRESS); // all tokens for specific sender
if (lane != 0) return lane;
return forwardingRule(ANY_ADDRESS, ANY_ADDRESS, _receiver); // all tokens for specific receiver
}
/**
* Updates the forwarding rule for bridging specific token.
* Only owner can call this method.
* @param _token address of the token contract on the foreign side.
* @param _enable true, if bridge operations for a given token should be forwarded to the manual lane.
*/
function setTokenForwardingRule(address _token, bool _enable) external {
require(_token != ANY_ADDRESS);
_setForwardingRule(_token, ANY_ADDRESS, ANY_ADDRESS, _enable ? int256(-1) : int256(0));
}
/**
* Allows a particular address to send bridge requests to the oracle-driven lane for a particular token.
* Only owner can call this method.
* @param _token address of the token contract on the foreign side.
* @param _sender address of the tokens sender on the home side of the bridge.
* @param _enable true, if bridge operations for a given token and sender should be forwarded to the oracle-driven lane.
*/
function setSenderExceptionForTokenForwardingRule(address _token, address _sender, bool _enable) external {
require(_token != ANY_ADDRESS);
require(_sender != ANY_ADDRESS);
_setForwardingRule(_token, _sender, ANY_ADDRESS, _enable ? int256(1) : int256(0));
}
/**
* Allows a particular address to receive bridged tokens from the oracle-driven lane for a particular token.
* Only owner can call this method.
* @param _token address of the token contract on the foreign side.
* @param _receiver address of the tokens receiver on the foreign side of the bridge.
* @param _enable true, if bridge operations for a given token and receiver should be forwarded to the oracle-driven lane.
*/
function setReceiverExceptionForTokenForwardingRule(address _token, address _receiver, bool _enable) external {
require(_token != ANY_ADDRESS);
require(_receiver != ANY_ADDRESS);
_setForwardingRule(_token, ANY_ADDRESS, _receiver, _enable ? int256(1) : int256(0));
}
/**
* Updates the forwarding rule for the specific sender.
* Only owner can call this method.
* @param _sender address of the tokens sender on the home side.
* @param _enable true, if all bridge operations from a given sender should be forwarded to the manual lane.
*/
function setSenderForwardingRule(address _sender, bool _enable) external {
require(_sender != ANY_ADDRESS);
_setForwardingRule(ANY_ADDRESS, _sender, ANY_ADDRESS, _enable ? int256(-1) : int256(0));
}
/**
* Updates the forwarding rule for the specific receiver.
* Only owner can call this method.
* @param _receiver address of the tokens receiver on the foreign side.
* @param _enable true, if all bridge operations to a given receiver should be forwarded to the manual lane.
*/
function setReceiverForwardingRule(address _receiver, bool _enable) external {
require(_receiver != ANY_ADDRESS);
_setForwardingRule(ANY_ADDRESS, ANY_ADDRESS, _receiver, _enable ? int256(-1) : int256(0));
}
/**
* @dev Tells forwarding rule set up for a particular bridge operation.
* @param _token address of the token contract on the foreign side of the bridge.
* @param _sender address of the tokens sender on the home side of the bridge.
* @param _receiver address of the tokens receiver on the foreign side of the bridge.
* @return preferred destination lane for the particular bridge operation.
*/
function forwardingRule(address _token, address _sender, address _receiver) public view returns (int256) {
return intStorage[keccak256(abi.encodePacked("f2", _token, _sender, _receiver))];
}
/**
* @dev Internal function for updating the preferred destination lane for the specific wildcard pattern.
* Only owner can call this method.
* Examples:
* _setForwardingRule(tokenA, ANY_ADDRESS, ANY_ADDRESS, -1) - forward all operations on tokenA to the manual lane
* _setForwardingRule(tokenA, Alice, ANY_ADDRESS, 1) - allow Alice to use the oracle-driven lane for bridging tokenA
* _setForwardingRule(tokenA, ANY_ADDRESS, Bob, 1) - forward all tokenA bridge operations, where Bob is the receiver, to the oracle-driven lane
* _setForwardingRule(ANY_ADDRESS, Mallory, ANY_ADDRESS, -1) - forward all bridge operations from Mallory to the manual lane
* @param _token address of the token contract on the foreign side of the bridge.
* @param _sender address of the tokens sender on the home side of the bridge.
* @param _receiver address of the tokens receiver on the foreign side of the bridge.
* @param _lane preferred destination lane for the particular sender.
* 1 - forward to the oracle-driven lane.
* 0 - behaviour is unset, proceed by checking other less-specific rules.
* -1 - manual lane should be used.
*/
function _setForwardingRule(address _token, address _sender, address _receiver, int256 _lane) internal onlyOwner {
intStorage[keccak256(abi.encodePacked("f2", _token, _sender, _receiver))] = _lane;
emit ForwardingRuleUpdated(_token, _sender, _receiver, _lane);
}
}
pragma solidity 0.4.24;
import "../../upgradeability/Proxy.sol";
interface IPermittableTokenVersion {
function version() external pure returns (string);
}
/**
* @title TokenProxy
* @dev Helps to reduces the size of the deployed bytecode for automatically created tokens, by using a proxy contract.
*/
contract TokenProxy is Proxy {
// storage layout is copied from PermittableToken.sol
string internal name;
string internal symbol;
uint8 internal decimals;
mapping(address => uint256) internal balances;
uint256 internal totalSupply;
mapping(address => mapping(address => uint256)) internal allowed;
address internal owner;
bool internal mintingFinished;
address internal bridgeContractAddr;
// string public constant version = "1";
bytes32 internal DOMAIN_SEPARATOR;
// bytes32 public constant PERMIT_TYPEHASH = 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb;
mapping(address => uint256) internal nonces;
mapping(address => mapping(address => uint256)) internal expirations;
/**
* @dev Creates a non-upgradeable token proxy for PermitableToken.sol, initializes its eternalStorage.
* @param _tokenImage address of the token image used for mirroring all functions.
* @param _name token name.
* @param _symbol token symbol.
* @param _decimals token decimals.
* @param _chainId chain id for current network.
*/
constructor(address _tokenImage, string memory _name, string memory _symbol, uint8 _decimals, uint256 _chainId)
public
{
string memory version = IPermittableTokenVersion(_tokenImage).version();
assembly {
// EIP 1967
// bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
sstore(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc, _tokenImage)
}
name = _name;
symbol = _symbol;
decimals = _decimals;
owner = msg.sender; // msg.sender == HomeMultiAMBErc20ToErc677 mediator
bridgeContractAddr = msg.sender;
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(_name)),
keccak256(bytes(version)),
_chainId,
address(this)
)
);
}
/**
* @dev Retrieves the implementation contract address, mirrored token image.
* @return token image address.
*/
function implementation() public view returns (address impl) {
assembly {
impl := sload(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc)
}
}
}
pragma solidity 0.4.24;
import "../upgradeability/EternalStorage.sol";
contract OtherSideBridgeStorage is EternalStorage {
bytes32 internal constant BRIDGE_CONTRACT = 0x71483949fe7a14d16644d63320f24d10cf1d60abecc30cc677a340e82b699dd2; // keccak256(abi.encodePacked("bridgeOnOtherSide"))
function _setBridgeContractOnOtherSide(address _bridgeContract) internal {
require(_bridgeContract != address(0));
addressStorage[BRIDGE_CONTRACT] = _bridgeContract;
}
function bridgeContractOnOtherSide() internal view returns (address) {
return addressStorage[BRIDGE_CONTRACT];
}
}
pragma solidity 0.4.24;
import "../upgradeability/EternalStorage.sol";
import "../interfaces/IUpgradeabilityOwnerStorage.sol";
/**
* @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;
}
}

Solidity contracts implemeting core bridge functionality.

Do not forget to update the flattening script when a new bridge mode is being implemented

pragma solidity 0.4.24;
import "../upgradeability/EternalStorage.sol";
contract ReentrancyGuard is EternalStorage {
bytes32 internal constant LOCK = 0x6168652c307c1e813ca11cfb3a601f1cf3b22452021a5052d8b05f1f1f8a3e92; // keccak256(abi.encodePacked("lock"))
function lock() internal returns (bool) {
return boolStorage[LOCK];
}
function setLock(bool _lock) internal {
boolStorage[LOCK] = _lock;
}
}
pragma solidity 0.4.24;
import "openzeppelin-solidity/contracts/AddressUtils.sol";
import "./Ownable.sol";
import "./FeeTypes.sol";
/**
* @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);
}
}
}
pragma solidity 0.4.24;
import "./Ownable.sol";
import "openzeppelin-solidity/contracts/AddressUtils.sol";
import "../interfaces/IMediatorFeeManager.sol";
/**
* @title RewardableMediator
* @dev Common functionality to interact with mediator fee manager contract methods.
*/
contract RewardableMediator is Ownable {
event FeeDistributed(uint256 feeAmount, bytes32 indexed messageId);
bytes32 internal constant FEE_MANAGER_CONTRACT = 0x779a349c5bee7817f04c960f525ee3e2f2516078c38c68a3149787976ee837e5; // keccak256(abi.encodePacked("feeManagerContract"))
bytes4 internal constant ON_TOKEN_TRANSFER = 0xa4c0ed36; // onTokenTransfer(address,uint256,bytes)
/**
* @dev Sets the fee manager contract address. Only the owner can call this method.
* @param _feeManager the address of the fee manager contract.
*/
function setFeeManagerContract(address _feeManager) external onlyOwner {
_setFeeManagerContract(_feeManager);
}
/**
* @dev Internal function for enabling new / disabling fee manage contract.
* @param _feeManager the address of the fee manager contract.
*/
function _setFeeManagerContract(address _feeManager) internal {
require(_feeManager == address(0) || AddressUtils.isContract(_feeManager));
addressStorage[FEE_MANAGER_CONTRACT] = _feeManager;
}
/**
* @dev Tells the fee manager contract address
* @return the address of the fee manager contract.
*/
function feeManagerContract() public view returns (IMediatorFeeManager) {
return IMediatorFeeManager(addressStorage[FEE_MANAGER_CONTRACT]);
}
/**
* @dev Distributes the provided amount of fees.
* @param _feeManager address of the fee manager contract
* @param _fee total amount to be distributed to the list of reward accounts.
* @param _messageId id of the message that generated fee distribution
*/
function distributeFee(IMediatorFeeManager _feeManager, uint256 _fee, bytes32 _messageId) internal {
onFeeDistribution(_feeManager, _fee);
_feeManager.call(abi.encodeWithSelector(ON_TOKEN_TRANSFER, address(this), _fee, ""));
emit FeeDistributed(_fee, _messageId);
}
/* solcov ignore next */
function onFeeDistribution(address _feeManager, uint256 _fee) internal;
}
pragma solidity 0.4.24;
import "./BaseBridgeValidators.sol";
contract RewardableValidators is BaseBridgeValidators {
function initialize(
uint256 _requiredSignatures,
address[] _initialValidators,
address[] _initialRewards,
address _owner
) external onlyRelevantSender returns (bool) {
require(!isInitialized());
_setOwner(_owner);
require(_requiredSignatures != 0);
require(_initialValidators.length >= _requiredSignatures);
require(_initialValidators.length == _initialRewards.length);
for (uint256 i = 0; i < _initialValidators.length; i++) {
require(_initialValidators[i] != address(0) && _initialValidators[i] != F_ADDR);
require(_initialRewards[i] != address(0));
require(!isValidator(_initialValidators[i]));
if (i == 0) {
setNextValidator(F_ADDR, _initialValidators[i]);
if (_initialValidators.length == 1) {
setNextValidator(_initialValidators[i], F_ADDR);
}
} else if (i == _initialValidators.length - 1) {
setNextValidator(_initialValidators[i - 1], _initialValidators[i]);
setNextValidator(_initialValidators[i], F_ADDR);
} else {
setNextValidator(_initialValidators[i - 1], _initialValidators[i]);
}
setValidatorRewardAddress(_initialValidators[i], _initialRewards[i]);
emit ValidatorAdded(_initialValidators[i]);
}
setValidatorCount(_initialValidators.length);
uintStorage[REQUIRED_SIGNATURES] = _requiredSignatures;
uintStorage[DEPLOYED_AT_BLOCK] = block.number;
setInitialize();
emit RequiredSignaturesChanged(_requiredSignatures);
return isInitialized();
}
function addRewardableValidator(address _validator, address _reward) external onlyOwner {
require(_reward != address(0));
_addValidator(_validator);
setValidatorRewardAddress(_validator, _reward);
emit ValidatorAdded(_validator);
}
function removeValidator(address _validator) external onlyOwner {
_removeValidator(_validator);
deleteItemFromAddressStorage("validatorsRewards", _validator);
emit ValidatorRemoved(_validator);
}
function getValidatorRewardAddress(address _validator) external view returns (address) {
return addressStorage[keccak256(abi.encodePacked("validatorsRewards", _validator))];
}
function setValidatorRewardAddress(address _validator, address _reward) internal {
addressStorage[keccak256(abi.encodePacked("validatorsRewards", _validator))] = _reward;
}
}
pragma solidity 0.4.24;
contract Sacrifice {
constructor(address _recipient) public payable {
selfdestruct(_recipient);
}
}
pragma solidity 0.4.24;
import "./BasicAMBMediator.sol";
import "./BasicTokenBridge.sol";
import "./TransferInfoStorage.sol";
/**
* @title TokenBridgeMediator
* @dev Common mediator functionality to handle operations related to token bridge messages sent to AMB bridge.
*/
contract TokenBridgeMediator is BasicAMBMediator, BasicTokenBridge, TransferInfoStorage {
event FailedMessageFixed(bytes32 indexed messageId, address recipient, uint256 value);
event TokensBridgingInitiated(address indexed sender, uint256 value, bytes32 indexed messageId);
event TokensBridged(address indexed recipient, uint256 value, bytes32 indexed messageId);
/**
* @dev Call AMB bridge to require the invocation of handleBridgedTokens method of the mediator on the other network.
* Store information related to the bridged tokens in case the message execution fails on the other network
* and the action needs to be fixed/rolled back.
* @param _from address of sender, if bridge operation fails, tokens will be returned to this address
* @param _receiver address of receiver on the other side, will eventually receive bridged tokens
* @param _value bridged amount of tokens
*/
function passMessage(address _from, address _receiver, uint256 _value) internal {
bytes4 methodSelector = this.handleBridgedTokens.selector;
bytes memory data = abi.encodeWithSelector(methodSelector, _receiver, _value);
bytes32 _messageId = bridgeContract().requireToPassMessage(
mediatorContractOnOtherSide(),
data,
requestGasLimit()
);
setMessageValue(_messageId, _value);
setMessageRecipient(_messageId, _from);
emit TokensBridgingInitiated(_from, _value, _messageId);
}
/**
* @dev Handles the bridged tokens. Checks that the value is inside the execution limits and invokes the method
* to execute the Mint or Unlock accordingly.
* @param _recipient address that will receive the tokens
* @param _value amount of tokens to be received
*/
function handleBridgedTokens(address _recipient, uint256 _value) external onlyMediator {
if (withinExecutionLimit(_value)) {
addTotalExecutedPerDay(getCurrentDay(), _value);
executeActionOnBridgedTokens(_recipient, _value);
} else {
executeActionOnBridgedTokensOutOfLimit(_recipient, _value);
}
}
/**
* @dev Method to be called when a bridged message execution failed. It will generate a new message requesting to
* fix/roll back the transferred assets on the other network.
* @param _messageId id of the message which execution failed.
*/
function requestFailedMessageFix(bytes32 _messageId) external {
require(!bridgeContract().messageCallStatus(_messageId));
require(bridgeContract().failedMessageReceiver(_messageId) == address(this));
require(bridgeContract().failedMessageSender(_messageId) == mediatorContractOnOtherSide());
bytes4 methodSelector = this.fixFailedMessage.selector;
bytes memory data = abi.encodeWithSelector(methodSelector, _messageId);
bridgeContract().requireToPassMessage(mediatorContractOnOtherSide(), data, requestGasLimit());
}
/**
* @dev Handles the request to fix transferred assets which bridged message execution failed on the other network.
* It uses the information stored by passMessage method when the assets were initially transferred
* @param _messageId id of the message which execution failed on the other network.
*/
function fixFailedMessage(bytes32 _messageId) external onlyMediator {
require(!messageFixed(_messageId));
address recipient = messageRecipient(_messageId);
uint256 value = messageValue(_messageId);
setMessageFixed(_messageId);
executeActionOnFixedTokens(recipient, value);
emit FailedMessageFixed(_messageId, recipient, value);
}
/* solcov ignore next */
function executeActionOnBridgedTokensOutOfLimit(address _recipient, uint256 _value) internal;
/* solcov ignore next */
function executeActionOnBridgedTokens(address _recipient, uint256 _value) internal;
/* solcov ignore next */
function executeActionOnFixedTokens(address _recipient, uint256 _value) internal;
}
pragma solidity 0.4.24;
contract TokenSwapper {
// emitted when two tokens is swapped (e. g. Sai to Dai, Chai to Dai)
event TokensSwapped(address indexed from, address indexed to, uint256 value);
}
pragma solidity 0.4.24;
import "../upgradeability/EternalStorage.sol";
contract TransferInfoStorage is EternalStorage {
/**
* @dev Stores the value of a message sent to the AMB bridge.
* @param _messageId of the message sent to the bridge.
* @param _value amount of tokens bridged.
*/
function setMessageValue(bytes32 _messageId, uint256 _value) internal {
uintStorage[keccak256(abi.encodePacked("messageValue", _messageId))] = _value;
}
/**
* @dev Tells the amount of tokens of a message sent to the AMB bridge.
* @return value representing amount of tokens.
*/
function messageValue(bytes32 _messageId) internal view returns (uint256) {
return uintStorage[keccak256(abi.encodePacked("messageValue", _messageId))];
}
/**
* @dev Stores the receiver of a message sent to the AMB bridge.
* @param _messageId of the message sent to the bridge.
* @param _recipient receiver of the tokens bridged.
*/
function setMessageRecipient(bytes32 _messageId, address _recipient) internal {
addressStorage[keccak256(abi.encodePacked("messageRecipient", _messageId))] = _recipient;
}
/**
* @dev Tells the receiver of a message sent to the AMB bridge.
* @return address of the receiver.
*/
function messageRecipient(bytes32 _messageId) internal view returns (address) {
return addressStorage[keccak256(abi.encodePacked("messageRecipient", _messageId))];
}
/**
* @dev Sets that the message sent to the AMB bridge has been fixed.
* @param _messageId of the message sent to the bridge.
*/
function setMessageFixed(bytes32 _messageId) internal {
boolStorage[keccak256(abi.encodePacked("messageFixed", _messageId))] = true;
}
/**
* @dev Tells if a message sent to the AMB bridge has been fixed.
* @return bool indicating the status of the message.
*/
function messageFixed(bytes32 _messageId) public view returns (bool) {
return boolStorage[keccak256(abi.encodePacked("messageFixed", _messageId))];
}
}
pragma solidity 0.4.24;
import "../interfaces/IUpgradeabilityOwnerStorage.sol";
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 */
_;
}
}
pragma solidity 0.4.24;
import "../interfaces/IBridgeValidators.sol";
import "../upgradeability/EternalStorage.sol";
import "./ValidatorStorage.sol";
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();
}
}
pragma solidity 0.4.24;
import "./BaseFeeManager.sol";
import "../interfaces/IRewardableValidators.sol";
import "./ValidatorStorage.sol";
contract ValidatorsFeeManager is BaseFeeManager, ValidatorStorage {
bytes32 public constant REWARD_FOR_TRANSFERRING_FROM_HOME = 0x2a11db67c480122765825a7e4bc5428e8b7b9eca0d4e62b91aac194f99edd0d7; // keccak256(abi.encodePacked("reward-transferring-from-home"))
bytes32 public constant REWARD_FOR_TRANSFERRING_FROM_FOREIGN = 0xb14796d751eb4f2570065a479f9e526eabeb2077c564c8a1c5ea559883ea2fab; // keccak256(abi.encodePacked("reward-transferring-from-foreign"))
function distributeFeeFromAffirmation(uint256 _fee) external {
distributeFeeProportionally(_fee, REWARD_FOR_TRANSFERRING_FROM_FOREIGN);
}
function distributeFeeFromSignatures(uint256 _fee) external {
distributeFeeProportionally(_fee, REWARD_FOR_TRANSFERRING_FROM_HOME);
}
function rewardableValidatorContract() internal view returns (IRewardableValidators) {
return IRewardableValidators(addressStorage[VALIDATOR_CONTRACT]);
}
function distributeFeeProportionally(uint256 _fee, bytes32 _direction) internal {
IRewardableValidators validators = rewardableValidatorContract();
// solhint-disable-next-line var-name-mixedcase
address F_ADDR = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF;
uint256 numOfValidators = validators.validatorCount();
uint256 feePerValidator = _fee.div(numOfValidators);
uint256 randomValidatorIndex;
uint256 diff = _fee.sub(feePerValidator.mul(numOfValidators));
if (diff > 0) {
randomValidatorIndex = random(numOfValidators);
}
address nextValidator = validators.getNextValidator(F_ADDR);
require((nextValidator != F_ADDR) && (nextValidator != address(0)));
uint256 i = 0;
while (nextValidator != F_ADDR) {
uint256 feeToDistribute = feePerValidator;
if (diff > 0 && randomValidatorIndex == i) {
feeToDistribute = feeToDistribute.add(diff);
}
address rewardAddress = validators.getValidatorRewardAddress(nextValidator);
onFeeDistribution(rewardAddress, feeToDistribute, _direction);
nextValidator = validators.getNextValidator(nextValidator);
require(nextValidator != address(0));
i = i + 1;
}
}
function onFeeDistribution(address _rewardAddress, uint256 _fee, bytes32 _direction) internal {
if (_direction == REWARD_FOR_TRANSFERRING_FROM_FOREIGN) {
onAffirmationFeeDistribution(_rewardAddress, _fee);
} else {
onSignatureFeeDistribution(_rewardAddress, _fee);
}
}
/* solcov ignore next */
function onAffirmationFeeDistribution(address _rewardAddress, uint256 _fee) internal;
/* solcov ignore next */
function onSignatureFeeDistribution(address _rewardAddress, uint256 _fee) internal;
}
pragma solidity 0.4.24;
contract ValidatorStorage {
bytes32 internal constant VALIDATOR_CONTRACT = 0x5a74bb7e202fb8e4bf311841c7d64ec19df195fee77d7e7ae749b27921b6ddfe; // keccak256(abi.encodePacked("validatorContract"))
}
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);
}
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;
}
}
pragma solidity ^0.4.24;
/**
* @title AutoIncrementing
* @author Matt Condon (@shrugs)
* @dev Provides an auto-incrementing uint256 id acquired by the `Counter#nextId` getter.
* Use this for issuing ERC721Token ids or keeping track of request ids, anything you want, really.
*
* Include with `using AutoIncrementing for AutoIncrementing.Counter;`
* @notice Does not allow an Id of 0, which is popularly used to signify a null state in solidity.
* Does not protect from overflows, but if you have 2^256 ids, you have other problems.
* (But actually, it's generally impossible to increment a counter this many times, energy wise
* so it's not something you have to worry about.)
*/
library AutoIncrementing {
struct Counter {
uint256 prevId; // default: 0
}
function nextId(Counter storage _counter)
internal
returns (uint256)
{
_counter.prevId = _counter.prevId + 1;
return _counter.prevId;
}
}
pragma solidity ^0.4.24;
import "./payment/PullPayment.sol";
import "./lifecycle/Destructible.sol";
/**
* @title Bounty
* @dev This bounty will pay out to a researcher if they break invariant logic of the contract.
*/
contract Bounty is PullPayment, Destructible {
bool public claimed;
mapping(address => address) public researchers;
event TargetCreated(address createdAddress);
/**
* @dev Fallback function allowing the contract to receive funds, if they haven't already been claimed.
*/
function() external payable {
require(!claimed);
}
/**
* @dev Create and deploy the target contract (extension of Target contract), and sets the
* msg.sender as a researcher
* @return A target contract
*/
function createTarget() public returns(Target) {
Target target = Target(deployContract());
researchers[target] = msg.sender;
emit TargetCreated(target);
return target;
}
/**
* @dev Transfers the contract funds to the researcher that proved the contract is broken.
* @param _target contract
*/
function claim(Target _target) public {
address researcher = researchers[_target];
require(researcher != address(0));
// Check Target contract invariants
require(!_target.checkInvariant());
asyncTransfer(researcher, address(this).balance);
claimed = true;
}
/**
* @dev Internal function to deploy the target contract.
* @return A target contract address
*/
function deployContract() internal returns(address);
}
/**
* @title Target
* @dev Your main contract should inherit from this class and implement the checkInvariant method.
*/
contract Target {
/**
* @dev Checks all values a contract assumes to be true all the time. If this function returns
* false, the contract is broken in some way and is in an inconsistent state.
* In order to win the bounty, security researchers will try to cause this broken state.
* @return True if all invariant values are correct, false otherwise.
*/
function checkInvariant() public returns(bool);
}
pragma solidity ^0.4.24;
/**
* @title Elliptic curve signature operations
* @dev Based on https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d
* TODO Remove this library once solidity supports passing a signature to ecrecover.
* See https://github.com/ethereum/solidity/issues/864
*/
library ECRecovery {
/**
* @dev Recover signer address from a message by using their signature
* @param _hash bytes32 message, the hash is the signed message. What is recovered is the signer address.
* @param _sig bytes signature, the signature is generated using web3.eth.sign()
*/
function recover(bytes32 _hash, bytes _sig)
internal
pure
returns (address)
{
bytes32 r;
bytes32 s;
uint8 v;
// Check the signature length
if (_sig.length != 65) {
return (address(0));
}
// Divide the signature in r, s and v variables
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
// solium-disable-next-line security/no-inline-assembly
assembly {
r := mload(add(_sig, 32))
s := mload(add(_sig, 64))
v := byte(0, mload(add(_sig, 96)))
}
// Version of signature should be 27 or 28, but 0 and 1 are also possible versions
if (v < 27) {
v += 27;
}
// If the version is correct return the signer address
if (v != 27 && v != 28) {
return (address(0));
} else {
// solium-disable-next-line arg-overflow
return ecrecover(_hash, v, r, s);
}
}
/**
* toEthSignedMessageHash
* @dev prefix a bytes32 value with "\x19Ethereum Signed Message:"
* and hash the result
*/
function toEthSignedMessageHash(bytes32 _hash)
internal
pure
returns (bytes32)
{
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash)
);
}
}
pragma solidity ^0.4.24;
/**
* @title LimitBalance
* @dev Simple contract to limit the balance of child contract.
* Note this doesn't prevent other contracts to send funds by using selfdestruct(address);
* See: https://github.com/ConsenSys/smart-contract-best-practices#remember-that-ether-can-be-forcibly-sent-to-an-account
*/
contract LimitBalance {
uint256 public limit;
/**
* @dev Constructor that sets the passed value as a limit.
* @param _limit uint256 to represent the limit.
*/
constructor(uint256 _limit) public {
limit = _limit;
}
/**
* @dev Checks if limit was reached. Case true, it throws.
*/
modifier limitedPayable() {
require(address(this).balance <= limit);
_;
}
}
pragma solidity ^0.4.24;
/**
* @title Math
* @dev Assorted math operations
*/
library Math {
function max64(uint64 _a, uint64 _b) internal pure returns (uint64) {
return _a >= _b ? _a : _b;
}
function min64(uint64 _a, uint64 _b) internal pure returns (uint64) {
return _a < _b ? _a : _b;
}
function max256(uint256 _a, uint256 _b) internal pure returns (uint256) {
return _a >= _b ? _a : _b;
}
function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {
return _a < _b ? _a : _b;
}
}
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;
}
}
pragma solidity ^0.4.24;
/**
* @title MerkleProof
* @dev Merkle proof verification based on
* https://github.com/ameensol/merkle-tree-solidity/blob/master/src/MerkleProof.sol
*/
library MerkleProof {
/**
* @dev Verifies a Merkle proof proving the existence of a leaf in a Merkle tree. Assumes that each pair of leaves
* and each pair of pre-images are sorted.
* @param _proof Merkle proof containing sibling hashes on the branch from the leaf to the root of the Merkle tree
* @param _root Merkle root
* @param _leaf Leaf of Merkle tree
*/
function verifyProof(
bytes32[] _proof,
bytes32 _root,
bytes32 _leaf
)
internal
pure
returns (bool)
{
bytes32 computedHash = _leaf;
for (uint256 i = 0; i < _proof.length; i++) {
bytes32 proofElement = _proof[i];
if (computedHash < proofElement) {
// Hash(current computed hash + current element of the proof)
computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
} else {
// Hash(current element of the proof + current computed hash)
computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
}
}
// Check if the computed hash (root) is equal to the provided root
return computedHash == _root;
}
}
pragma solidity ^0.4.24;
/**
* @title Helps contracts guard against reentrancy attacks.
* @author Remco Bloemen <remco@2π.com>, Eenae <alexey@mixbytes.io>
* @dev If you mark a function `nonReentrant`, you should also
* mark it `external`.
*/
contract ReentrancyGuard {
/// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.
/// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056
uint private constant REENTRANCY_GUARD_FREE = 1;
/// @dev Constant for locked guard state
uint private constant REENTRANCY_GUARD_LOCKED = 2;
/**
* @dev We use a single lock for the whole contract.
*/
uint private reentrancyLock = REENTRANCY_GUARD_FREE;
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* If you mark a function `nonReentrant`, you should also
* mark it `external`. Calling one `nonReentrant` function from
* another is not supported. Instead, you can implement a
* `private` function doing the actual work, and an `external`
* wrapper marked as `nonReentrant`.
*/
modifier nonReentrant() {
require(reentrancyLock == REENTRANCY_GUARD_FREE);
reentrancyLock = REENTRANCY_GUARD_LOCKED;
_;
reentrancyLock = REENTRANCY_GUARD_FREE;
}
}
pragma solidity ^0.4.24;
import "./ERC20Basic.sol";
import "../../math/SafeMath.sol";
/**
* @title Basic token
* @dev Basic version of StandardToken, with no allowances.
*/
contract BasicToken is ERC20Basic {
using SafeMath for uint256;
mapping(address => uint256) internal balances;
uint256 internal totalSupply_;
/**
* @dev Total number of tokens in existence
*/
function totalSupply() public view returns (uint256) {
return totalSupply_;
}
/**
* @dev Transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint256 _value) public returns (bool) {
require(_value <= balances[msg.sender]);
require(_to != address(0));
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address _owner) public view returns (uint256) {
return balances[_owner];
}
}
pragma solidity ^0.4.24;
import "./BasicToken.sol";
/**
* @title Burnable Token
* @dev Token that can be irreversibly burned (destroyed).
*/
contract BurnableToken is BasicToken {
event Burn(address indexed burner, uint256 value);
/**
* @dev Burns a specific amount of tokens.
* @param _value The amount of token to be burned.
*/
function burn(uint256 _value) public {
_burn(msg.sender, _value);
}
function _burn(address _who, uint256 _value) internal {
require(_value <= balances[_who]);
// no need to require value <= totalSupply, since that would imply the
// sender's balance is greater than the totalSupply, which *should* be an assertion failure
balances[_who] = balances[_who].sub(_value);
totalSupply_ = totalSupply_.sub(_value);
emit Burn(_who, _value);
emit Transfer(_who, address(0), _value);
}
}
pragma solidity ^0.4.24;
import "./MintableToken.sol";
/**
* @title Capped token
* @dev Mintable token with a token cap.
*/
contract CappedToken is MintableToken {
uint256 public cap;
constructor(uint256 _cap) public {
require(_cap > 0);
cap = _cap;
}
/**
* @dev Function to mint tokens
* @param _to The address that will receive the minted tokens.
* @param _amount The amount of tokens to mint.
* @return A boolean that indicates if the operation was successful.
*/
function mint(
address _to,
uint256 _amount
)
public
returns (bool)
{
require(totalSupply_.add(_amount) <= cap);
return super.mint(_to, _amount);
}
}
pragma solidity ^0.4.24;
import "./ERC20.sol";
/**
* @title DetailedERC20 token
* @dev The decimals are only for visualization purposes.
* All the operations are done using the smallest and indivisible token unit,
* just as on Ethereum all the operations are done in wei.
*/
contract DetailedERC20 is ERC20 {
string public name;
string public symbol;
uint8 public decimals;
constructor(string _name, string _symbol, uint8 _decimals) public {
name = _name;
symbol = _symbol;
decimals = _decimals;
}
}
pragma solidity ^0.4.24;
import "./ERC20Basic.sol";
/**
* @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
);
}
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);
}
pragma solidity ^0.4.24;
import "./StandardToken.sol";
import "../../ownership/Ownable.sol";
/**
* @title Mintable token
* @dev Simple ERC20 Token example, with mintable token creation
* Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol
*/
contract MintableToken is StandardToken, Ownable {
event Mint(address indexed to, uint256 amount);
event MintFinished();
bool public mintingFinished = false;
modifier canMint() {
require(!mintingFinished);
_;
}
modifier hasMintPermission() {
require(msg.sender == owner);
_;
}
/**
* @dev Function to mint tokens
* @param _to The address that will receive the minted tokens.
* @param _amount The amount of tokens to mint.
* @return A boolean that indicates if the operation was successful.
*/
function mint(
address _to,
uint256 _amount
)
public
hasMintPermission
canMint
returns (bool)
{
totalSupply_ = totalSupply_.add(_amount);
balances[_to] = balances[_to].add(_amount);
emit Mint(_to, _amount);
emit Transfer(address(0), _to, _amount);
return true;
}
/**
* @dev Function to stop minting new tokens.
* @return True if the operation was successful.
*/
function finishMinting() public onlyOwner canMint returns (bool) {
mintingFinished = true;
emit MintFinished();
return true;
}
}
pragma solidity ^0.4.24;
import "./StandardToken.sol";
import "../../lifecycle/Pausable.sol";
/**
* @title Pausable token
* @dev StandardToken modified with pausable transfers.
**/
contract PausableToken is StandardToken, Pausable {
function transfer(
address _to,
uint256 _value
)
public
whenNotPaused
returns (bool)
{
return super.transfer(_to, _value);
}
function transferFrom(
address _from,
address _to,
uint256 _value
)
public
whenNotPaused
returns (bool)
{
return super.transferFrom(_from, _to, _value);
}
function approve(
address _spender,
uint256 _value
)
public
whenNotPaused
returns (bool)
{
return super.approve(_spender, _value);
}
function increaseApproval(
address _spender,
uint _addedValue
)
public
whenNotPaused
returns (bool success)
{
return super.increaseApproval(_spender, _addedValue);
}
function decreaseApproval(
address _spender,
uint _subtractedValue
)
public
whenNotPaused
returns (bool success)
{
return super.decreaseApproval(_spender, _subtractedValue);
}
}
pragma solidity ^0.4.24;
import "./MintableToken.sol";
import "../../access/rbac/RBAC.sol";
/**
* @title RBACMintableToken
* @author Vittorio Minacori (@vittominacori)
* @dev Mintable Token, with RBAC minter permissions
*/
contract RBACMintableToken is MintableToken, RBAC {
/**
* A constant role name for indicating minters.
*/
string public constant ROLE_MINTER = "minter";
/**
* @dev override the Mintable token modifier to add role based logic
*/
modifier hasMintPermission() {
checkRole(msg.sender, ROLE_MINTER);
_;
}
/**
* @dev add a minter role to an address
* @param _minter address
*/
function addMinter(address _minter) public onlyOwner {
addRole(_minter, ROLE_MINTER);
}
/**
* @dev remove a minter role from an address
* @param _minter address
*/
function removeMinter(address _minter) public onlyOwner {
removeRole(_minter, ROLE_MINTER);
}
}
pragma solidity ^0.4.24;
import "./ERC20Basic.sol";
import "./ERC20.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure.
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
function safeTransfer(
ERC20Basic _token,
address _to,
uint256 _value
)
internal
{
require(_token.transfer(_to, _value));
}
function safeTransferFrom(
ERC20 _token,
address _from,
address _to,
uint256 _value
)
internal
{
require(_token.transferFrom(_from, _to, _value));
}
function safeApprove(
ERC20 _token,
address _spender,
uint256 _value
)
internal
{
require(_token.approve(_spender, _value));
}
}
pragma solidity ^0.4.24;
import "./BurnableToken.sol";
import "./StandardToken.sol";
/**
* @title Standard Burnable Token
* @dev Adds burnFrom method to ERC20 implementations
*/
contract StandardBurnableToken is BurnableToken, StandardToken {
/**
* @dev Burns a specific amount of tokens from the target address and decrements allowance
* @param _from address The address which you want to send tokens from
* @param _value uint256 The amount of token to be burned
*/
function burnFrom(address _from, uint256 _value) public {
require(_value <= allowed[_from][msg.sender]);
// Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted,
// this function needs to emit an event with the updated approval.
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
_burn(_from, _value);
}
}
pragma solidity ^0.4.24;
import "./BasicToken.sol";
import "./ERC20.sol";
/**
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* https://github.com/ethereum/EIPs/issues/20
* Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*/
contract StandardToken is ERC20, BasicToken {
mapping (address => mapping (address => uint256)) internal allowed;
/**
* @dev Transfer tokens from one address to another
* @param _from address The address which you want to send tokens from
* @param _to address The address which you want to transfer to
* @param _value uint256 the amount of tokens to be transferred
*/
function transferFrom(
address _from,
address _to,
uint256 _value
)
public
returns (bool)
{
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
require(_to != address(0));
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
emit Transfer(_from, _to, _value);
return true;
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
* Beware that changing an allowance with this method brings the risk that someone may use both the old
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
/**
* @dev Function to check the amount of tokens that an owner allowed to a spender.
* @param _owner address The address which owns the funds.
* @param _spender address The address which will spend the funds.
* @return A uint256 specifying the amount of tokens still available for the spender.
*/
function allowance(
address _owner,
address _spender
)
public
view
returns (uint256)
{
return allowed[_owner][_spender];
}
/**
* @dev Increase the amount of tokens that an owner allowed to a spender.
* approve should be called when allowed[_spender] == 0. To increment
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _addedValue The amount of tokens to increase the allowance by.
*/
function increaseApproval(
address _spender,
uint256 _addedValue
)
public
returns (bool)
{
allowed[msg.sender][_spender] = (
allowed[msg.sender][_spender].add(_addedValue));
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
/**
* @dev Decrease the amount of tokens that an owner allowed to a spender.
* approve should be called when allowed[_spender] == 0. To decrement
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _subtractedValue The amount of tokens to decrease the allowance by.
*/
function decreaseApproval(
address _spender,
uint256 _subtractedValue
)
public
returns (bool)
{
uint256 oldValue = allowed[msg.sender][_spender];
if (_subtractedValue >= oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
}
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
}
pragma solidity ^0.4.24;
import "./SafeERC20.sol";
/**
* @title TokenTimelock
* @dev TokenTimelock is a token holder contract that will allow a
* beneficiary to extract the tokens after a given release time
*/
contract TokenTimelock {
using SafeERC20 for ERC20Basic;
// ERC20 basic token contract being held
ERC20Basic public token;
// beneficiary of tokens after they are released
address public beneficiary;
// timestamp when token release is enabled
uint256 public releaseTime;
constructor(
ERC20Basic _token,
address _beneficiary,
uint256 _releaseTime
)
public
{
// solium-disable-next-line security/no-block-members
require(_releaseTime > block.timestamp);
token = _token;
beneficiary = _beneficiary;
releaseTime = _releaseTime;
}
/**
* @notice Transfers tokens held by timelock to beneficiary.
*/
function release() public {
// solium-disable-next-line security/no-block-members
require(block.timestamp >= releaseTime);
uint256 amount = token.balanceOf(address(this));
require(amount > 0);
token.safeTransfer(beneficiary, amount);
}
}
/* solium-disable security/no-block-members */
pragma solidity ^0.4.24;
import "./ERC20Basic.sol";
import "./SafeERC20.sol";
import "../../ownership/Ownable.sol";
import "../../math/SafeMath.sol";
/**
* @title TokenVesting
* @dev A token holder contract that can release its token balance gradually like a
* typical vesting scheme, with a cliff and vesting period. Optionally revocable by the
* owner.
*/
contract TokenVesting is Ownable {
using SafeMath for uint256;
using SafeERC20 for ERC20Basic;
event Released(uint256 amount);
event Revoked();
// beneficiary of tokens after they are released
address public beneficiary;
uint256 public cliff;
uint256 public start;
uint256 public duration;
bool public revocable;
mapping (address => uint256) public released;
mapping (address => bool) public revoked;
/**
* @dev Creates a vesting contract that vests its balance of any ERC20 token to the
* _beneficiary, gradually in a linear fashion until _start + _duration. By then all
* of the balance will have vested.
* @param _beneficiary address of the beneficiary to whom vested tokens are transferred
* @param _cliff duration in seconds of the cliff in which tokens will begin to vest
* @param _start the time (as Unix time) at which point vesting starts
* @param _duration duration in seconds of the period in which the tokens will vest
* @param _revocable whether the vesting is revocable or not
*/
constructor(
address _beneficiary,
uint256 _start,
uint256 _cliff,
uint256 _duration,
bool _revocable
)
public
{
require(_beneficiary != address(0));
require(_cliff <= _duration);
beneficiary = _beneficiary;
revocable = _revocable;
duration = _duration;
cliff = _start.add(_cliff);
start = _start;
}
/**
* @notice Transfers vested tokens to beneficiary.
* @param _token ERC20 token which is being vested
*/
function release(ERC20Basic _token) public {
uint256 unreleased = releasableAmount(_token);
require(unreleased > 0);
released[_token] = released[_token].add(unreleased);
_token.safeTransfer(beneficiary, unreleased);
emit Released(unreleased);
}
/**
* @notice Allows the owner to revoke the vesting. Tokens already vested
* remain in the contract, the rest are returned to the owner.
* @param _token ERC20 token which is being vested
*/
function revoke(ERC20Basic _token) public onlyOwner {
require(revocable);
require(!revoked[_token]);
uint256 balance = _token.balanceOf(address(this));
uint256 unreleased = releasableAmount(_token);
uint256 refund = balance.sub(unreleased);
revoked[_token] = true;
_token.safeTransfer(owner, refund);
emit Revoked();
}
/**
* @dev Calculates the amount that has already vested but hasn't been released yet.
* @param _token ERC20 token which is being vested
*/
function releasableAmount(ERC20Basic _token) public view returns (uint256) {
return vestedAmount(_token).sub(released[_token]);
}
/**
* @dev Calculates the amount that has already vested.
* @param _token ERC20 token which is being vested
*/
function vestedAmount(ERC20Basic _token) public view returns (uint256) {
uint256 currentBalance = _token.balanceOf(address(this));
uint256 totalBalance = currentBalance.add(released[_token]);
if (block.timestamp < cliff) {
return 0;
} else if (block.timestamp >= start.add(duration) || revoked[_token]) {
return totalBalance;
} else {
return totalBalance.mul(block.timestamp.sub(start)).div(duration);
}
}
}
// Right click on the script name and hit "Run" to execute
(async () => {
try {
console.log('Running deployWithEthers script...')
const contractName = 'Storage' // Change this for other contract
const constructorArgs = [] // Put constructor args (if any) here for your contract
// Note that the script needs the ABI which is generated from the compilation artifact.
// Make sure contract is compiled and artifacts are generated
const artifactsPath = `browser/contracts/artifacts/${contractName}.json` // Change this for different path
const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath))
// 'web3Provider' is a remix global variable object
const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner()
let factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer);
let contract = await factory.deploy(...constructorArgs);
console.log('Contract Address: ', contract.address);
// The contract is NOT deployed yet; we must wait until it is mined
await contract.deployed()
console.log('Deployment successful.')
} catch (e) {
console.log(e.message)
}
})()
// Right click on the script name and hit "Run" to execute
(async () => {
try {
console.log('Running deployWithWeb3 script...')
const contractName = 'Storage' // Change this for other contract
const constructorArgs = [] // Put constructor args (if any) here for your contract
// Note that the script needs the ABI which is generated from the compilation artifact.
// Make sure contract is compiled and artifacts are generated
const artifactsPath = `browser/contracts/artifacts/${contractName}.json` // Change this for different path
const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath))
const accounts = await web3.eth.getAccounts()
let contract = new web3.eth.Contract(metadata.abi)
contract = contract.deploy({
data: metadata.data.bytecode.object,
arguments: constructorArgs
})
const newContractInstance = await contract.send({
from: accounts[0],
gas: 1500000,
gasPrice: '30000000000'
})
console.log('Contract deployed at address: ', newContractInstance.options.address)
} catch (e) {
console.log(e.message)
}
})()
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
import "remix_tests.sol"; // this import is automatically injected by Remix.
import "../contracts/3_Ballot.sol";
contract BallotTest {
bytes32[] proposalNames;
Ballot ballotToTest;
function beforeAll () public {
proposalNames.push(bytes32("candidate1"));
ballotToTest = new Ballot(proposalNames);
}
function checkWinningProposal () public {
ballotToTest.vote(0);
Assert.equal(ballotToTest.winningProposal(), uint(0), "proposal at index 0 should be the winning proposal");
Assert.equal(ballotToTest.winnerName(), bytes32("candidate1"), "candidate1 should be the winner name");
}
function checkWinninProposalWithReturnValue () public view returns (bool) {
return ballotToTest.winningProposal() == 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment