Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- BridgeV2
- Optimization enabled
- true
- Compiler version
- v0.8.19+commit.7dd6d404
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2025-03-16T13:30:12.677028Z
contracts/BridgeV2.sol
// SPDX-License-Identifier: No License (None)
pragma solidity ^0.8.0;
interface IERC20TokenCloned {
// initialize cloned token just for ERC20TokenCloned
function initialize(
string calldata name,
string calldata symbol,
uint8 decimals
) external;
function mint(address user, uint256 amount) external;
function burnFrom(address account, uint256 amount) external returns (bool);
function burn(uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
function allowance(address _owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function decimals() external view returns (uint8);
function symbol() external view returns (string memory);
function name() external view returns (string memory);
function transferOwnership(address newOwner) external;
}
interface IContractCaller {
function callContract(
address user,
address token,
uint256 value,
address toContract,
bytes memory data
) external payable;
}
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*
* _Available since v3.4._
*/
library Clones {
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address implementation) internal returns (address instance) {
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, implementation))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
instance := create(0, ptr, 0x37)
}
require(instance != address(0), "ERC1167: create failed");
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple time will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, implementation))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
instance := create2(0, ptr, 0x37, salt)
}
require(instance != address(0), "ERC1167: create2 failed");
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, implementation))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
mstore(add(ptr, 0x38), shl(0x60, deployer))
mstore(add(ptr, 0x4c), salt)
mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
predicted := keccak256(add(ptr, 0x37), 0x55)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(address implementation, bytes32 salt)
internal
view
returns (address predicted)
{
return predictDeterministicAddress(implementation, salt, address(this));
}
}
// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
function safeApprove(address token, address to, uint value) internal {
// bytes4(keccak256(bytes('approve(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
}
function safeTransfer(address token, address to, uint value) internal {
// bytes4(keccak256(bytes('transfer(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
}
function safeTransferFrom(address token, address from, address to, uint value) internal {
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
}
function safeTransferETH(address to, uint value) internal {
(bool success,) = to.call{value:value}(new bytes(0));
require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
}
}
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256`
* (`UintSet`) are supported.
*/
library EnumerableSet {
struct AddressSet {
// Storage of set values
address[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(address => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value)
internal
returns (bool)
{
if (!contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value)
internal
returns (bool)
{
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
// When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
// so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
address lastvalue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastvalue;
// Update the index for the moved value
set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value)
internal
view
returns (bool)
{
return set._indexes[value] != 0;
}
/**
* @dev Returns 1-based index of value in the set. O(1).
*/
function indexOf(AddressSet storage set, address value)
internal
view
returns (uint256)
{
return set._indexes[value];
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index)
internal
view
returns (address)
{
require(
set._values.length > index,
"EnumerableSet: index out of bounds"
);
return set._values[index];
}
}
abstract contract Ownable {
address internal _owner;
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
/* will use initialize instead
constructor () {
_owner = msg.sender;
emit OwnershipTransferred(address(0), msg.sender);
}
*/
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == msg.sender, "Ownable: caller is not the owner");
_;
}
}
interface IBridge {
function owner() external view returns (address);
}
contract ContractCaller {
using TransferHelper for address;
address constant NATIVE_COINS = address(1); // address is considered as native coins
address public bridge;
event RescuedTokens(address token, address to, uint256 balance);
modifier onlyOwner() {
require(msg.sender == IBridge(bridge).owner(), "Only owner"); // owner multisig
_;
}
modifier onlyBridge() {
require(msg.sender == bridge, "Only bridge"); // Bridge contract address
_;
}
constructor () {
bridge = msg.sender;
}
function tokenReceived(address _from, uint, bytes calldata) external view{
require(_from == bridge, "Only from bridge"); // Bridge contract address
}
function rescueTokens(address token, address to) external onlyOwner {
uint256 balance;
if (token == address(0)) {
balance = address(this).balance;
to.safeTransferETH(balance);
} else {
balance = IERC20TokenCloned(token).balanceOf(address(this));
token.safeTransfer(to, balance);
}
emit RescuedTokens(token, to, balance);
}
function callContract(address user, address token, uint256 value, address toContract, bytes memory data) external payable onlyBridge {
if (token == NATIVE_COINS) {
value = msg.value;
uint balanceBefore = address(this).balance - value; // balance before
(bool success,) = toContract.call{value: value}(data);
if (success) value = address(this).balance - balanceBefore; // check, if we have some rest of token
if (value != 0) user.safeTransferETH(value); // send coin to user
} else {
token.safeApprove(toContract, value);
(bool success,) = toContract.call{value: 0}(data);
if (success) value = IERC20TokenCloned(token).allowance(address(this), toContract); // unused amount (the rest) = allowance
if (value != 0) { // if not all value used reset approvement
token.safeApprove(toContract, 0);
token.safeTransfer(user, value); // send to user rest of tokens
}
}
}
}
contract BridgeV2 is Ownable {
using TransferHelper for address;
using EnumerableSet for EnumerableSet.AddressSet;
EnumerableSet.AddressSet authorities; // authority has to sign claim transaction (message)
EnumerableSet.AddressSet tokenList; // list of added tokens in the bridge on this chain
address constant NATIVE_COINS = address(1); // address is considered as native coins
struct Token {
address token; // origin token address
uint256 chainID; // origin token chainID
address wrappedToken; // address of wrapped token on this chain (address(0) if no wrapped token)
address authority; // authority address that MUST approve token transfer. address(0) - not set. It may not be in the authorities list
}
struct Upgrade {
address newContract;
uint64 validFrom;
}
// Token details for frontend returns by getTokenList function
struct TokenDetails {
address token;
uint8 decimals;
string name;
string symbol;
}
uint256 public threshold; // minimum number of signatures required to approve swap
address public tokenImplementation; // implementation of wrapped token
address public feeTo; // send fee to this address
bool public frozen; // if frozen - swap will not work
mapping(uint256 => mapping(bytes32 => bool)) public isTxProcessed; // chainID => txID => isProcessed
mapping(address => uint256) public tokenDeposits; // amount of tokens were deposited by users
mapping(address => bool) public isFreezer; // addresses that have right to freeze contract
uint256 public setupMode; // time when setup mode will start, 0 if disable
Upgrade public upgradeData; // data for upgrade to new contract
address public founders; // founders multisig wallet. It has right to change owner
address public contractCaller; // intermediate contract that calls third-party contract functions (toContract)
mapping(bytes32 => Token) internal addedTokens; // native (wrapped) token address => Token struct
mapping(address => bytes32) internal nativeToToken; // mapping from native token to key hash for Token structure
mapping(uint256 => bool) public isSupported; // chainID => isSupported
mapping(address => bool) public requiredAuthorities; // authority address that MUST sign swap transaction (trusted authorities)
uint256 public minRequiredAuthorities; // minimum number of trusted authorities required to sign transaction
mapping(address nativeToken => uint256) internal bridgeFee; // fee in percent with 4 decimals (i.e. 1.5% = 15000) for specific token. 0 - no fee. bridgeFee[address(0)] - global fee
event SetAuthority(address authority, bool isEnable);
event SetRequiredAuthority(address authority, bool isEnable);
event SetTokenAuthority(address indexed token, uint256 chainId, address authority);
event SetFeeTo(address previousFeeTo, address newFeeTo);
event SetBridgeFee(address token, uint256 fee); // fee in percent with 4 decimals (i.e. 1.5% = 15000). 0 - no fee. bridgeFee[address(0)] - global fee
event SetThreshold(uint256 threshold, uint256 minRequiredAuthorities);
event SetContractCaller(address newContractCaller);
event Deposit(
address indexed originalToken,
uint256 originalChainID,
address indexed token,
address indexed receiver,
uint256 value,
uint256 toChainId
);
event Claim(
address indexed originalToken,
uint256 originalChainID,
address indexed token,
address indexed to,
uint256 value,
bytes32 txId,
uint256 fromChainId
);
event Fee(address sender, address token, uint256 fee); // fee amount in token paid by user.
event CreatePair(address toToken, address fromToken, uint256 fromChainId);
event Frozen(bool status);
event RescuedERC20(address token, address to, uint256 value);
event SetFreezer(address freezer, bool isActive);
event SetupMode(uint256 time);
event UpgradeRequest(address newContract, uint256 validFrom);
event BridgeToContract(
address indexed originalToken,
uint256 originalChainID,
address indexed token,
address indexed receiver,
uint256 value,
uint256 toChainId,
address toContract,
bytes data
);
event ClaimToContract(
address indexed originalToken,
uint256 originalChainID,
address indexed token,
address indexed to,
uint256 value,
bytes32 txId,
uint256 fromChainId,
address toContract
);
event AddToken(
address indexed token,
uint256 chainID,
uint256 decimals,
string name,
string symbol
);
event SetSupportedChain(uint256 chainID, bool isSupported);
// run only once from proxy
function initialize(
address newOwner, // bridge owner (company wallet)
address newFounders,
address _feeTo, // wallet which receive fees from bridge
address _tokenImplementation, // token implementation contract
uint256 _threshold, // minimum authorities required to approve bridge transaction
address[] calldata _authorities, // addresses of authorities. _authorities[0] is requiredAuthority
uint256[] calldata _chainID, // supported chain IDs (exclude native chain)
string calldata _nativeCoin // name of native coin (i.e. ETH, BNB, MATIC)
) external {
require(
_owner == address(0) &&
newOwner != address(0) &&
newFounders != address(0) &&
_feeTo != address(0) &&
_tokenImplementation != address(0) &&
_threshold != 0
); // run only once
_owner = newOwner;
founders = newFounders;
emit OwnershipTransferred(address(0), newOwner);
setupMode = 1; // allow setup after deployment
addAuthorities(_authorities);
setSupportedChain(_chainID, true);
tokenImplementation = _tokenImplementation;
contractCaller = address(new ContractCaller());
feeTo = _feeTo;
emit SetFeeTo(address(0), _feeTo);
// set threshold and required authorities
threshold = _threshold;
minRequiredAuthorities = 1;
emit SetThreshold(_threshold, 1);
requiredAuthorities[_authorities[0]] = true;
emit SetRequiredAuthority(_authorities[0], true);
// add native coin to bridge
bytes32 key = keccak256(abi.encodePacked(address(1), block.chainid));
addedTokens[key].token = address(1);
addedTokens[key].chainID = block.chainid;
nativeToToken[address(1)] = key;
emit AddToken(address(1), block.chainid, 18, _nativeCoin, _nativeCoin);
}
constructor () {
_owner = address(1); // disallow to use implementation contract directly
}
modifier notFrozen() {
require(!frozen, "Bridge is frozen");
_;
}
// allowed only in setup mode
modifier onlySetup() {
uint256 mode = setupMode; //use local variable to save gas
require(mode != 0 && mode < block.timestamp, "Not in setup mode");
_;
}
function upgradeTo() external view returns (address newContract) {
Upgrade memory upg = upgradeData;
require(
upg.validFrom < block.timestamp && upg.newContract != address(0),
"Upgrade not allowed"
);
newContract = upg.newContract;
}
function requestUpgrade(address newContract) external onlyOwner {
require(newContract != address(0), "Zero address");
uint256 validFrom = block.timestamp + 3 days; // remove delay for testing
upgradeData = Upgrade(newContract, uint64(validFrom));
emit UpgradeRequest(newContract, validFrom);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public {
require(founders == msg.sender || _owner == msg.sender, "Ownable: caller is not the founders");
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
function changeFounder(address newFounders) public {
require(founders == msg.sender, "caller is not the founders");
require(newFounders != address(0), "new owner is the zero address");
emit OwnershipTransferred(founders, newFounders);
founders = newFounders;
}
// get number of authorities
function getAuthoritiesNumber() external view returns (uint256) {
return authorities.length();
}
// returns list of authorities addresses
function getAuthorities() external view returns (address[] memory) {
return authorities._values;
}
// Owner or Authority may freeze bridge in case of anomaly detection
function freeze() external {
require(
msg.sender == owner() ||
authorities.contains(msg.sender) ||
isFreezer[msg.sender]
);
frozen = true;
emit Frozen(true);
}
// Only owner can manually unfreeze contract
function unfreeze() external onlyOwner onlySetup {
frozen = false;
emit Frozen(false);
}
// add address to freezer list (who can freeze bridge)
function setFreezer(address freezer, bool isActive) external onlyOwner {
require(freezer != address(0), "Zero address");
isFreezer[freezer] = isActive;
emit SetFreezer(freezer, isActive);
}
// add authorities
function addAuthorities(address[] calldata _authorities) public onlyOwner onlySetup {
require(authorities.length() + _authorities.length < 255, "Too many authorities");
for (uint256 i = 0; i < _authorities.length; i++){
require(_authorities[i] != address(0), "Zero address");
require(authorities.add(_authorities[i]), "Authority already added");
emit SetAuthority(_authorities[i], true);
}
}
// remove authorities
function removeAuthorities(address[] calldata _authorities) external onlyOwner {
for (uint256 i = 0; i < _authorities.length; i++){
require(authorities.remove(_authorities[i]), "Authority does not exist");
emit SetAuthority(_authorities[i], false);
}
}
// set authority address that MUST sign claim request
function setRequiredAuthorities(address[] calldata _authorities, bool isActive)
external
onlyOwner
onlySetup
{
for (uint256 i = 0; i < _authorities.length; i++){
requiredAuthorities[_authorities[i]] = isActive;
emit SetRequiredAuthority(_authorities[i], isActive);
}
}
// get fee for specific token, if fee is not set, return global fee
function getBridgeFee(address token) public view returns (uint256 fee) {
fee = bridgeFee[token];
if (fee == 0) fee = bridgeFee[address(0)]; // return global fee
else if (fee == 100000) fee = 0; // if fee == 100000, it means 0 fee for specific token
}
// fee percent with 4 decimals (i.e. 1.5% = 15000) that will subtracted from deposited tokens. 0 - no fee. bridgeFee[address(0)] - global fee
function setBridgeFee(address token, uint256 fee) external onlyOwner {
require(fee <= 100000, "Too high fee"); // fee must be less than 10% (99999 max). If fee == 100000, it will set 0 fee for specific token
bridgeFee[token] = fee;
emit SetBridgeFee(token, fee);
}
// set fee receiver address
function setFeeTo(address newFeeTo) external onlyOwner onlySetup {
require(newFeeTo != address(0), "Zero address");
address previousFeeTo = feeTo;
feeTo = newFeeTo;
emit SetFeeTo(previousFeeTo, newFeeTo);
}
// set threshold - minimum number of signatures required to approve swap
// minRequiredAuthorities - minimum number of trusted authorities required to sign transaction
function setThreshold(uint256 _threshold, uint256 _minRequiredAuthorities) external onlyOwner onlySetup {
require(
_threshold != 0 && _threshold <= authorities.length() && _minRequiredAuthorities <= _threshold,
"Wrong threshold"
);
minRequiredAuthorities = _minRequiredAuthorities;
threshold = _threshold;
emit SetThreshold(_threshold, _minRequiredAuthorities);
}
// set contractCaller address
function setContractCaller(address newContractCaller)
external
onlyOwner
onlySetup
{
contractCaller = newContractCaller;
emit SetContractCaller(newContractCaller);
}
// set foreign supported chain (exclude native chain)
function setSupportedChain(uint256[] calldata _chainID, bool _isSupported)
public
onlyOwner
{
for (uint256 i = 0; i < _chainID.length; i++){
isSupported[_chainID[i]] = _isSupported;
emit SetSupportedChain(_chainID[i], _isSupported);
}
}
function disableSetupMode() external onlyOwner {
setupMode = 0;
emit SetupMode(0);
}
function enableSetupMode() external onlyOwner {
setupMode = block.timestamp + 1 days;
emit SetupMode(setupMode);
}
function rescueERC20(address token, address to) external onlyOwner {
uint256 value = IERC20TokenCloned(token).balanceOf(address(this)) -
tokenDeposits[token];
token.safeTransfer(to, value);
emit RescuedERC20(token, to, value);
}
// return Token structure for selected original token address and chainID
function getToken(address originalToken, uint256 originalChainID)
external
view
returns (Token memory)
{
return
addedTokens[
keccak256(abi.encodePacked(originalToken, originalChainID))
];
}
// return Token structure for native token address (token from native chain)
function getToken(address nativeToken)
external
view
returns (Token memory)
{
bytes32 key = nativeToToken[nativeToken];
return addedTokens[key];
}
// return list of added tokens
function getTokenList() external view returns (TokenDetails[] memory) {
uint len = tokenList.length();
TokenDetails[] memory tokens = new TokenDetails[](len);
for (uint i = 0; i < len; i++){
address token = tokenList.at(i);
//bytes32 key = nativeToToken[token];
tokens[i] = TokenDetails(
token,
IERC20TokenCloned(token).decimals(),
IERC20TokenCloned(token).name(),
IERC20TokenCloned(token).symbol()
);
}
return tokens;
}
// add new token to the bridge
function addToken(address token) external {
require(uint256(nativeToToken[token]) == 0, "Token already added");
string memory name = IERC20TokenCloned(token).name();
string memory symbol = IERC20TokenCloned(token).symbol();
uint256 decimals = IERC20TokenCloned(token).decimals();
bytes32 key = keccak256(abi.encodePacked(token, block.chainid));
addedTokens[key].token = token;
addedTokens[key].chainID = block.chainid;
addedTokens[key].wrappedToken = address(0);
nativeToToken[token] = key;
tokenList.add(token);
emit AddToken(token, block.chainid, decimals, name, symbol);
}
// add wrapped token
function addWrappedToken(
address token, // original token address
uint256 chainID, // original token chain ID
uint256 decimals, // original token decimals
string calldata name, // original token name
string calldata symbol, // original token symbol
bytes[] memory sig // authority signatures
) external {
require(isSupported[chainID] && chainID != block.chainid, "Source chain not supported");
bytes32 key = keccak256(abi.encodePacked(token, chainID));
require(addedTokens[key].token == address(0), "Token already added");
bytes32 messageHash = keccak256(
abi.encodePacked(token, chainID, decimals, name, symbol)
);
checkSignatures(address(0), messageHash, sig);
string memory _name = string(abi.encodePacked("Wrapped ", name));
string memory _symbol = string(abi.encodePacked("W", symbol));
address wrappedToken = Clones.cloneDeterministic(
tokenImplementation,
bytes32(uint256(uint160(token)))
);
IERC20TokenCloned(wrappedToken).initialize(
_name,
_symbol,
uint8(decimals)
);
addedTokens[key].token = token;
addedTokens[key].chainID = chainID;
addedTokens[key].wrappedToken = wrappedToken;
nativeToToken[wrappedToken] = key;
tokenList.add(wrappedToken);
emit CreatePair(wrappedToken, token, chainID); //wrappedToken - wrapped token contract address
}
// set MUST authority for specific token
function setTokenMustAuthority(
address token, // original token address
uint256 chainID, // original token chain ID
address authority // address of MUST authority for this token, address(0) if don't need specific authority
) external onlyOwner {
bytes32 key = keccak256(abi.encodePacked(token, chainID));
require(addedTokens[key].token != address(0), "token not exist");
require(addedTokens[key].authority != address(0), "change authority not allowed");
require(authority != address(0));
addedTokens[key].authority = authority;
emit SetTokenAuthority(token, chainID, authority);
}
// Move tokens through the bridge and call the contract with 'data' parameters on the destination chain
function bridgeToContract(
address receiver, // address of token receiver on destination chain
address token, // token that user send (if token address < 32, then send native coin)
uint256 value, // tokens value
uint256 toChainId, // destination chain Id where will be claimed tokens
address toContract, // this contract will be called on destination chain
bytes memory data // this data will be passed to contract call (ABI encoded parameters)
) external payable notFrozen {
require(receiver != address(0), "Incorrect receiver address");
(address originalToken, uint256 originalChainID, uint256 valueWithoutFee) = _deposit(
token,
value,
toChainId
);
emit BridgeToContract(
originalToken,
originalChainID,
token,
receiver,
valueWithoutFee,
toChainId,
toContract,
data
);
}
// Claim tokens from the bridge and call the contract with 'data' parameters
function claimToContract(
address originalToken, // original token
uint256 originalChainID, // original chain ID
bytes32 txId, // deposit transaction hash on fromChain
address to, // receiver address
uint256 value, // value of tokens
uint256 fromChainId, // chain ID where user deposited
address toContract, // this contract will be called on destination chain
bytes memory data, // this data will be passed to contract call (ABI encoded parameters)
bytes[] memory sig // authority signatures
) external notFrozen {
bytes32 key = validate(originalToken, originalChainID, txId, fromChainId);
// Check signature
{
address must = addedTokens[key].authority;
bytes32 messageHash = keccak256(
abi.encodePacked(
originalToken,
originalChainID,
to,
value,
txId,
fromChainId,
block.chainid,
address(this),
toContract,
data
)
);
checkSignatures(must, messageHash, sig);
}
{
address token = addedTokens[key].wrappedToken;
// Call toContract
if (isContract(toContract) && toContract != address(this)) {
if (token == address(0) && originalToken == NATIVE_COINS) {
token = originalToken;
IContractCaller(contractCaller).callContract{value: value}(
to,
token,
value,
toContract,
data
);
} else {
if (token != address(0)) {
IERC20TokenCloned(token).mint(contractCaller, value);
} else {
token = originalToken;
tokenDeposits[token] -= value;
token.safeTransfer(contractCaller, value);
}
IContractCaller(contractCaller).callContract(
to,
token,
value,
toContract,
data
);
}
} else {
// if not contract
if (token != address(0)) {
IERC20TokenCloned(token).mint(to, value);
} else {
token = originalToken;
if (token == NATIVE_COINS) {
to.safeTransferETH(value);
} else {
tokenDeposits[token] -= value;
token.safeTransfer(to, value);
}
}
}
emit ClaimToContract(
originalToken,
originalChainID,
token,
to,
value,
txId,
fromChainId,
toContract
);
}
}
function depositTokens(
address receiver, // address of token receiver on destination chain
address token, // token that user send (if token address < 32, then send native coin)
uint256 value, // tokens value
uint256 toChainId // destination chain Id where will be claimed tokens
) external payable notFrozen {
require(receiver != address(0), "Incorrect receiver address");
(address originalToken, uint256 originalChainID, uint256 valueWithoutFee) = _deposit(
token,
value,
toChainId
);
emit Deposit(
originalToken,
originalChainID,
token,
receiver,
valueWithoutFee,
toChainId
);
}
function _deposit(
address token, // token that user send (if token is address(1), then send native coin)
uint256 value, // tokens value
uint256 toChainId // destination chain Id where will be claimed tokens
) internal returns (address originalToken, uint256 originalChainID, uint256 valueWithoutFee) {
require(isSupported[toChainId] && toChainId != block.chainid, "Destination chain not supported");
uint256 fee = getBridgeFee(token); // fee in percent with 4 decimals
if (fee !=0) {
fee = value * fee / 1000000; // fee amount
valueWithoutFee = value - fee;
if (fee != 0) {
if (token == NATIVE_COINS) {
feeTo.safeTransferETH(fee);
} else {
token.safeTransferFrom(msg.sender, feeTo, fee);
}
emit Fee(msg.sender, token, fee);
}
} else {
valueWithoutFee = value;
}
bytes32 key = nativeToToken[token];
require(uint256(key) != 0, "Token wasn't added");
originalToken = addedTokens[key].token;
originalChainID = addedTokens[key].chainID;
if (token == NATIVE_COINS) {
require(value <= msg.value, "Wrong value");
} else {
if (addedTokens[key].wrappedToken == token) {
IERC20TokenCloned(token).burnFrom(msg.sender, valueWithoutFee);
} else {
tokenDeposits[token] += valueWithoutFee;
token.safeTransferFrom(msg.sender, address(this), valueWithoutFee);
}
}
}
// claim
function claim(
address originalToken, // original token
uint256 originalChainID, // original chain ID
bytes32 txId, // deposit transaction hash on fromChain
address to, // user address
uint256 value, // value of tokens
uint256 fromChainId, // chain ID where user deposited
bytes[] memory sig // authority signatures
) external notFrozen {
bytes32 key = validate(originalToken, originalChainID, txId, fromChainId);
{
address must = addedTokens[key].authority;
bytes32 messageHash = keccak256(
abi.encodePacked(
originalToken,
originalChainID,
to,
value,
txId,
fromChainId,
block.chainid,
address(this)
)
);
checkSignatures(must, messageHash, sig);
}
address token = addedTokens[key].wrappedToken;
if (token != address(0)) {
IERC20TokenCloned(token).mint(to, value);
} else {
token = originalToken;
if (token == NATIVE_COINS) {
to.safeTransferETH(value);
} else {
tokenDeposits[token] -= value;
token.safeTransfer(to, value);
}
}
emit Claim(
originalToken,
originalChainID,
token,
to,
value,
txId,
fromChainId
);
}
// validate tx and token for claim request
function validate(
address originalToken, // original token
uint256 originalChainID, // original chain ID
bytes32 txId, // deposit transaction hash on fromChain
uint256 fromChainId // chain ID where user deposited
) internal returns (bytes32 key) {
require(isSupported[fromChainId], "Source chain not supported");
require(
!isTxProcessed[fromChainId][txId],
"Transaction already processed"
);
key = keccak256(abi.encodePacked(originalToken, originalChainID));
require(addedTokens[key].token != address(0), "token not exist");
isTxProcessed[fromChainId][txId] = true;
}
// Signature methods
function checkSignatures(
address must,
bytes32 messageHash,
bytes[] memory sig
) internal view {
messageHash = prefixed(messageHash);
uint256 required;
uint256 uniqSig;
uint256 set; // maximum number of authorities is 255
for (uint256 i = 0; i < sig.length; i++) {
address authority = recoverSigner(messageHash, sig[i]);
uint256 index = authorities.indexOf(authority);
uint256 mask = 1 << index;
if (index != 0 && (set & mask) == 0) {
set |= mask;
uniqSig++;
if (requiredAuthorities[authority]) required++;
}
if (authority == must) must = address(0); // must authority for specific token may not be approved by other authorities
}
require(threshold <= uniqSig, "Require more signatures");
require(
must == address(0) && required >= minRequiredAuthorities,
"The required authorities didn't sign"
);
}
function splitSignature(bytes memory sig)
internal
pure
returns (
uint8 v,
bytes32 r,
bytes32 s
)
{
require(sig.length == 65);
assembly {
// first 32 bytes, after the length prefix
r := mload(add(sig, 32))
// second 32 bytes
s := mload(add(sig, 64))
// final byte (first byte of the next 32 bytes)
v := byte(0, mload(add(sig, 96)))
}
}
function recoverSigner(bytes32 message, bytes memory sig)
internal
pure
returns (address)
{
uint8 v;
bytes32 r;
bytes32 s;
(v, r, s) = splitSignature(sig);
return ecrecover(message, v, r, s);
}
// Builds a prefixed hash to mimic the behavior of eth_sign.
function prefixed(bytes32 hash) internal pure returns (bytes32) {
return
keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)
);
}
function isContract(address account) internal view returns (bool) {
// This method relies in extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly {
size := extcodesize(account)
}
return size > 0;
}
}
Compiler Settings
{"outputSelection":{"*":{"*":["abi","metadata","devdoc","userdoc","storageLayout","evm.legacyAssembly","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","evm.gasEstimates","evm.assembly"],"":["ast"]}},"optimizer":{"runs":200,"enabled":true},"libraries":{}}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[]},{"type":"event","name":"AddToken","inputs":[{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"uint256","name":"chainID","internalType":"uint256","indexed":false},{"type":"uint256","name":"decimals","internalType":"uint256","indexed":false},{"type":"string","name":"name","internalType":"string","indexed":false},{"type":"string","name":"symbol","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"BridgeToContract","inputs":[{"type":"address","name":"originalToken","internalType":"address","indexed":true},{"type":"uint256","name":"originalChainID","internalType":"uint256","indexed":false},{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"address","name":"receiver","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"uint256","name":"toChainId","internalType":"uint256","indexed":false},{"type":"address","name":"toContract","internalType":"address","indexed":false},{"type":"bytes","name":"data","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"Claim","inputs":[{"type":"address","name":"originalToken","internalType":"address","indexed":true},{"type":"uint256","name":"originalChainID","internalType":"uint256","indexed":false},{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"bytes32","name":"txId","internalType":"bytes32","indexed":false},{"type":"uint256","name":"fromChainId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ClaimToContract","inputs":[{"type":"address","name":"originalToken","internalType":"address","indexed":true},{"type":"uint256","name":"originalChainID","internalType":"uint256","indexed":false},{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"bytes32","name":"txId","internalType":"bytes32","indexed":false},{"type":"uint256","name":"fromChainId","internalType":"uint256","indexed":false},{"type":"address","name":"toContract","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"CreatePair","inputs":[{"type":"address","name":"toToken","internalType":"address","indexed":false},{"type":"address","name":"fromToken","internalType":"address","indexed":false},{"type":"uint256","name":"fromChainId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Deposit","inputs":[{"type":"address","name":"originalToken","internalType":"address","indexed":true},{"type":"uint256","name":"originalChainID","internalType":"uint256","indexed":false},{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"address","name":"receiver","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"uint256","name":"toChainId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Fee","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"fee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Frozen","inputs":[{"type":"bool","name":"status","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RescuedERC20","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"address","name":"to","internalType":"address","indexed":false},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetAuthority","inputs":[{"type":"address","name":"authority","internalType":"address","indexed":false},{"type":"bool","name":"isEnable","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"SetBridgeFee","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"fee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetContractCaller","inputs":[{"type":"address","name":"newContractCaller","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"SetFeeTo","inputs":[{"type":"address","name":"previousFeeTo","internalType":"address","indexed":false},{"type":"address","name":"newFeeTo","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"SetFreezer","inputs":[{"type":"address","name":"freezer","internalType":"address","indexed":false},{"type":"bool","name":"isActive","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"SetRequiredAuthority","inputs":[{"type":"address","name":"authority","internalType":"address","indexed":false},{"type":"bool","name":"isEnable","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"SetSupportedChain","inputs":[{"type":"uint256","name":"chainID","internalType":"uint256","indexed":false},{"type":"bool","name":"isSupported","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"SetThreshold","inputs":[{"type":"uint256","name":"threshold","internalType":"uint256","indexed":false},{"type":"uint256","name":"minRequiredAuthorities","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetTokenAuthority","inputs":[{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"uint256","name":"chainId","internalType":"uint256","indexed":false},{"type":"address","name":"authority","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"SetupMode","inputs":[{"type":"uint256","name":"time","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"UpgradeRequest","inputs":[{"type":"address","name":"newContract","internalType":"address","indexed":false},{"type":"uint256","name":"validFrom","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addAuthorities","inputs":[{"type":"address[]","name":"_authorities","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addToken","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addWrappedToken","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"chainID","internalType":"uint256"},{"type":"uint256","name":"decimals","internalType":"uint256"},{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"symbol","internalType":"string"},{"type":"bytes[]","name":"sig","internalType":"bytes[]"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"bridgeToContract","inputs":[{"type":"address","name":"receiver","internalType":"address"},{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"toChainId","internalType":"uint256"},{"type":"address","name":"toContract","internalType":"address"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"changeFounder","inputs":[{"type":"address","name":"newFounders","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claim","inputs":[{"type":"address","name":"originalToken","internalType":"address"},{"type":"uint256","name":"originalChainID","internalType":"uint256"},{"type":"bytes32","name":"txId","internalType":"bytes32"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"fromChainId","internalType":"uint256"},{"type":"bytes[]","name":"sig","internalType":"bytes[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimToContract","inputs":[{"type":"address","name":"originalToken","internalType":"address"},{"type":"uint256","name":"originalChainID","internalType":"uint256"},{"type":"bytes32","name":"txId","internalType":"bytes32"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"fromChainId","internalType":"uint256"},{"type":"address","name":"toContract","internalType":"address"},{"type":"bytes","name":"data","internalType":"bytes"},{"type":"bytes[]","name":"sig","internalType":"bytes[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"contractCaller","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"depositTokens","inputs":[{"type":"address","name":"receiver","internalType":"address"},{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"toChainId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"disableSetupMode","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"enableSetupMode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"feeTo","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"founders","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"freeze","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"frozen","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getAuthorities","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getAuthoritiesNumber","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"fee","internalType":"uint256"}],"name":"getBridgeFee","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct BridgeV2.Token","components":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"chainID","internalType":"uint256"},{"type":"address","name":"wrappedToken","internalType":"address"},{"type":"address","name":"authority","internalType":"address"}]}],"name":"getToken","inputs":[{"type":"address","name":"originalToken","internalType":"address"},{"type":"uint256","name":"originalChainID","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct BridgeV2.Token","components":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"chainID","internalType":"uint256"},{"type":"address","name":"wrappedToken","internalType":"address"},{"type":"address","name":"authority","internalType":"address"}]}],"name":"getToken","inputs":[{"type":"address","name":"nativeToken","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct BridgeV2.TokenDetails[]","components":[{"type":"address","name":"token","internalType":"address"},{"type":"uint8","name":"decimals","internalType":"uint8"},{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"symbol","internalType":"string"}]}],"name":"getTokenList","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"newOwner","internalType":"address"},{"type":"address","name":"newFounders","internalType":"address"},{"type":"address","name":"_feeTo","internalType":"address"},{"type":"address","name":"_tokenImplementation","internalType":"address"},{"type":"uint256","name":"_threshold","internalType":"uint256"},{"type":"address[]","name":"_authorities","internalType":"address[]"},{"type":"uint256[]","name":"_chainID","internalType":"uint256[]"},{"type":"string","name":"_nativeCoin","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isFreezer","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isSupported","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isTxProcessed","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minRequiredAuthorities","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeAuthorities","inputs":[{"type":"address[]","name":"_authorities","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"requestUpgrade","inputs":[{"type":"address","name":"newContract","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"requiredAuthorities","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"rescueERC20","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"address","name":"to","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBridgeFee","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"fee","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setContractCaller","inputs":[{"type":"address","name":"newContractCaller","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFeeTo","inputs":[{"type":"address","name":"newFeeTo","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFreezer","inputs":[{"type":"address","name":"freezer","internalType":"address"},{"type":"bool","name":"isActive","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRequiredAuthorities","inputs":[{"type":"address[]","name":"_authorities","internalType":"address[]"},{"type":"bool","name":"isActive","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setSupportedChain","inputs":[{"type":"uint256[]","name":"_chainID","internalType":"uint256[]"},{"type":"bool","name":"_isSupported","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setThreshold","inputs":[{"type":"uint256","name":"_threshold","internalType":"uint256"},{"type":"uint256","name":"_minRequiredAuthorities","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setTokenMustAuthority","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"chainID","internalType":"uint256"},{"type":"address","name":"authority","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"setupMode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"threshold","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"tokenDeposits","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"tokenImplementation","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unfreeze","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"newContract","internalType":"address"},{"type":"uint64","name":"validFrom","internalType":"uint64"}],"name":"upgradeData","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"newContract","internalType":"address"}],"name":"upgradeTo","inputs":[]}]
Contract Creation Code
0x608060405234801561001057600080fd5b50600080546001600160a01b0319166001179055615695806100336000396000f3fe6080604052600436106102885760003560e01c8063648a58961161015a578063c21b4865116100c1578063e8eccb661161007a578063e8eccb6614610876578063f2fde38b14610896578063f391b573146108b6578063f46901ed146108e6578063fa08767114610906578063fab9fa531461095f57600080fd5b8063c21b486514610797578063d04567f3146107b9578063d48bfca7146107ce578063df42fd36146107ee578063e4d7a86314610829578063e6074da71461084957600080fd5b80638da5cb5b116101135780638da5cb5b146106e45780638f7157011461070257806393c32e0614610717578063a0fd9ec814610737578063a85c33cd14610757578063b9c362091461077757600080fd5b8063648a58961461060f5780636a28f0001461062f5780636b9f97ef146106445780636c65fd6a146106645780636d331f1d146106945780638d60cded146106b457600080fd5b80633cb3e9dc116101fe5780635417b02c116101b75780635417b02c146104e057806354cf428a1461050057806359770438146105205780635d799f87146105ba5780635e14e319146105da57806362a5af3b146105fa57600080fd5b80633cb3e9dc1461040d578063411b007e1461042357806342cde4e81461044357806343d7cce61461045957806344ddcb60146104ba578063487cda0d146104cd57600080fd5b8063273cbaa011610250578063273cbaa014610356578063278fa3e9146103785780632a94a9c8146103985780632ca0814b146103b85780632f3a3d5d146103d85780633af84ac4146103f857600080fd5b8063017e7e581461028d578063054f7d9c146102ca57806313bf8126146102fb57806316a27ecd1461031f5780631c9499e814610334575b600080fd5b34801561029957600080fd5b506007546102ad906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102d657600080fd5b506007546102eb90600160a01b900460ff1681565b60405190151581526020016102c1565b34801561030757600080fd5b50610311600b5481565b6040519081526020016102c1565b34801561032b57600080fd5b506102ad61097f565b34801561034057600080fd5b5061035461034f366004613f13565b610a17565b005b34801561036257600080fd5b5061036b610c48565b6040516102c19190613fe7565b34801561038457600080fd5b50610354610393366004614091565b610e72565b3480156103a457600080fd5b506103546103b33660046140cd565b611018565b3480156103c457600080fd5b506103546103d336600461413a565b6110d4565b3480156103e457600080fd5b506006546102ad906001600160a01b031681565b34801561040457600080fd5b506103116112ed565b34801561041957600080fd5b5061031160135481565b34801561042f57600080fd5b50600d546102ad906001600160a01b031681565b34801561044f57600080fd5b5061031160055481565b34801561046557600080fd5b5061047961047436600461417b565b6112fd565b6040516102c1919081516001600160a01b03908116825260208084015190830152604080840151821690830152606092830151169181019190915260800190565b6103546104c83660046141a5565b6113a3565b6103546104db366004614225565b61148e565b3480156104ec57600080fd5b506103116104fb3660046140cd565b611597565b34801561050c57600080fd5b50600e546102ad906001600160a01b031681565b34801561052c57600080fd5b5061047961053b3660046140cd565b60408051608080820183526000808352602080840182905283850182905260609384018290526001600160a01b03958616825260108152848220548252600f8152908490208451928301855280548616835260018101549183019190915260028101548516938201939093526003909201549092169181019190915290565b3480156105c657600080fd5b506103546105d5366004614267565b6115fb565b3480156105e657600080fd5b506103546105f53660046142ab565b61170e565b34801561060657600080fd5b506103546117c9565b34801561061b57600080fd5b5061035461062a36600461417b565b61185d565b34801561063b57600080fd5b50610354611929565b34801561065057600080fd5b5061035461065f3660046140cd565b6119d3565b34801561067057600080fd5b506102eb61067f3660046140cd565b600a6020526000908152604090205460ff1681565b3480156106a057600080fd5b506103546106af366004614323565b611abd565b3480156106c057600080fd5b506102eb6106cf36600461440f565b60116020526000908152604090205460ff1681565b3480156106f057600080fd5b506000546001600160a01b03166102ad565b34801561070e57600080fd5b50610354611e35565b34801561072357600080fd5b506103546107323660046140cd565b611eb0565b34801561074357600080fd5b50610354610752366004614428565b611fbc565b34801561076357600080fd5b5061035461077236600461447e565b612104565b34801561078357600080fd5b50610354610792366004614534565b612423565b3480156107a357600080fd5b506107ac612524565b6040516102c19190614556565b3480156107c557600080fd5b50610354612589565b3480156107da57600080fd5b506103546107e93660046140cd565b6125f9565b3480156107fa57600080fd5b506102eb610809366004614534565b600860209081526000928352604080842090915290825290205460ff1681565b34801561083557600080fd5b506103546108443660046145a3565b612861565b34801561085557600080fd5b506103116108643660046140cd565b60096020526000908152604090205481565b34801561088257600080fd5b5061035461089136600461413a565b612c38565b3480156108a257600080fd5b506103546108b13660046140cd565b612d7a565b3480156108c257600080fd5b506102eb6108d13660046140cd565b60126020526000908152604090205460ff1681565b3480156108f257600080fd5b506103546109013660046140cd565b612eb5565b34801561091257600080fd5b50600c54610938906001600160a01b03811690600160a01b90046001600160401b031682565b604080516001600160a01b0390931683526001600160401b039091166020830152016102c1565b34801561096b57600080fd5b5061035461097a366004614428565b612f9b565b60408051808201909152600c546001600160a01b0381168252600160a01b90046001600160401b03166020820181905260009190421180156109ca575080516001600160a01b031615155b610a115760405162461bcd60e51b8152602060048201526013602482015272155c19dc985919481b9bdd08185b1b1bddd959606a1b60448201526064015b60405180910390fd5b51919050565b600754600160a01b900460ff1615610a415760405162461bcd60e51b8152600401610a089061465f565b6000610a4f88888886613090565b6000818152600f60209081526040918290206003015482516bffffffffffffffffffffffff1960608e811b821683860152603483018e90528b811b82166054840152606883018b9052608883018d905260a883018a90524660c884015230901b1660e8820152835180820360dc01815260fc909101909352825192909101919091209192506001600160a01b031690610ae9828286613205565b50506000818152600f60205260409020600201546001600160a01b03168015610b73576040516340c10f1960e01b81526001600160a01b038781166004830152602482018790528216906340c10f1990604401600060405180830381600087803b158015610b5657600080fd5b505af1158015610b6a573d6000803e3d6000fd5b50505050610be1565b50876000196001600160a01b03821601610b9f57610b9a6001600160a01b03871686613408565b610be1565b6001600160a01b03811660009081526009602052604081208054879290610bc790849061469f565b90915550610be190506001600160a01b03821687876134d1565b6040805189815260208101879052908101889052606081018590526001600160a01b0380881691838216918c16907f11d59cd9a05f00f00dae480666f9155193ed03ea6f17496757f3adcc07c2670d906080015b60405180910390a4505050505050505050565b60606000610c5560035490565b90506000816001600160401b03811115610c7157610c71613db2565b604051908082528060200260200182016040528015610cc557816020015b6040805160808101825260008082526020820152606091810182905281810191909152815260200190600190039081610c8f5790505b50905060005b82811015610e6b576000610ce06003836135e5565b90506040518060800160405280826001600160a01b03168152602001826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5e91906146b2565b60ff168152602001826001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015610da4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610dcc91908101906146d5565b8152602001826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610e0f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e3791908101906146d5565b815250838381518110610e4c57610e4c61474b565b6020026020010181905250508080610e6390614761565b915050610ccb565b5092915050565b33610e856000546001600160a01b031690565b6001600160a01b031614610eab5760405162461bcd60e51b8152600401610a089061477a565b60008383604051602001610ec09291906147af565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b0316610f2f5760405162461bcd60e51b815260206004820152600f60248201526e1d1bdad95b881b9bdd08195e1a5cdd608a1b6044820152606401610a08565b6000818152600f60205260409020600301546001600160a01b0316610f965760405162461bcd60e51b815260206004820152601c60248201527f6368616e676520617574686f72697479206e6f7420616c6c6f776564000000006044820152606401610a08565b6001600160a01b038216610fa957600080fd5b6000818152600f602090815260409182902060030180546001600160a01b0319166001600160a01b038681169182179092558351878152928301528616917fee5ad7c073e09e589f00215f80efe0e7c6d5b9c4d19f5b85660a348b28ae867f910160405180910390a250505050565b3361102b6000546001600160a01b031690565b6001600160a01b0316146110515760405162461bcd60e51b8152600401610a089061477a565b600b54801580159061106257504281105b61107e5760405162461bcd60e51b8152600401610a08906147d1565b600e80546001600160a01b0319166001600160a01b0384169081179091556040519081527f850b65e0a4a0af8155b0d56212b309166a3618bcd7ba7c1e83f09f3e721f294c906020015b60405180910390a15050565b336110e76000546001600160a01b031690565b6001600160a01b03161461110d5760405162461bcd60e51b8152600401610a089061477a565b600b54801580159061111e57504281105b61113a5760405162461bcd60e51b8152600401610a08906147d1565b60ff8261114660015490565b61115091906147fc565b106111945760405162461bcd60e51b8152602060048201526014602482015273546f6f206d616e7920617574686f72697469657360601b6044820152606401610a08565b60005b828110156112e75760008484838181106111b3576111b361474b565b90506020020160208101906111c891906140cd565b6001600160a01b0316036111ee5760405162461bcd60e51b8152600401610a089061480f565b6112208484838181106112035761120361474b565b905060200201602081019061121891906140cd565b600190613674565b61126c5760405162461bcd60e51b815260206004820152601760248201527f417574686f7269747920616c72656164792061646465640000000000000000006044820152606401610a08565b7f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c36199384848381811061129f5761129f61474b565b90506020020160208101906112b491906140cd565b604080516001600160a01b039092168252600160208301520160405180910390a1806112df81614761565b915050611197565b50505050565b60006112f860015490565b905090565b604080516080810182526000808252602082018190529181018290526060810191909152600f600084846040516020016113389291906147af565b60408051601f198184030181529181528151602092830120835282820193909352908201600020825160808101845281546001600160a01b03908116825260018301549382019390935260028201548316938101939093526003015416606082015290505b92915050565b600754600160a01b900460ff16156113cd5760405162461bcd60e51b8152600401610a089061465f565b6001600160a01b0386166114235760405162461bcd60e51b815260206004820152601a60248201527f496e636f727265637420726563656976657220616464726573730000000000006044820152606401610a08565b60008060006114338888886136e6565b925092509250886001600160a01b0316886001600160a01b0316846001600160a01b03167feaa11317bb61110cf1035a22a7b6b4c716b909b47954d51ee13de1627fdf0f5085858b8b8b604051610c35959493929190614835565b600754600160a01b900460ff16156114b85760405162461bcd60e51b8152600401610a089061465f565b6001600160a01b03841661150e5760405162461bcd60e51b815260206004820152601a60248201527f496e636f727265637420726563656976657220616464726573730000000000006044820152606401610a08565b600080600061151e8686866136e6565b925092509250866001600160a01b0316866001600160a01b0316846001600160a01b03167fc9e84ed7aa56cf1771d0373f4b6380ccc9c7cdae154f287abf95c48f72e7f0cf858589604051611586939291909283526020830191909152604082015260600190565b60405180910390a450505050505050565b6001600160a01b038116600090815260146020526040812054908190036115e85750506000805260146020527f4f26c3876aa9f4b92579780beea1161a61f87ebf1ec6ee865b299e447ecba99c5490565b80620186a0036115f6575060005b919050565b3361160e6000546001600160a01b031690565b6001600160a01b0316146116345760405162461bcd60e51b8152600401610a089061477a565b6001600160a01b0382166000818152600960205260408082205490516370a0823160e01b8152306004820152919290916370a0823190602401602060405180830381865afa15801561168a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ae9190614873565b6116b8919061469f565b90506116ce6001600160a01b03841683836134d1565b7f2c5650189f92c7058626efc371b51fe7e71f37dacb696bc7cad0b1320931974a8383836040516117019392919061488c565b60405180910390a1505050565b336117216000546001600160a01b031690565b6001600160a01b0316146117475760405162461bcd60e51b8152600401610a089061477a565b6001600160a01b03821661176d5760405162461bcd60e51b8152600401610a089061480f565b6001600160a01b0382166000818152600a6020908152604091829020805460ff19168515159081179091558251938452908301527feabe320fe7911eab2e5125ac393caa5937659b712f0c3ac43316c61d4bc0880191016110c8565b6000546001600160a01b03163314806117f057503360009081526002602052604090205415155b8061180a5750336000908152600a602052604090205460ff165b61181357600080fd5b6007805460ff60a01b1916600160a01b179055604051600181527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e906020015b60405180910390a1565b336118706000546001600160a01b031690565b6001600160a01b0316146118965760405162461bcd60e51b8152600401610a089061477a565b620186a08111156118d85760405162461bcd60e51b815260206004820152600c60248201526b546f6f20686967682066656560a01b6044820152606401610a08565b6001600160a01b038216600081815260146020908152604091829020849055815192835282018390527fa065abcf8156e439379371f7924f05c22b16f14de6a1448c5bcbdc525b46dd8591016110c8565b3361193c6000546001600160a01b031690565b6001600160a01b0316146119625760405162461bcd60e51b8152600401610a089061477a565b600b54801580159061197357504281105b61198f5760405162461bcd60e51b8152600401610a08906147d1565b6007805460ff60a01b19169055604051600081527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e9060200160405180910390a150565b336119e66000546001600160a01b031690565b6001600160a01b031614611a0c5760405162461bcd60e51b8152600401610a089061477a565b6001600160a01b038116611a325760405162461bcd60e51b8152600401610a089061480f565b6000611a41426203f4806147fc565b6040805180820182526001600160a01b0385168082526001600160401b0384166020928301819052600c80546001600160e01b0319168317600160a01b90920291909117905582519081529081018390529192507fd990f8f4f90cd3307c50ab3d095cfb65516e999b7584aee60c0af83eb48118de91016110c8565b6000546001600160a01b0316158015611ade57506001600160a01b038b1615155b8015611af257506001600160a01b038a1615155b8015611b0657506001600160a01b03891615155b8015611b1a57506001600160a01b03881615155b8015611b2557508615155b611b2e57600080fd5b600080546001600160a01b03199081166001600160a01b038e81169182178455600d8054909316908e16179091556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a36001600b55611b9686866110d4565b611ba284846001612f9b565b600680546001600160a01b0319166001600160a01b038a16179055604051611bc990613d8e565b604051809103906000f080158015611be5573d6000803e3d6000fd5b50600e80546001600160a01b03199081166001600160a01b039384161790915560078054909116918b169182179055604080516000815260208101929092527f41d2755f00068d89c23ebc6f1e73ce119a6236a44517ca061f544a3f91c9bca4910160405180910390a16005879055600160138190556040805189815260208101929092527f9620b035d59a00def857ad7fb234d46b8245c9d1a79a0075e71587dd503a4961910160405180910390a160016012600088886000818110611cae57611cae61474b565b9050602002016020810190611cc391906140cd565b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055507f769e5b6d0e1e39e7afbc891ae32dbc689cd164ac034d66bc633096c559b7928786866000818110611d2e57611d2e61474b565b9050602002016020810190611d4391906140cd565b604080516001600160a01b039092168252600160208301520160405180910390a16000600146604051602001611d7a9291906147af565b60408051601f1981840301815282825280516020918201206000818152600f835292832080546001600160a01b03191660019081178255469181018290559384905260109092527f8c6065603763fec3f5742441d3833f3f43b982453612d76adb39a885e3006b5f819055935090917fef4ec9b3cfaa22dd32688bf4ac3c820e8b468ffb6452f61717fb9d845f3c526391611e1f9160129088908890829082906148d9565b60405180910390a2505050505050505050505050565b33611e486000546001600160a01b031690565b6001600160a01b031614611e6e5760405162461bcd60e51b8152600401610a089061477a565b611e7b42620151806147fc565b600b8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611853565b600d546001600160a01b03163314611f0a5760405162461bcd60e51b815260206004820152601a60248201527f63616c6c6572206973206e6f742074686520666f756e646572730000000000006044820152606401610a08565b6001600160a01b038116611f605760405162461bcd60e51b815260206004820152601d60248201527f6e6577206f776e657220697320746865207a65726f20616464726573730000006044820152606401610a08565b600d546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600d80546001600160a01b0319166001600160a01b0392909216919091179055565b33611fcf6000546001600160a01b031690565b6001600160a01b031614611ff55760405162461bcd60e51b8152600401610a089061477a565b600b54801580159061200657504281105b6120225760405162461bcd60e51b8152600401610a08906147d1565b60005b838110156120fd5782601260008787858181106120445761204461474b565b905060200201602081019061205991906140cd565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790557f769e5b6d0e1e39e7afbc891ae32dbc689cd164ac034d66bc633096c559b792878585838181106120b4576120b461474b565b90506020020160208101906120c991906140cd565b604080516001600160a01b03909216825285151560208301520160405180910390a1806120f581614761565b915050612025565b5050505050565b60008781526011602052604090205460ff1680156121225750468714155b61216e5760405162461bcd60e51b815260206004820152601a60248201527f536f7572636520636861696e206e6f7420737570706f727465640000000000006044820152606401610a08565b600088886040516020016121839291906147af565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b0316156121f75760405162461bcd60e51b8152602060048201526013602482015272151bdad95b88185b1c9958591e481859191959606a1b6044820152606401610a08565b6000898989898989896040516020016122169796959493929190614919565b60405160208183030381529060405280519060200120905061223a60008285613205565b6000878760405160200161224f92919061496a565b60405160208183030381529060405290506000868660405160200161227592919061498e565b60408051601f198184030181529190526006549091506000906122a5906001600160a01b03908116908f166139da565b9050806001600160a01b0316631624f6c684848e6040518463ffffffff1660e01b81526004016122d7939291906149ab565b600060405180830381600087803b1580156122f157600080fd5b505af1158015612305573d6000803e3d6000fd5b505050508c600f600087815260200190815260200160002060000160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508b600f60008781526020019081526020016000206001018190555080600f600087815260200190815260200160002060020160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508460106000836001600160a01b03166001600160a01b03168152602001908152602001600020819055506123d881600361367490919063ffffffff16565b507f7cedf5820723679f9a981ba7249d0ab5c6ecdb2f98392ef5a29051153b9e5a7d818e8e60405161240c9392919061488c565b60405180910390a150505050505050505050505050565b336124366000546001600160a01b031690565b6001600160a01b03161461245c5760405162461bcd60e51b8152600401610a089061477a565b600b54801580159061246d57504281105b6124895760405162461bcd60e51b8152600401610a08906147d1565b821580159061249a57506001548311155b80156124a65750828211155b6124e45760405162461bcd60e51b815260206004820152600f60248201526e15dc9bdb99c81d1a1c995cda1bdb19608a1b6044820152606401610a08565b6013829055600583905560408051848152602081018490527f9620b035d59a00def857ad7fb234d46b8245c9d1a79a0075e71587dd503a49619101611701565b6060600160000180548060200260200160405190810160405280929190818152602001828054801561257f57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612561575b5050505050905090565b3361259c6000546001600160a01b031690565b6001600160a01b0316146125c25760405162461bcd60e51b8152600401610a089061477a565b6000600b8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611853565b6001600160a01b038116600090815260106020526040902054156126555760405162461bcd60e51b8152602060048201526013602482015272151bdad95b88185b1c9958591e481859191959606a1b6044820152606401610a08565b6000816001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015612695573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126bd91908101906146d5565b90506000826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156126ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261272791908101906146d5565b90506000836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612769573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061278d91906146b2565b60ff169050600084466040516020016127a79291906147af565b60408051601f1981840301815291815281516020928301206000818152600f845282812080546001600160a01b038b166001600160a01b0319918216811783554660018401556002909201805490911690558152601090935291208190559050612812600386613674565b50846001600160a01b03167fef4ec9b3cfaa22dd32688bf4ac3c820e8b468ffb6452f61717fb9d845f3c52634684878760405161285294939291906149e4565b60405180910390a25050505050565b600754600160a01b900460ff161561288b5760405162461bcd60e51b8152600401610a089061465f565b60006128998a8a8a88613090565b90506000600f600083815260200190815260200160002060030160009054906101000a90046001600160a01b0316905060008b8b8a8a8d8b46308d8d6040516020016128ee9a99989796959493929190614a15565b604051602081830303815290604052805190602001209050612911828286613205565b50506000818152600f60205260409020600201546001600160a01b0316843b1515801561294757506001600160a01b0385163014155b15612b16576001600160a01b03811615801561296c57506001600160a01b038b166001145b156129e35750600e54604051631490ba2d60e31b81528b916001600160a01b03169063a485d1689089906129ac908c90869084908c908c90600401614a96565b6000604051808303818588803b1580156129c557600080fd5b505af11580156129d9573d6000803e3d6000fd5b5050505050612bc8565b6001600160a01b03811615612a5d57600e546040516340c10f1960e01b81526001600160a01b03918216600482015260248101899052908216906340c10f1990604401600060405180830381600087803b158015612a4057600080fd5b505af1158015612a54573d6000803e3d6000fd5b50505050612aa7565b506001600160a01b038a16600090815260096020526040812080548c92899291612a8890849061469f565b9091555050600e54612aa7906001600160a01b038381169116896134d1565b600e54604051631490ba2d60e31b81526001600160a01b039091169063a485d16890612adf908b9085908c908b908b90600401614a96565b600060405180830381600087803b158015612af957600080fd5b505af1158015612b0d573d6000803e3d6000fd5b50505050612bc8565b6001600160a01b03811615612b5a576040516340c10f1960e01b81526001600160a01b038981166004830152602482018990528216906340c10f1990604401612adf565b50896000196001600160a01b03821601612b8657612b816001600160a01b03891688613408565b612bc8565b6001600160a01b03811660009081526009602052604081208054899290612bae90849061469f565b90915550612bc890506001600160a01b03821689896134d1565b604080518b8152602081018990529081018a9052606081018790526001600160a01b038681166080830152808a1691838216918e16907f3d5595f71187e446858be0c0fa22a3dd315023362b3b056c5eada14baecfc1019060a00160405180910390a45050505050505050505050565b33612c4b6000546001600160a01b031690565b6001600160a01b031614612c715760405162461bcd60e51b8152600401610a089061477a565b60005b81811015612d7557612cae838383818110612c9157612c9161474b565b9050602002016020810190612ca691906140cd565b600190613a7a565b612cfa5760405162461bcd60e51b815260206004820152601860248201527f417574686f7269747920646f6573206e6f7420657869737400000000000000006044820152606401610a08565b7f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c361993838383818110612d2d57612d2d61474b565b9050602002016020810190612d4291906140cd565b604080516001600160a01b039092168252600060208301520160405180910390a180612d6d81614761565b915050612c74565b505050565b600d546001600160a01b0316331480612d9d57506000546001600160a01b031633145b612df55760405162461bcd60e51b815260206004820152602360248201527f4f776e61626c653a2063616c6c6572206973206e6f742074686520666f756e6460448201526265727360e81b6064820152608401610a08565b6001600160a01b038116612e5a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a08565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b33612ec86000546001600160a01b031690565b6001600160a01b031614612eee5760405162461bcd60e51b8152600401610a089061477a565b600b548015801590612eff57504281105b612f1b5760405162461bcd60e51b8152600401610a08906147d1565b6001600160a01b038216612f415760405162461bcd60e51b8152600401610a089061480f565b600780546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527f41d2755f00068d89c23ebc6f1e73ce119a6236a44517ca061f544a3f91c9bca49101611701565b33612fae6000546001600160a01b031690565b6001600160a01b031614612fd45760405162461bcd60e51b8152600401610a089061477a565b60005b828110156112e7578160116000868685818110612ff657612ff661474b565b90506020020135815260200190815260200160002060006101000a81548160ff0219169083151502179055507f96fb1460e35cd6722dbde21ee5de56c0c1e73920214010e33b2591763744fd8b8484838181106130555761305561474b565b90506020020135836040516130769291909182521515602082015260400190565b60405180910390a18061308881614761565b915050612fd7565b60008181526011602052604081205460ff166130ee5760405162461bcd60e51b815260206004820152601a60248201527f536f7572636520636861696e206e6f7420737570706f727465640000000000006044820152606401610a08565b600082815260086020908152604080832086845290915290205460ff16156131585760405162461bcd60e51b815260206004820152601d60248201527f5472616e73616374696f6e20616c72656164792070726f6365737365640000006044820152606401610a08565b848460405160200161316b9291906147af565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b03166131da5760405162461bcd60e51b815260206004820152600f60248201526e1d1bdad95b881b9bdd08195e1a5cdd608a1b6044820152606401610a08565b6000918252600860209081526040808420948452939052919020805460ff1916600117905592915050565b61325c826040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b915060008080805b845181101561333c576000613292878784815181106132855761328561474b565b6020026020010151613bbc565b6001600160a01b0381166000908152600260205260409020549091506001811b81158015906132c15750848116155b156133085793841793856132d481614761565b6001600160a01b03851660009081526012602052604090205490975060ff16159050613308578661330481614761565b9750505b896001600160a01b0316836001600160a01b03160361332657600099505b505050808061333490614761565b915050613264565b5081600554111561338f5760405162461bcd60e51b815260206004820152601760248201527f52657175697265206d6f7265207369676e6174757265730000000000000000006044820152606401610a08565b6001600160a01b0386161580156133a857506013548310155b6134005760405162461bcd60e51b8152602060048201526024808201527f54686520726571756972656420617574686f726974696573206469646e27742060448201526339b4b3b760e11b6064820152608401610a08565b505050505050565b604080516000808252602082019092526001600160a01b0384169083906040516134329190614ad1565b60006040518083038185875af1925050503d806000811461346f576040519150601f19603f3d011682016040523d82523d6000602084013e613474565b606091505b5050905080612d755760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610a08565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b179052915160009283929087169161352d9190614ad1565b6000604051808303816000865af19150503d806000811461356a576040519150601f19603f3d011682016040523d82523d6000602084013e61356f565b606091505b50915091508180156135995750805115806135995750808060200190518101906135999190614aed565b6120fd5760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610a08565b815460009082106136435760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604482015261647360f01b6064820152608401610a08565b8260000182815481106136585761365861474b565b6000918252602090912001546001600160a01b03169392505050565b6001600160a01b03811660009081526001830160205260408120546136de57508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b0386169081179091558554908252828601909352604090209190915561139d565b50600061139d565b6000818152601160205260408120548190819060ff1680156137085750468414155b6137545760405162461bcd60e51b815260206004820152601f60248201527f44657374696e6174696f6e20636861696e206e6f7420737570706f72746564006044820152606401610a08565b600061375f87611597565b9050801561381d57620f42406137758288614b0a565b61377f9190614b21565b905061378b818761469f565b91508015613818576000196001600160a01b038816016137c0576007546137bb906001600160a01b031682613408565b6137dc565b6007546137dc906001600160a01b038981169133911684613c3b565b7f6ded982279c8387ad8a63e73385031a3807c1862e633f06e09d11bcb6e282f6033888360405161380f9392919061488c565b60405180910390a15b613821565b8591505b6001600160a01b0387166000908152601060205260408120549081900361387f5760405162461bcd60e51b8152602060048201526012602482015271151bdad95b881dd85cdb89dd08185919195960721b6044820152606401610a08565b6000818152600f6020526040902080546001909101546001600160a01b03918216965094508816600019016138f157348711156138ec5760405162461bcd60e51b815260206004820152600b60248201526a57726f6e672076616c756560a81b6044820152606401610a08565b6139cf565b6000818152600f60205260409020600201546001600160a01b03808a1691160361398c5760405163079cc67960e41b8152336004820152602481018490526001600160a01b038916906379cc6790906044016020604051808303816000875af1158015613962573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139869190614aed565b506139cf565b6001600160a01b038816600090815260096020526040812080548592906139b49084906147fc565b909155506139cf90506001600160a01b038916333086613c3b565b505093509350939050565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b03811661139d5760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401610a08565b6001600160a01b03811660009081526001830160205260408120548015613bb2576000613aa860018361469f565b8554909150600090613abc9060019061469f565b90506000866000018281548110613ad557613ad561474b565b60009182526020909120015487546001600160a01b0390911691508190889085908110613b0457613b0461474b565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055613b388360016147fc565b6001600160a01b03821660009081526001890160205260409020558654879080613b6457613b64614b43565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038816825260018981019091526040822091909155945061139d9350505050565b600091505061139d565b600080600080613bcb85613d5f565b6040805160008152602081018083528b905260ff8516918101919091526060810183905260808101829052929550909350915060019060a0016020604051602081039080840390855afa158015613c26573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b600080856001600160a01b03166323b872dd868686604051602401613c629392919061488c565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051613c9b9190614ad1565b6000604051808303816000865af19150503d8060008114613cd8576040519150601f19603f3d011682016040523d82523d6000602084013e613cdd565b606091505b5091509150818015613d07575080511580613d07575080806020019051810190613d079190614aed565b6134005760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608401610a08565b60008060008351604114613d7257600080fd5b5050506020810151604082015160609092015160001a92909190565b610b0680614b5a83390190565b80356001600160a01b03811681146115f657600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715613df057613df0613db2565b604052919050565b60006001600160401b03821115613e1157613e11613db2565b50601f01601f191660200190565b600082601f830112613e3057600080fd5b8135613e43613e3e82613df8565b613dc8565b818152846020838601011115613e5857600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f830112613e8657600080fd5b813560206001600160401b0380831115613ea257613ea2613db2565b8260051b613eb1838201613dc8565b9384528581018301938381019088861115613ecb57600080fd5b84880192505b85831015613f0757823584811115613ee95760008081fd5b613ef78a87838c0101613e1f565b8352509184019190840190613ed1565b98975050505050505050565b600080600080600080600060e0888a031215613f2e57600080fd5b613f3788613d9b565b96506020880135955060408801359450613f5360608901613d9b565b93506080880135925060a0880135915060c08801356001600160401b03811115613f7c57600080fd5b613f888a828b01613e75565b91505092959891949750929550565b60005b83811015613fb2578181015183820152602001613f9a565b50506000910152565b60008151808452613fd3816020860160208601613f97565b601f01601f19169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561408357888303603f19018552815180516001600160a01b031684528781015160ff16888501528681015160808886018190529061405282870182613fbb565b9150506060808301519250858203818701525061406f8183613fbb565b96890196945050509086019060010161400e565b509098975050505050505050565b6000806000606084860312156140a657600080fd5b6140af84613d9b565b9250602084013591506140c460408501613d9b565b90509250925092565b6000602082840312156140df57600080fd5b6140e882613d9b565b9392505050565b60008083601f84011261410157600080fd5b5081356001600160401b0381111561411857600080fd5b6020830191508360208260051b850101111561413357600080fd5b9250929050565b6000806020838503121561414d57600080fd5b82356001600160401b0381111561416357600080fd5b61416f858286016140ef565b90969095509350505050565b6000806040838503121561418e57600080fd5b61419783613d9b565b946020939093013593505050565b60008060008060008060c087890312156141be57600080fd5b6141c787613d9b565b95506141d560208801613d9b565b945060408701359350606087013592506141f160808801613d9b565b915060a08701356001600160401b0381111561420c57600080fd5b61421889828a01613e1f565b9150509295509295509295565b6000806000806080858703121561423b57600080fd5b61424485613d9b565b935061425260208601613d9b565b93969395505050506040820135916060013590565b6000806040838503121561427a57600080fd5b61428383613d9b565b915061429160208401613d9b565b90509250929050565b80151581146142a857600080fd5b50565b600080604083850312156142be57600080fd5b6142c783613d9b565b915060208301356142d78161429a565b809150509250929050565b60008083601f8401126142f457600080fd5b5081356001600160401b0381111561430b57600080fd5b60208301915083602082850101111561413357600080fd5b60008060008060008060008060008060006101008c8e03121561434557600080fd5b61434e8c613d9b565b9a5061435c60208d01613d9b565b995061436a60408d01613d9b565b985061437860608d01613d9b565b975060808c013596506001600160401b038060a08e0135111561439a57600080fd5b6143aa8e60a08f01358f016140ef565b909750955060c08d01358110156143c057600080fd5b6143d08e60c08f01358f016140ef565b909550935060e08d01358110156143e657600080fd5b506143f78d60e08e01358e016142e2565b81935080925050509295989b509295989b9093969950565b60006020828403121561442157600080fd5b5035919050565b60008060006040848603121561443d57600080fd5b83356001600160401b0381111561445357600080fd5b61445f868287016140ef565b90945092505060208401356144738161429a565b809150509250925092565b60008060008060008060008060c0898b03121561449a57600080fd5b6144a389613d9b565b9750602089013596506040890135955060608901356001600160401b03808211156144cd57600080fd5b6144d98c838d016142e2565b909750955060808b01359150808211156144f257600080fd5b6144fe8c838d016142e2565b909550935060a08b013591508082111561451757600080fd5b506145248b828c01613e75565b9150509295985092959890939650565b6000806040838503121561454757600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b818110156145975783516001600160a01b031683529284019291840191600101614572565b50909695505050505050565b60008060008060008060008060006101208a8c0312156145c257600080fd5b6145cb8a613d9b565b985060208a0135975060408a013596506145e760608b01613d9b565b955060808a0135945060a08a0135935061460360c08b01613d9b565b925060e08a01356001600160401b038082111561461f57600080fd5b61462b8d838e01613e1f565b93506101008c013591508082111561464257600080fd5b5061464f8c828d01613e75565b9150509295985092959850929598565b60208082526010908201526f213934b233b29034b990333937bd32b760811b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b8181038181111561139d5761139d614689565b6000602082840312156146c457600080fd5b815160ff811681146140e857600080fd5b6000602082840312156146e757600080fd5b81516001600160401b038111156146fd57600080fd5b8201601f8101841361470e57600080fd5b805161471c613e3e82613df8565b81815285602083850101111561473157600080fd5b614742826020830160208601613f97565b95945050505050565b634e487b7160e01b600052603260045260246000fd5b60006001820161477357614773614689565b5060010190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60609290921b6bffffffffffffffffffffffff19168252601482015260340190565b6020808252601190820152704e6f7420696e207365747570206d6f646560781b604082015260600190565b8082018082111561139d5761139d614689565b6020808252600c908201526b5a65726f206164647265737360a01b604082015260600190565b85815284602082015283604082015260018060a01b038316606082015260a06080820152600061486860a0830184613fbb565b979650505050505050565b60006020828403121561488557600080fd5b5051919050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8681528560208201526080604082015260006148f96080830186886148b0565b828103606084015261490c8185876148b0565b9998505050505050505050565b6bffffffffffffffffffffffff198860601b16815286601482015285603482015283856054830137600084820160548101600081528486823750600093016054019283525090979650505050505050565b6702bb930b83832b2160c51b81528183600883013760009101600801908152919050565b605760f81b81528183600183013760009101600101908152919050565b6060815260006149be6060830186613fbb565b82810360208401526149d08186613fbb565b91505060ff83166040830152949350505050565b848152836020820152608060408201526000614a036080830185613fbb565b82810360608401526148688185613fbb565b60006bffffffffffffffffffffffff19808d60601b1683528b6014840152808b60601b1660348401528960488401528860688401528760888401528660a8840152808660601b1660c8840152808560601b1660dc840152508251614a808160f0850160208701613f97565b9190910160f0019b9a5050505050505050505050565b6001600160a01b0386811682528581166020830152604082018590528316606082015260a06080820181905260009061486890830184613fbb565b60008251614ae3818460208701613f97565b9190910192915050565b600060208284031215614aff57600080fd5b81516140e88161429a565b808202811582820484141761139d5761139d614689565b600082614b3e57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603160045260246000fdfe608060405234801561001057600080fd5b50600080546001600160a01b03191633179055610ad4806100326000396000f3fe60806040526004361061003f5760003560e01c80635431c94e146100445780638943ec0214610066578063a485d16814610086578063e78cea9214610099575b600080fd5b34801561005057600080fd5b5061006461005f36600461081e565b6100d5565b005b34801561007257600080fd5b50610064610081366004610857565b610294565b6100646100943660046108f6565b6102ea565b3480156100a557600080fd5b506000546100b9906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b60008054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061014a91906109e9565b6001600160a01b0316336001600160a01b03161461019c5760405162461bcd60e51b815260206004820152600a60248201526927b7363c9037bbb732b960b11b60448201526064015b60405180910390fd5b60006001600160a01b0383166101c65750476101c16001600160a01b03831682610510565b610244565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa15801561020a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061022e9190610a0d565b90506102446001600160a01b03841683836105de565b604080516001600160a01b038086168252841660208201529081018290527f0f51b71e5e9ee881072b57bf4022b60435e0000ad377b5c1434da39471002b559060600160405180910390a1505050565b6000546001600160a01b038581169116146102e45760405162461bcd60e51b815260206004820152601060248201526f4f6e6c792066726f6d2062726964676560801b6044820152606401610193565b50505050565b6000546001600160a01b031633146103325760405162461bcd60e51b815260206004820152600b60248201526a4f6e6c792062726964676560a81b6044820152606401610193565b6000196001600160a01b038516016103e95734925060006103538447610a26565b90506000836001600160a01b031685846040516103709190610a4d565b60006040518083038185875af1925050503d80600081146103ad576040519150601f19603f3d011682016040523d82523d6000602084013e6103b2565b606091505b5050905080156103c9576103c68247610a26565b94505b84156103e2576103e26001600160a01b03881686610510565b5050610509565b6103fd6001600160a01b03851683856106f2565b6000826001600160a01b03166000836040516104199190610a4d565b60006040518083038185875af1925050503d8060008114610456576040519150601f19603f3d011682016040523d82523d6000602084013e61045b565b606091505b5050905080156104d857604051636eb1769f60e11b81523060048201526001600160a01b03848116602483015286169063dd62ed3e90604401602060405180830381865afa1580156104b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d59190610a0d565b93505b8315610507576104f36001600160a01b0386168460006106f2565b6105076001600160a01b03861687866105de565b505b5050505050565b604080516000808252602082019092526001600160a01b03841690839060405161053a9190610a4d565b60006040518083038185875af1925050503d8060008114610577576040519150601f19603f3d011682016040523d82523d6000602084013e61057c565b606091505b50509050806105d95760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610193565b505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b179052915160009283929087169161063a9190610a4d565b6000604051808303816000865af19150503d8060008114610677576040519150601f19603f3d011682016040523d82523d6000602084013e61067c565b606091505b50915091508180156106a65750805115806106a65750808060200190518101906106a69190610a7c565b6105095760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610193565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b179052915160009283929087169161074e9190610a4d565b6000604051808303816000865af19150503d806000811461078b576040519150601f19603f3d011682016040523d82523d6000602084013e610790565b606091505b50915091508180156107ba5750805115806107ba5750808060200190518101906107ba9190610a7c565b6105095760405162461bcd60e51b815260206004820152601e60248201527f5472616e7366657248656c7065723a20415050524f56455f4641494c454400006044820152606401610193565b6001600160a01b038116811461081b57600080fd5b50565b6000806040838503121561083157600080fd5b823561083c81610806565b9150602083013561084c81610806565b809150509250929050565b6000806000806060858703121561086d57600080fd5b843561087881610806565b935060208501359250604085013567ffffffffffffffff8082111561089c57600080fd5b818701915087601f8301126108b057600080fd5b8135818111156108bf57600080fd5b8860208285010111156108d157600080fd5b95989497505060200194505050565b634e487b7160e01b600052604160045260246000fd5b600080600080600060a0868803121561090e57600080fd5b853561091981610806565b9450602086013561092981610806565b935060408601359250606086013561094081610806565b9150608086013567ffffffffffffffff8082111561095d57600080fd5b818801915088601f83011261097157600080fd5b813581811115610983576109836108e0565b604051601f8201601f19908116603f011681019083821181831017156109ab576109ab6108e0565b816040528281528b60208487010111156109c457600080fd5b8260208601602083013760006020848301015280955050505050509295509295909350565b6000602082840312156109fb57600080fd5b8151610a0681610806565b9392505050565b600060208284031215610a1f57600080fd5b5051919050565b81810381811115610a4757634e487b7160e01b600052601160045260246000fd5b92915050565b6000825160005b81811015610a6e5760208186018101518583015201610a54565b506000920191825250919050565b600060208284031215610a8e57600080fd5b81518015158114610a0657600080fdfea2646970667358221220561228070316a49611824b96e51515f8e328abbde3ec61cc36afa086e64476ec64736f6c63430008130033a26469706673582212204d8751db2047bdea7557be53599d8c76c894d6dc5ab7a9fc6215f7cf83b0508d64736f6c63430008130033
Deployed ByteCode
0x6080604052600436106102885760003560e01c8063648a58961161015a578063c21b4865116100c1578063e8eccb661161007a578063e8eccb6614610876578063f2fde38b14610896578063f391b573146108b6578063f46901ed146108e6578063fa08767114610906578063fab9fa531461095f57600080fd5b8063c21b486514610797578063d04567f3146107b9578063d48bfca7146107ce578063df42fd36146107ee578063e4d7a86314610829578063e6074da71461084957600080fd5b80638da5cb5b116101135780638da5cb5b146106e45780638f7157011461070257806393c32e0614610717578063a0fd9ec814610737578063a85c33cd14610757578063b9c362091461077757600080fd5b8063648a58961461060f5780636a28f0001461062f5780636b9f97ef146106445780636c65fd6a146106645780636d331f1d146106945780638d60cded146106b457600080fd5b80633cb3e9dc116101fe5780635417b02c116101b75780635417b02c146104e057806354cf428a1461050057806359770438146105205780635d799f87146105ba5780635e14e319146105da57806362a5af3b146105fa57600080fd5b80633cb3e9dc1461040d578063411b007e1461042357806342cde4e81461044357806343d7cce61461045957806344ddcb60146104ba578063487cda0d146104cd57600080fd5b8063273cbaa011610250578063273cbaa014610356578063278fa3e9146103785780632a94a9c8146103985780632ca0814b146103b85780632f3a3d5d146103d85780633af84ac4146103f857600080fd5b8063017e7e581461028d578063054f7d9c146102ca57806313bf8126146102fb57806316a27ecd1461031f5780631c9499e814610334575b600080fd5b34801561029957600080fd5b506007546102ad906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102d657600080fd5b506007546102eb90600160a01b900460ff1681565b60405190151581526020016102c1565b34801561030757600080fd5b50610311600b5481565b6040519081526020016102c1565b34801561032b57600080fd5b506102ad61097f565b34801561034057600080fd5b5061035461034f366004613f13565b610a17565b005b34801561036257600080fd5b5061036b610c48565b6040516102c19190613fe7565b34801561038457600080fd5b50610354610393366004614091565b610e72565b3480156103a457600080fd5b506103546103b33660046140cd565b611018565b3480156103c457600080fd5b506103546103d336600461413a565b6110d4565b3480156103e457600080fd5b506006546102ad906001600160a01b031681565b34801561040457600080fd5b506103116112ed565b34801561041957600080fd5b5061031160135481565b34801561042f57600080fd5b50600d546102ad906001600160a01b031681565b34801561044f57600080fd5b5061031160055481565b34801561046557600080fd5b5061047961047436600461417b565b6112fd565b6040516102c1919081516001600160a01b03908116825260208084015190830152604080840151821690830152606092830151169181019190915260800190565b6103546104c83660046141a5565b6113a3565b6103546104db366004614225565b61148e565b3480156104ec57600080fd5b506103116104fb3660046140cd565b611597565b34801561050c57600080fd5b50600e546102ad906001600160a01b031681565b34801561052c57600080fd5b5061047961053b3660046140cd565b60408051608080820183526000808352602080840182905283850182905260609384018290526001600160a01b03958616825260108152848220548252600f8152908490208451928301855280548616835260018101549183019190915260028101548516938201939093526003909201549092169181019190915290565b3480156105c657600080fd5b506103546105d5366004614267565b6115fb565b3480156105e657600080fd5b506103546105f53660046142ab565b61170e565b34801561060657600080fd5b506103546117c9565b34801561061b57600080fd5b5061035461062a36600461417b565b61185d565b34801561063b57600080fd5b50610354611929565b34801561065057600080fd5b5061035461065f3660046140cd565b6119d3565b34801561067057600080fd5b506102eb61067f3660046140cd565b600a6020526000908152604090205460ff1681565b3480156106a057600080fd5b506103546106af366004614323565b611abd565b3480156106c057600080fd5b506102eb6106cf36600461440f565b60116020526000908152604090205460ff1681565b3480156106f057600080fd5b506000546001600160a01b03166102ad565b34801561070e57600080fd5b50610354611e35565b34801561072357600080fd5b506103546107323660046140cd565b611eb0565b34801561074357600080fd5b50610354610752366004614428565b611fbc565b34801561076357600080fd5b5061035461077236600461447e565b612104565b34801561078357600080fd5b50610354610792366004614534565b612423565b3480156107a357600080fd5b506107ac612524565b6040516102c19190614556565b3480156107c557600080fd5b50610354612589565b3480156107da57600080fd5b506103546107e93660046140cd565b6125f9565b3480156107fa57600080fd5b506102eb610809366004614534565b600860209081526000928352604080842090915290825290205460ff1681565b34801561083557600080fd5b506103546108443660046145a3565b612861565b34801561085557600080fd5b506103116108643660046140cd565b60096020526000908152604090205481565b34801561088257600080fd5b5061035461089136600461413a565b612c38565b3480156108a257600080fd5b506103546108b13660046140cd565b612d7a565b3480156108c257600080fd5b506102eb6108d13660046140cd565b60126020526000908152604090205460ff1681565b3480156108f257600080fd5b506103546109013660046140cd565b612eb5565b34801561091257600080fd5b50600c54610938906001600160a01b03811690600160a01b90046001600160401b031682565b604080516001600160a01b0390931683526001600160401b039091166020830152016102c1565b34801561096b57600080fd5b5061035461097a366004614428565b612f9b565b60408051808201909152600c546001600160a01b0381168252600160a01b90046001600160401b03166020820181905260009190421180156109ca575080516001600160a01b031615155b610a115760405162461bcd60e51b8152602060048201526013602482015272155c19dc985919481b9bdd08185b1b1bddd959606a1b60448201526064015b60405180910390fd5b51919050565b600754600160a01b900460ff1615610a415760405162461bcd60e51b8152600401610a089061465f565b6000610a4f88888886613090565b6000818152600f60209081526040918290206003015482516bffffffffffffffffffffffff1960608e811b821683860152603483018e90528b811b82166054840152606883018b9052608883018d905260a883018a90524660c884015230901b1660e8820152835180820360dc01815260fc909101909352825192909101919091209192506001600160a01b031690610ae9828286613205565b50506000818152600f60205260409020600201546001600160a01b03168015610b73576040516340c10f1960e01b81526001600160a01b038781166004830152602482018790528216906340c10f1990604401600060405180830381600087803b158015610b5657600080fd5b505af1158015610b6a573d6000803e3d6000fd5b50505050610be1565b50876000196001600160a01b03821601610b9f57610b9a6001600160a01b03871686613408565b610be1565b6001600160a01b03811660009081526009602052604081208054879290610bc790849061469f565b90915550610be190506001600160a01b03821687876134d1565b6040805189815260208101879052908101889052606081018590526001600160a01b0380881691838216918c16907f11d59cd9a05f00f00dae480666f9155193ed03ea6f17496757f3adcc07c2670d906080015b60405180910390a4505050505050505050565b60606000610c5560035490565b90506000816001600160401b03811115610c7157610c71613db2565b604051908082528060200260200182016040528015610cc557816020015b6040805160808101825260008082526020820152606091810182905281810191909152815260200190600190039081610c8f5790505b50905060005b82811015610e6b576000610ce06003836135e5565b90506040518060800160405280826001600160a01b03168152602001826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5e91906146b2565b60ff168152602001826001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015610da4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610dcc91908101906146d5565b8152602001826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610e0f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e3791908101906146d5565b815250838381518110610e4c57610e4c61474b565b6020026020010181905250508080610e6390614761565b915050610ccb565b5092915050565b33610e856000546001600160a01b031690565b6001600160a01b031614610eab5760405162461bcd60e51b8152600401610a089061477a565b60008383604051602001610ec09291906147af565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b0316610f2f5760405162461bcd60e51b815260206004820152600f60248201526e1d1bdad95b881b9bdd08195e1a5cdd608a1b6044820152606401610a08565b6000818152600f60205260409020600301546001600160a01b0316610f965760405162461bcd60e51b815260206004820152601c60248201527f6368616e676520617574686f72697479206e6f7420616c6c6f776564000000006044820152606401610a08565b6001600160a01b038216610fa957600080fd5b6000818152600f602090815260409182902060030180546001600160a01b0319166001600160a01b038681169182179092558351878152928301528616917fee5ad7c073e09e589f00215f80efe0e7c6d5b9c4d19f5b85660a348b28ae867f910160405180910390a250505050565b3361102b6000546001600160a01b031690565b6001600160a01b0316146110515760405162461bcd60e51b8152600401610a089061477a565b600b54801580159061106257504281105b61107e5760405162461bcd60e51b8152600401610a08906147d1565b600e80546001600160a01b0319166001600160a01b0384169081179091556040519081527f850b65e0a4a0af8155b0d56212b309166a3618bcd7ba7c1e83f09f3e721f294c906020015b60405180910390a15050565b336110e76000546001600160a01b031690565b6001600160a01b03161461110d5760405162461bcd60e51b8152600401610a089061477a565b600b54801580159061111e57504281105b61113a5760405162461bcd60e51b8152600401610a08906147d1565b60ff8261114660015490565b61115091906147fc565b106111945760405162461bcd60e51b8152602060048201526014602482015273546f6f206d616e7920617574686f72697469657360601b6044820152606401610a08565b60005b828110156112e75760008484838181106111b3576111b361474b565b90506020020160208101906111c891906140cd565b6001600160a01b0316036111ee5760405162461bcd60e51b8152600401610a089061480f565b6112208484838181106112035761120361474b565b905060200201602081019061121891906140cd565b600190613674565b61126c5760405162461bcd60e51b815260206004820152601760248201527f417574686f7269747920616c72656164792061646465640000000000000000006044820152606401610a08565b7f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c36199384848381811061129f5761129f61474b565b90506020020160208101906112b491906140cd565b604080516001600160a01b039092168252600160208301520160405180910390a1806112df81614761565b915050611197565b50505050565b60006112f860015490565b905090565b604080516080810182526000808252602082018190529181018290526060810191909152600f600084846040516020016113389291906147af565b60408051601f198184030181529181528151602092830120835282820193909352908201600020825160808101845281546001600160a01b03908116825260018301549382019390935260028201548316938101939093526003015416606082015290505b92915050565b600754600160a01b900460ff16156113cd5760405162461bcd60e51b8152600401610a089061465f565b6001600160a01b0386166114235760405162461bcd60e51b815260206004820152601a60248201527f496e636f727265637420726563656976657220616464726573730000000000006044820152606401610a08565b60008060006114338888886136e6565b925092509250886001600160a01b0316886001600160a01b0316846001600160a01b03167feaa11317bb61110cf1035a22a7b6b4c716b909b47954d51ee13de1627fdf0f5085858b8b8b604051610c35959493929190614835565b600754600160a01b900460ff16156114b85760405162461bcd60e51b8152600401610a089061465f565b6001600160a01b03841661150e5760405162461bcd60e51b815260206004820152601a60248201527f496e636f727265637420726563656976657220616464726573730000000000006044820152606401610a08565b600080600061151e8686866136e6565b925092509250866001600160a01b0316866001600160a01b0316846001600160a01b03167fc9e84ed7aa56cf1771d0373f4b6380ccc9c7cdae154f287abf95c48f72e7f0cf858589604051611586939291909283526020830191909152604082015260600190565b60405180910390a450505050505050565b6001600160a01b038116600090815260146020526040812054908190036115e85750506000805260146020527f4f26c3876aa9f4b92579780beea1161a61f87ebf1ec6ee865b299e447ecba99c5490565b80620186a0036115f6575060005b919050565b3361160e6000546001600160a01b031690565b6001600160a01b0316146116345760405162461bcd60e51b8152600401610a089061477a565b6001600160a01b0382166000818152600960205260408082205490516370a0823160e01b8152306004820152919290916370a0823190602401602060405180830381865afa15801561168a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ae9190614873565b6116b8919061469f565b90506116ce6001600160a01b03841683836134d1565b7f2c5650189f92c7058626efc371b51fe7e71f37dacb696bc7cad0b1320931974a8383836040516117019392919061488c565b60405180910390a1505050565b336117216000546001600160a01b031690565b6001600160a01b0316146117475760405162461bcd60e51b8152600401610a089061477a565b6001600160a01b03821661176d5760405162461bcd60e51b8152600401610a089061480f565b6001600160a01b0382166000818152600a6020908152604091829020805460ff19168515159081179091558251938452908301527feabe320fe7911eab2e5125ac393caa5937659b712f0c3ac43316c61d4bc0880191016110c8565b6000546001600160a01b03163314806117f057503360009081526002602052604090205415155b8061180a5750336000908152600a602052604090205460ff165b61181357600080fd5b6007805460ff60a01b1916600160a01b179055604051600181527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e906020015b60405180910390a1565b336118706000546001600160a01b031690565b6001600160a01b0316146118965760405162461bcd60e51b8152600401610a089061477a565b620186a08111156118d85760405162461bcd60e51b815260206004820152600c60248201526b546f6f20686967682066656560a01b6044820152606401610a08565b6001600160a01b038216600081815260146020908152604091829020849055815192835282018390527fa065abcf8156e439379371f7924f05c22b16f14de6a1448c5bcbdc525b46dd8591016110c8565b3361193c6000546001600160a01b031690565b6001600160a01b0316146119625760405162461bcd60e51b8152600401610a089061477a565b600b54801580159061197357504281105b61198f5760405162461bcd60e51b8152600401610a08906147d1565b6007805460ff60a01b19169055604051600081527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e9060200160405180910390a150565b336119e66000546001600160a01b031690565b6001600160a01b031614611a0c5760405162461bcd60e51b8152600401610a089061477a565b6001600160a01b038116611a325760405162461bcd60e51b8152600401610a089061480f565b6000611a41426203f4806147fc565b6040805180820182526001600160a01b0385168082526001600160401b0384166020928301819052600c80546001600160e01b0319168317600160a01b90920291909117905582519081529081018390529192507fd990f8f4f90cd3307c50ab3d095cfb65516e999b7584aee60c0af83eb48118de91016110c8565b6000546001600160a01b0316158015611ade57506001600160a01b038b1615155b8015611af257506001600160a01b038a1615155b8015611b0657506001600160a01b03891615155b8015611b1a57506001600160a01b03881615155b8015611b2557508615155b611b2e57600080fd5b600080546001600160a01b03199081166001600160a01b038e81169182178455600d8054909316908e16179091556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a36001600b55611b9686866110d4565b611ba284846001612f9b565b600680546001600160a01b0319166001600160a01b038a16179055604051611bc990613d8e565b604051809103906000f080158015611be5573d6000803e3d6000fd5b50600e80546001600160a01b03199081166001600160a01b039384161790915560078054909116918b169182179055604080516000815260208101929092527f41d2755f00068d89c23ebc6f1e73ce119a6236a44517ca061f544a3f91c9bca4910160405180910390a16005879055600160138190556040805189815260208101929092527f9620b035d59a00def857ad7fb234d46b8245c9d1a79a0075e71587dd503a4961910160405180910390a160016012600088886000818110611cae57611cae61474b565b9050602002016020810190611cc391906140cd565b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055507f769e5b6d0e1e39e7afbc891ae32dbc689cd164ac034d66bc633096c559b7928786866000818110611d2e57611d2e61474b565b9050602002016020810190611d4391906140cd565b604080516001600160a01b039092168252600160208301520160405180910390a16000600146604051602001611d7a9291906147af565b60408051601f1981840301815282825280516020918201206000818152600f835292832080546001600160a01b03191660019081178255469181018290559384905260109092527f8c6065603763fec3f5742441d3833f3f43b982453612d76adb39a885e3006b5f819055935090917fef4ec9b3cfaa22dd32688bf4ac3c820e8b468ffb6452f61717fb9d845f3c526391611e1f9160129088908890829082906148d9565b60405180910390a2505050505050505050505050565b33611e486000546001600160a01b031690565b6001600160a01b031614611e6e5760405162461bcd60e51b8152600401610a089061477a565b611e7b42620151806147fc565b600b8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611853565b600d546001600160a01b03163314611f0a5760405162461bcd60e51b815260206004820152601a60248201527f63616c6c6572206973206e6f742074686520666f756e646572730000000000006044820152606401610a08565b6001600160a01b038116611f605760405162461bcd60e51b815260206004820152601d60248201527f6e6577206f776e657220697320746865207a65726f20616464726573730000006044820152606401610a08565b600d546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600d80546001600160a01b0319166001600160a01b0392909216919091179055565b33611fcf6000546001600160a01b031690565b6001600160a01b031614611ff55760405162461bcd60e51b8152600401610a089061477a565b600b54801580159061200657504281105b6120225760405162461bcd60e51b8152600401610a08906147d1565b60005b838110156120fd5782601260008787858181106120445761204461474b565b905060200201602081019061205991906140cd565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790557f769e5b6d0e1e39e7afbc891ae32dbc689cd164ac034d66bc633096c559b792878585838181106120b4576120b461474b565b90506020020160208101906120c991906140cd565b604080516001600160a01b03909216825285151560208301520160405180910390a1806120f581614761565b915050612025565b5050505050565b60008781526011602052604090205460ff1680156121225750468714155b61216e5760405162461bcd60e51b815260206004820152601a60248201527f536f7572636520636861696e206e6f7420737570706f727465640000000000006044820152606401610a08565b600088886040516020016121839291906147af565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b0316156121f75760405162461bcd60e51b8152602060048201526013602482015272151bdad95b88185b1c9958591e481859191959606a1b6044820152606401610a08565b6000898989898989896040516020016122169796959493929190614919565b60405160208183030381529060405280519060200120905061223a60008285613205565b6000878760405160200161224f92919061496a565b60405160208183030381529060405290506000868660405160200161227592919061498e565b60408051601f198184030181529190526006549091506000906122a5906001600160a01b03908116908f166139da565b9050806001600160a01b0316631624f6c684848e6040518463ffffffff1660e01b81526004016122d7939291906149ab565b600060405180830381600087803b1580156122f157600080fd5b505af1158015612305573d6000803e3d6000fd5b505050508c600f600087815260200190815260200160002060000160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508b600f60008781526020019081526020016000206001018190555080600f600087815260200190815260200160002060020160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508460106000836001600160a01b03166001600160a01b03168152602001908152602001600020819055506123d881600361367490919063ffffffff16565b507f7cedf5820723679f9a981ba7249d0ab5c6ecdb2f98392ef5a29051153b9e5a7d818e8e60405161240c9392919061488c565b60405180910390a150505050505050505050505050565b336124366000546001600160a01b031690565b6001600160a01b03161461245c5760405162461bcd60e51b8152600401610a089061477a565b600b54801580159061246d57504281105b6124895760405162461bcd60e51b8152600401610a08906147d1565b821580159061249a57506001548311155b80156124a65750828211155b6124e45760405162461bcd60e51b815260206004820152600f60248201526e15dc9bdb99c81d1a1c995cda1bdb19608a1b6044820152606401610a08565b6013829055600583905560408051848152602081018490527f9620b035d59a00def857ad7fb234d46b8245c9d1a79a0075e71587dd503a49619101611701565b6060600160000180548060200260200160405190810160405280929190818152602001828054801561257f57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612561575b5050505050905090565b3361259c6000546001600160a01b031690565b6001600160a01b0316146125c25760405162461bcd60e51b8152600401610a089061477a565b6000600b8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611853565b6001600160a01b038116600090815260106020526040902054156126555760405162461bcd60e51b8152602060048201526013602482015272151bdad95b88185b1c9958591e481859191959606a1b6044820152606401610a08565b6000816001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015612695573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126bd91908101906146d5565b90506000826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156126ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261272791908101906146d5565b90506000836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612769573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061278d91906146b2565b60ff169050600084466040516020016127a79291906147af565b60408051601f1981840301815291815281516020928301206000818152600f845282812080546001600160a01b038b166001600160a01b0319918216811783554660018401556002909201805490911690558152601090935291208190559050612812600386613674565b50846001600160a01b03167fef4ec9b3cfaa22dd32688bf4ac3c820e8b468ffb6452f61717fb9d845f3c52634684878760405161285294939291906149e4565b60405180910390a25050505050565b600754600160a01b900460ff161561288b5760405162461bcd60e51b8152600401610a089061465f565b60006128998a8a8a88613090565b90506000600f600083815260200190815260200160002060030160009054906101000a90046001600160a01b0316905060008b8b8a8a8d8b46308d8d6040516020016128ee9a99989796959493929190614a15565b604051602081830303815290604052805190602001209050612911828286613205565b50506000818152600f60205260409020600201546001600160a01b0316843b1515801561294757506001600160a01b0385163014155b15612b16576001600160a01b03811615801561296c57506001600160a01b038b166001145b156129e35750600e54604051631490ba2d60e31b81528b916001600160a01b03169063a485d1689089906129ac908c90869084908c908c90600401614a96565b6000604051808303818588803b1580156129c557600080fd5b505af11580156129d9573d6000803e3d6000fd5b5050505050612bc8565b6001600160a01b03811615612a5d57600e546040516340c10f1960e01b81526001600160a01b03918216600482015260248101899052908216906340c10f1990604401600060405180830381600087803b158015612a4057600080fd5b505af1158015612a54573d6000803e3d6000fd5b50505050612aa7565b506001600160a01b038a16600090815260096020526040812080548c92899291612a8890849061469f565b9091555050600e54612aa7906001600160a01b038381169116896134d1565b600e54604051631490ba2d60e31b81526001600160a01b039091169063a485d16890612adf908b9085908c908b908b90600401614a96565b600060405180830381600087803b158015612af957600080fd5b505af1158015612b0d573d6000803e3d6000fd5b50505050612bc8565b6001600160a01b03811615612b5a576040516340c10f1960e01b81526001600160a01b038981166004830152602482018990528216906340c10f1990604401612adf565b50896000196001600160a01b03821601612b8657612b816001600160a01b03891688613408565b612bc8565b6001600160a01b03811660009081526009602052604081208054899290612bae90849061469f565b90915550612bc890506001600160a01b03821689896134d1565b604080518b8152602081018990529081018a9052606081018790526001600160a01b038681166080830152808a1691838216918e16907f3d5595f71187e446858be0c0fa22a3dd315023362b3b056c5eada14baecfc1019060a00160405180910390a45050505050505050505050565b33612c4b6000546001600160a01b031690565b6001600160a01b031614612c715760405162461bcd60e51b8152600401610a089061477a565b60005b81811015612d7557612cae838383818110612c9157612c9161474b565b9050602002016020810190612ca691906140cd565b600190613a7a565b612cfa5760405162461bcd60e51b815260206004820152601860248201527f417574686f7269747920646f6573206e6f7420657869737400000000000000006044820152606401610a08565b7f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c361993838383818110612d2d57612d2d61474b565b9050602002016020810190612d4291906140cd565b604080516001600160a01b039092168252600060208301520160405180910390a180612d6d81614761565b915050612c74565b505050565b600d546001600160a01b0316331480612d9d57506000546001600160a01b031633145b612df55760405162461bcd60e51b815260206004820152602360248201527f4f776e61626c653a2063616c6c6572206973206e6f742074686520666f756e6460448201526265727360e81b6064820152608401610a08565b6001600160a01b038116612e5a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a08565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b33612ec86000546001600160a01b031690565b6001600160a01b031614612eee5760405162461bcd60e51b8152600401610a089061477a565b600b548015801590612eff57504281105b612f1b5760405162461bcd60e51b8152600401610a08906147d1565b6001600160a01b038216612f415760405162461bcd60e51b8152600401610a089061480f565b600780546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527f41d2755f00068d89c23ebc6f1e73ce119a6236a44517ca061f544a3f91c9bca49101611701565b33612fae6000546001600160a01b031690565b6001600160a01b031614612fd45760405162461bcd60e51b8152600401610a089061477a565b60005b828110156112e7578160116000868685818110612ff657612ff661474b565b90506020020135815260200190815260200160002060006101000a81548160ff0219169083151502179055507f96fb1460e35cd6722dbde21ee5de56c0c1e73920214010e33b2591763744fd8b8484838181106130555761305561474b565b90506020020135836040516130769291909182521515602082015260400190565b60405180910390a18061308881614761565b915050612fd7565b60008181526011602052604081205460ff166130ee5760405162461bcd60e51b815260206004820152601a60248201527f536f7572636520636861696e206e6f7420737570706f727465640000000000006044820152606401610a08565b600082815260086020908152604080832086845290915290205460ff16156131585760405162461bcd60e51b815260206004820152601d60248201527f5472616e73616374696f6e20616c72656164792070726f6365737365640000006044820152606401610a08565b848460405160200161316b9291906147af565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b03166131da5760405162461bcd60e51b815260206004820152600f60248201526e1d1bdad95b881b9bdd08195e1a5cdd608a1b6044820152606401610a08565b6000918252600860209081526040808420948452939052919020805460ff1916600117905592915050565b61325c826040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b915060008080805b845181101561333c576000613292878784815181106132855761328561474b565b6020026020010151613bbc565b6001600160a01b0381166000908152600260205260409020549091506001811b81158015906132c15750848116155b156133085793841793856132d481614761565b6001600160a01b03851660009081526012602052604090205490975060ff16159050613308578661330481614761565b9750505b896001600160a01b0316836001600160a01b03160361332657600099505b505050808061333490614761565b915050613264565b5081600554111561338f5760405162461bcd60e51b815260206004820152601760248201527f52657175697265206d6f7265207369676e6174757265730000000000000000006044820152606401610a08565b6001600160a01b0386161580156133a857506013548310155b6134005760405162461bcd60e51b8152602060048201526024808201527f54686520726571756972656420617574686f726974696573206469646e27742060448201526339b4b3b760e11b6064820152608401610a08565b505050505050565b604080516000808252602082019092526001600160a01b0384169083906040516134329190614ad1565b60006040518083038185875af1925050503d806000811461346f576040519150601f19603f3d011682016040523d82523d6000602084013e613474565b606091505b5050905080612d755760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610a08565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b179052915160009283929087169161352d9190614ad1565b6000604051808303816000865af19150503d806000811461356a576040519150601f19603f3d011682016040523d82523d6000602084013e61356f565b606091505b50915091508180156135995750805115806135995750808060200190518101906135999190614aed565b6120fd5760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610a08565b815460009082106136435760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604482015261647360f01b6064820152608401610a08565b8260000182815481106136585761365861474b565b6000918252602090912001546001600160a01b03169392505050565b6001600160a01b03811660009081526001830160205260408120546136de57508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b0386169081179091558554908252828601909352604090209190915561139d565b50600061139d565b6000818152601160205260408120548190819060ff1680156137085750468414155b6137545760405162461bcd60e51b815260206004820152601f60248201527f44657374696e6174696f6e20636861696e206e6f7420737570706f72746564006044820152606401610a08565b600061375f87611597565b9050801561381d57620f42406137758288614b0a565b61377f9190614b21565b905061378b818761469f565b91508015613818576000196001600160a01b038816016137c0576007546137bb906001600160a01b031682613408565b6137dc565b6007546137dc906001600160a01b038981169133911684613c3b565b7f6ded982279c8387ad8a63e73385031a3807c1862e633f06e09d11bcb6e282f6033888360405161380f9392919061488c565b60405180910390a15b613821565b8591505b6001600160a01b0387166000908152601060205260408120549081900361387f5760405162461bcd60e51b8152602060048201526012602482015271151bdad95b881dd85cdb89dd08185919195960721b6044820152606401610a08565b6000818152600f6020526040902080546001909101546001600160a01b03918216965094508816600019016138f157348711156138ec5760405162461bcd60e51b815260206004820152600b60248201526a57726f6e672076616c756560a81b6044820152606401610a08565b6139cf565b6000818152600f60205260409020600201546001600160a01b03808a1691160361398c5760405163079cc67960e41b8152336004820152602481018490526001600160a01b038916906379cc6790906044016020604051808303816000875af1158015613962573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139869190614aed565b506139cf565b6001600160a01b038816600090815260096020526040812080548592906139b49084906147fc565b909155506139cf90506001600160a01b038916333086613c3b565b505093509350939050565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b03811661139d5760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401610a08565b6001600160a01b03811660009081526001830160205260408120548015613bb2576000613aa860018361469f565b8554909150600090613abc9060019061469f565b90506000866000018281548110613ad557613ad561474b565b60009182526020909120015487546001600160a01b0390911691508190889085908110613b0457613b0461474b565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055613b388360016147fc565b6001600160a01b03821660009081526001890160205260409020558654879080613b6457613b64614b43565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038816825260018981019091526040822091909155945061139d9350505050565b600091505061139d565b600080600080613bcb85613d5f565b6040805160008152602081018083528b905260ff8516918101919091526060810183905260808101829052929550909350915060019060a0016020604051602081039080840390855afa158015613c26573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b600080856001600160a01b03166323b872dd868686604051602401613c629392919061488c565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051613c9b9190614ad1565b6000604051808303816000865af19150503d8060008114613cd8576040519150601f19603f3d011682016040523d82523d6000602084013e613cdd565b606091505b5091509150818015613d07575080511580613d07575080806020019051810190613d079190614aed565b6134005760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608401610a08565b60008060008351604114613d7257600080fd5b5050506020810151604082015160609092015160001a92909190565b610b0680614b5a83390190565b80356001600160a01b03811681146115f657600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715613df057613df0613db2565b604052919050565b60006001600160401b03821115613e1157613e11613db2565b50601f01601f191660200190565b600082601f830112613e3057600080fd5b8135613e43613e3e82613df8565b613dc8565b818152846020838601011115613e5857600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f830112613e8657600080fd5b813560206001600160401b0380831115613ea257613ea2613db2565b8260051b613eb1838201613dc8565b9384528581018301938381019088861115613ecb57600080fd5b84880192505b85831015613f0757823584811115613ee95760008081fd5b613ef78a87838c0101613e1f565b8352509184019190840190613ed1565b98975050505050505050565b600080600080600080600060e0888a031215613f2e57600080fd5b613f3788613d9b565b96506020880135955060408801359450613f5360608901613d9b565b93506080880135925060a0880135915060c08801356001600160401b03811115613f7c57600080fd5b613f888a828b01613e75565b91505092959891949750929550565b60005b83811015613fb2578181015183820152602001613f9a565b50506000910152565b60008151808452613fd3816020860160208601613f97565b601f01601f19169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561408357888303603f19018552815180516001600160a01b031684528781015160ff16888501528681015160808886018190529061405282870182613fbb565b9150506060808301519250858203818701525061406f8183613fbb565b96890196945050509086019060010161400e565b509098975050505050505050565b6000806000606084860312156140a657600080fd5b6140af84613d9b565b9250602084013591506140c460408501613d9b565b90509250925092565b6000602082840312156140df57600080fd5b6140e882613d9b565b9392505050565b60008083601f84011261410157600080fd5b5081356001600160401b0381111561411857600080fd5b6020830191508360208260051b850101111561413357600080fd5b9250929050565b6000806020838503121561414d57600080fd5b82356001600160401b0381111561416357600080fd5b61416f858286016140ef565b90969095509350505050565b6000806040838503121561418e57600080fd5b61419783613d9b565b946020939093013593505050565b60008060008060008060c087890312156141be57600080fd5b6141c787613d9b565b95506141d560208801613d9b565b945060408701359350606087013592506141f160808801613d9b565b915060a08701356001600160401b0381111561420c57600080fd5b61421889828a01613e1f565b9150509295509295509295565b6000806000806080858703121561423b57600080fd5b61424485613d9b565b935061425260208601613d9b565b93969395505050506040820135916060013590565b6000806040838503121561427a57600080fd5b61428383613d9b565b915061429160208401613d9b565b90509250929050565b80151581146142a857600080fd5b50565b600080604083850312156142be57600080fd5b6142c783613d9b565b915060208301356142d78161429a565b809150509250929050565b60008083601f8401126142f457600080fd5b5081356001600160401b0381111561430b57600080fd5b60208301915083602082850101111561413357600080fd5b60008060008060008060008060008060006101008c8e03121561434557600080fd5b61434e8c613d9b565b9a5061435c60208d01613d9b565b995061436a60408d01613d9b565b985061437860608d01613d9b565b975060808c013596506001600160401b038060a08e0135111561439a57600080fd5b6143aa8e60a08f01358f016140ef565b909750955060c08d01358110156143c057600080fd5b6143d08e60c08f01358f016140ef565b909550935060e08d01358110156143e657600080fd5b506143f78d60e08e01358e016142e2565b81935080925050509295989b509295989b9093969950565b60006020828403121561442157600080fd5b5035919050565b60008060006040848603121561443d57600080fd5b83356001600160401b0381111561445357600080fd5b61445f868287016140ef565b90945092505060208401356144738161429a565b809150509250925092565b60008060008060008060008060c0898b03121561449a57600080fd5b6144a389613d9b565b9750602089013596506040890135955060608901356001600160401b03808211156144cd57600080fd5b6144d98c838d016142e2565b909750955060808b01359150808211156144f257600080fd5b6144fe8c838d016142e2565b909550935060a08b013591508082111561451757600080fd5b506145248b828c01613e75565b9150509295985092959890939650565b6000806040838503121561454757600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b818110156145975783516001600160a01b031683529284019291840191600101614572565b50909695505050505050565b60008060008060008060008060006101208a8c0312156145c257600080fd5b6145cb8a613d9b565b985060208a0135975060408a013596506145e760608b01613d9b565b955060808a0135945060a08a0135935061460360c08b01613d9b565b925060e08a01356001600160401b038082111561461f57600080fd5b61462b8d838e01613e1f565b93506101008c013591508082111561464257600080fd5b5061464f8c828d01613e75565b9150509295985092959850929598565b60208082526010908201526f213934b233b29034b990333937bd32b760811b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b8181038181111561139d5761139d614689565b6000602082840312156146c457600080fd5b815160ff811681146140e857600080fd5b6000602082840312156146e757600080fd5b81516001600160401b038111156146fd57600080fd5b8201601f8101841361470e57600080fd5b805161471c613e3e82613df8565b81815285602083850101111561473157600080fd5b614742826020830160208601613f97565b95945050505050565b634e487b7160e01b600052603260045260246000fd5b60006001820161477357614773614689565b5060010190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60609290921b6bffffffffffffffffffffffff19168252601482015260340190565b6020808252601190820152704e6f7420696e207365747570206d6f646560781b604082015260600190565b8082018082111561139d5761139d614689565b6020808252600c908201526b5a65726f206164647265737360a01b604082015260600190565b85815284602082015283604082015260018060a01b038316606082015260a06080820152600061486860a0830184613fbb565b979650505050505050565b60006020828403121561488557600080fd5b5051919050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8681528560208201526080604082015260006148f96080830186886148b0565b828103606084015261490c8185876148b0565b9998505050505050505050565b6bffffffffffffffffffffffff198860601b16815286601482015285603482015283856054830137600084820160548101600081528486823750600093016054019283525090979650505050505050565b6702bb930b83832b2160c51b81528183600883013760009101600801908152919050565b605760f81b81528183600183013760009101600101908152919050565b6060815260006149be6060830186613fbb565b82810360208401526149d08186613fbb565b91505060ff83166040830152949350505050565b848152836020820152608060408201526000614a036080830185613fbb565b82810360608401526148688185613fbb565b60006bffffffffffffffffffffffff19808d60601b1683528b6014840152808b60601b1660348401528960488401528860688401528760888401528660a8840152808660601b1660c8840152808560601b1660dc840152508251614a808160f0850160208701613f97565b9190910160f0019b9a5050505050505050505050565b6001600160a01b0386811682528581166020830152604082018590528316606082015260a06080820181905260009061486890830184613fbb565b60008251614ae3818460208701613f97565b9190910192915050565b600060208284031215614aff57600080fd5b81516140e88161429a565b808202811582820484141761139d5761139d614689565b600082614b3e57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603160045260246000fdfe608060405234801561001057600080fd5b50600080546001600160a01b03191633179055610ad4806100326000396000f3fe60806040526004361061003f5760003560e01c80635431c94e146100445780638943ec0214610066578063a485d16814610086578063e78cea9214610099575b600080fd5b34801561005057600080fd5b5061006461005f36600461081e565b6100d5565b005b34801561007257600080fd5b50610064610081366004610857565b610294565b6100646100943660046108f6565b6102ea565b3480156100a557600080fd5b506000546100b9906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b60008054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061014a91906109e9565b6001600160a01b0316336001600160a01b03161461019c5760405162461bcd60e51b815260206004820152600a60248201526927b7363c9037bbb732b960b11b60448201526064015b60405180910390fd5b60006001600160a01b0383166101c65750476101c16001600160a01b03831682610510565b610244565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa15801561020a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061022e9190610a0d565b90506102446001600160a01b03841683836105de565b604080516001600160a01b038086168252841660208201529081018290527f0f51b71e5e9ee881072b57bf4022b60435e0000ad377b5c1434da39471002b559060600160405180910390a1505050565b6000546001600160a01b038581169116146102e45760405162461bcd60e51b815260206004820152601060248201526f4f6e6c792066726f6d2062726964676560801b6044820152606401610193565b50505050565b6000546001600160a01b031633146103325760405162461bcd60e51b815260206004820152600b60248201526a4f6e6c792062726964676560a81b6044820152606401610193565b6000196001600160a01b038516016103e95734925060006103538447610a26565b90506000836001600160a01b031685846040516103709190610a4d565b60006040518083038185875af1925050503d80600081146103ad576040519150601f19603f3d011682016040523d82523d6000602084013e6103b2565b606091505b5050905080156103c9576103c68247610a26565b94505b84156103e2576103e26001600160a01b03881686610510565b5050610509565b6103fd6001600160a01b03851683856106f2565b6000826001600160a01b03166000836040516104199190610a4d565b60006040518083038185875af1925050503d8060008114610456576040519150601f19603f3d011682016040523d82523d6000602084013e61045b565b606091505b5050905080156104d857604051636eb1769f60e11b81523060048201526001600160a01b03848116602483015286169063dd62ed3e90604401602060405180830381865afa1580156104b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d59190610a0d565b93505b8315610507576104f36001600160a01b0386168460006106f2565b6105076001600160a01b03861687866105de565b505b5050505050565b604080516000808252602082019092526001600160a01b03841690839060405161053a9190610a4d565b60006040518083038185875af1925050503d8060008114610577576040519150601f19603f3d011682016040523d82523d6000602084013e61057c565b606091505b50509050806105d95760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610193565b505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b179052915160009283929087169161063a9190610a4d565b6000604051808303816000865af19150503d8060008114610677576040519150601f19603f3d011682016040523d82523d6000602084013e61067c565b606091505b50915091508180156106a65750805115806106a65750808060200190518101906106a69190610a7c565b6105095760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610193565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b179052915160009283929087169161074e9190610a4d565b6000604051808303816000865af19150503d806000811461078b576040519150601f19603f3d011682016040523d82523d6000602084013e610790565b606091505b50915091508180156107ba5750805115806107ba5750808060200190518101906107ba9190610a7c565b6105095760405162461bcd60e51b815260206004820152601e60248201527f5472616e7366657248656c7065723a20415050524f56455f4641494c454400006044820152606401610193565b6001600160a01b038116811461081b57600080fd5b50565b6000806040838503121561083157600080fd5b823561083c81610806565b9150602083013561084c81610806565b809150509250929050565b6000806000806060858703121561086d57600080fd5b843561087881610806565b935060208501359250604085013567ffffffffffffffff8082111561089c57600080fd5b818701915087601f8301126108b057600080fd5b8135818111156108bf57600080fd5b8860208285010111156108d157600080fd5b95989497505060200194505050565b634e487b7160e01b600052604160045260246000fd5b600080600080600060a0868803121561090e57600080fd5b853561091981610806565b9450602086013561092981610806565b935060408601359250606086013561094081610806565b9150608086013567ffffffffffffffff8082111561095d57600080fd5b818801915088601f83011261097157600080fd5b813581811115610983576109836108e0565b604051601f8201601f19908116603f011681019083821181831017156109ab576109ab6108e0565b816040528281528b60208487010111156109c457600080fd5b8260208601602083013760006020848301015280955050505050509295509295909350565b6000602082840312156109fb57600080fd5b8151610a0681610806565b9392505050565b600060208284031215610a1f57600080fd5b5051919050565b81810381811115610a4757634e487b7160e01b600052601160045260246000fd5b92915050565b6000825160005b81811015610a6e5760208186018101518583015201610a54565b506000920191825250919050565b600060208284031215610a8e57600080fd5b81518015158114610a0657600080fdfea2646970667358221220561228070316a49611824b96e51515f8e328abbde3ec61cc36afa086e64476ec64736f6c63430008130033a26469706673582212204d8751db2047bdea7557be53599d8c76c894d6dc5ab7a9fc6215f7cf83b0508d64736f6c63430008130033