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-13T18:58:03.548901Z
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);
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
//address _contractCaller, // intermediate contract caller
uint256 _threshold, // minimum authorities required to approve bridge transaction
address[] calldata _authorities, // addresses of authorities. _authorities[0] is requiredAuthority
string calldata _nativeCoin // name of native coin (i.e. ETH, BNB, MATIC)
) external {
require(
newOwner != address(0) &&
newFounders != address(0) &&
_owner == address(0) &&
_feeTo != address(0)
); // run only once
_owner = newOwner;
founders = newFounders;
emit OwnershipTransferred(address(0), newOwner);
require(
_tokenImplementation != address(0),
"Wrong tokenImplementation"
);
require(
_threshold != 0,
"Wrong threshold"
);
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);
}
tokenImplementation = _tokenImplementation;
//contractCaller = _contractCaller;
contractCaller = address(new ContractCaller());
//emit SetContractCaller(_contractCaller);
feeTo = _feeTo;
emit SetFeeTo(address(0), _feeTo);
threshold = _threshold;
emit SetThreshold(_threshold);
requiredAuthorities[_authorities[0]] = true;
emit SetRequiredAuthority(_authorities[0], true);
minRequiredAuthorities = 1;
setupMode = 1; // allow setup after deployment
// 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) external 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 onlySetup {
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
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);
}
// set contractCaller address
function setContractCaller(address newContractCaller)
external
onlyOwner
onlySetup
{
contractCaller = newContractCaller;
emit SetContractCaller(newContractCaller);
}
// set supported chain
function setSupportedChain(uint256[] calldata _chainID, bool _isSupported)
external
onlyOwner
onlySetup
{
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(chainID != block.chainid, "Only foreign token");
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 {
require(
!isTxProcessed[fromChainId][txId],
"Transaction already processed"
);
bytes32 key = keccak256(
abi.encodePacked(originalToken, originalChainID)
);
require(addedTokens[key].token != address(0), "token not exist");
isTxProcessed[fromChainId][txId] = true;
// 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 {
require(
!isTxProcessed[fromChainId][txId],
"Transaction already processed"
);
bytes32 key = keccak256(
abi.encodePacked(originalToken, originalChainID)
);
require(addedTokens[key].token != address(0), "token not exist");
isTxProcessed[fromChainId][txId] = true;
{
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
);
}
// 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}],"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":"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
0x608060405234801561001057600080fd5b50600080546001600160a01b03191660011790556158ca806100336000396000f3fe6080604052600436106102885760003560e01c8063648a58961161015a578063d04567f3116100c1578063f2fde38b1161007a578063f2fde38b14610876578063f391b57314610896578063f46901ed146108c6578063fa087671146108e6578063fa220f621461093f578063fab9fa531461095f57600080fd5b8063d04567f314610799578063d48bfca7146107ae578063df42fd36146107ce578063e4d7a86314610809578063e6074da714610829578063e8eccb661461085657600080fd5b80638f715701116101135780638f715701146106e257806393c32e06146106f7578063a0fd9ec814610717578063a85c33cd14610737578063b9c3620914610757578063c21b48651461077757600080fd5b8063648a58961461060f5780636a28f0001461062f5780636b9f97ef146106445780636c65fd6a146106645780638d60cded146106945780638da5cb5b146106c457600080fd5b80633cb3e9dc116101fe5780635417b02c116101b75780635417b02c146104e057806354cf428a1461050057806359770438146105205780635d799f87146105ba5780635e14e319146105da57806362a5af3b146105fa57600080fd5b80633cb3e9dc1461040d578063411b007e1461042357806342cde4e81461044357806343d7cce61461045957806344ddcb60146104ba578063487cda0d146104cd57600080fd5b8063273cbaa011610250578063273cbaa014610356578063278fa3e9146103785780632a94a9c8146103985780632ca0814b146103b85780632f3a3d5d146103d85780633af84ac4146103f857600080fd5b8063017e7e581461028d578063054f7d9c146102ca57806313bf8126146102fb57806316a27ecd1461031f5780631c9499e814610334575b600080fd5b34801561029957600080fd5b506007546102ad906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102d657600080fd5b506007546102eb90600160a01b900460ff1681565b60405190151581526020016102c1565b34801561030757600080fd5b50610311600b5481565b6040519081526020016102c1565b34801561032b57600080fd5b506102ad61097f565b34801561034057600080fd5b5061035461034f36600461414e565b610a17565b005b34801561036257600080fd5b5061036b610d25565b6040516102c19190614222565b34801561038457600080fd5b506103546103933660046142cc565b610f4f565b3480156103a457600080fd5b506103546103b3366004614308565b6110d3565b3480156103c457600080fd5b506103546103d3366004614375565b61118f565b3480156103e457600080fd5b506006546102ad906001600160a01b031681565b34801561040457600080fd5b506103116113a2565b34801561041957600080fd5b5061031160135481565b34801561042f57600080fd5b50600d546102ad906001600160a01b031681565b34801561044f57600080fd5b5061031160055481565b34801561046557600080fd5b506104796104743660046143b6565b6113b2565b6040516102c1919081516001600160a01b03908116825260208084015190830152604080840151821690830152606092830151169181019190915260800190565b6103546104c83660046143e0565b611458565b6103546104db366004614460565b611543565b3480156104ec57600080fd5b506103116104fb366004614308565b61164c565b34801561050c57600080fd5b50600e546102ad906001600160a01b031681565b34801561052c57600080fd5b5061047961053b366004614308565b60408051608080820183526000808352602080840182905283850182905260609384018290526001600160a01b03958616825260108152848220548252600f8152908490208451928301855280548616835260018101549183019190915260028101548516938201939093526003909201549092169181019190915290565b3480156105c657600080fd5b506103546105d53660046144a2565b6116b0565b3480156105e657600080fd5b506103546105f53660046144e6565b6117c3565b34801561060657600080fd5b5061035461187e565b34801561061b57600080fd5b5061035461062a3660046143b6565b611912565b34801561063b57600080fd5b50610354611a0b565b34801561065057600080fd5b5061035461065f366004614308565b611ab5565b34801561067057600080fd5b506102eb61067f366004614308565b600a6020526000908152604090205460ff1681565b3480156106a057600080fd5b506102eb6106af36600461451d565b60116020526000908152604090205460ff1681565b3480156106d057600080fd5b506000546001600160a01b03166102ad565b3480156106ee57600080fd5b50610354611b90565b34801561070357600080fd5b50610354610712366004614308565b611c0b565b34801561072357600080fd5b50610354610732366004614536565b611d17565b34801561074357600080fd5b506103546107523660046145cd565b611e5f565b34801561076357600080fd5b50610354610772366004614683565b612158565b34801561078357600080fd5b5061078c612253565b6040516102c191906146a5565b3480156107a557600080fd5b506103546122b8565b3480156107ba57600080fd5b506103546107c9366004614308565b612328565b3480156107da57600080fd5b506102eb6107e9366004614683565b600860209081526000928352604080842090915290825290205460ff1681565b34801561081557600080fd5b506103546108243660046146f2565b612590565b34801561083557600080fd5b50610311610844366004614308565b60096020526000908152604090205481565b34801561086257600080fd5b50610354610871366004614375565b612a60565b34801561088257600080fd5b50610354610891366004614308565b612ba2565b3480156108a257600080fd5b506102eb6108b1366004614308565b60126020526000908152604090205460ff1681565b3480156108d257600080fd5b506103546108e1366004614308565b612cdd565b3480156108f257600080fd5b50600c54610918906001600160a01b03811690600160a01b90046001600160401b031682565b604080516001600160a01b0390931683526001600160401b039091166020830152016102c1565b34801561094b57600080fd5b5061035461095a3660046147ae565b612dc3565b34801561096b57600080fd5b5061035461097a366004614536565b61331e565b60408051808201909152600c546001600160a01b0381168252600160a01b90046001600160401b03166020820181905260009190421180156109ca575080516001600160a01b031615155b610a115760405162461bcd60e51b8152602060048201526013602482015272155c19dc985919481b9bdd08185b1b1bddd959606a1b60448201526064015b60405180910390fd5b51919050565b600754600160a01b900460ff1615610a415760405162461bcd60e51b8152600401610a089061486b565b600082815260086020908152604080832088845290915290205460ff1615610aab5760405162461bcd60e51b815260206004820152601d60248201527f5472616e73616374696f6e20616c72656164792070726f6365737365640000006044820152606401610a08565b60008787604051602001610ac0929190614895565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b0316610b0d5760405162461bcd60e51b8152600401610a08906148b7565b60008381526008602090815260408083208984528252808320805460ff19166001179055838352600f825280832060030154905160608c811b6bffffffffffffffffffffffff1990811694830194909452603482018c905289811b8416605483015260688201899052608882018b905260a882018890524660c883015230901b90921660e88301526001600160a01b0316919060fc01604051602081830303815290604052805190602001209050610bc6828286613440565b50506000818152600f60205260409020600201546001600160a01b03168015610c50576040516340c10f1960e01b81526001600160a01b038781166004830152602482018790528216906340c10f1990604401600060405180830381600087803b158015610c3357600080fd5b505af1158015610c47573d6000803e3d6000fd5b50505050610cbe565b50876000196001600160a01b03821601610c7c57610c776001600160a01b03871686613643565b610cbe565b6001600160a01b03811660009081526009602052604081208054879290610ca49084906148f6565b90915550610cbe90506001600160a01b038216878761370c565b6040805189815260208101879052908101889052606081018590526001600160a01b0380881691838216918c16907f11d59cd9a05f00f00dae480666f9155193ed03ea6f17496757f3adcc07c2670d906080015b60405180910390a4505050505050505050565b60606000610d3260035490565b90506000816001600160401b03811115610d4e57610d4e613fed565b604051908082528060200260200182016040528015610da257816020015b6040805160808101825260008082526020820152606091810182905281810191909152815260200190600190039081610d6c5790505b50905060005b82811015610f48576000610dbd600383613820565b90506040518060800160405280826001600160a01b03168152602001826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3b9190614909565b60ff168152602001826001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015610e81573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ea9919081019061492c565b8152602001826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610eec573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f14919081019061492c565b815250838381518110610f2957610f296149a2565b6020026020010181905250508080610f40906149b8565b915050610da8565b5092915050565b33610f626000546001600160a01b031690565b6001600160a01b031614610f885760405162461bcd60e51b8152600401610a08906149d1565b60008383604051602001610f9d929190614895565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b0316610fea5760405162461bcd60e51b8152600401610a08906148b7565b6000818152600f60205260409020600301546001600160a01b03166110515760405162461bcd60e51b815260206004820152601c60248201527f6368616e676520617574686f72697479206e6f7420616c6c6f776564000000006044820152606401610a08565b6001600160a01b03821661106457600080fd5b6000818152600f602090815260409182902060030180546001600160a01b0319166001600160a01b038681169182179092558351878152928301528616917fee5ad7c073e09e589f00215f80efe0e7c6d5b9c4d19f5b85660a348b28ae867f910160405180910390a250505050565b336110e66000546001600160a01b031690565b6001600160a01b03161461110c5760405162461bcd60e51b8152600401610a08906149d1565b600b54801580159061111d57504281105b6111395760405162461bcd60e51b8152600401610a0890614a06565b600e80546001600160a01b0319166001600160a01b0384169081179091556040519081527f850b65e0a4a0af8155b0d56212b309166a3618bcd7ba7c1e83f09f3e721f294c906020015b60405180910390a15050565b336111a26000546001600160a01b031690565b6001600160a01b0316146111c85760405162461bcd60e51b8152600401610a08906149d1565b600b5480158015906111d957504281105b6111f55760405162461bcd60e51b8152600401610a0890614a06565b60ff8261120160015490565b61120b9190614a31565b1061124f5760405162461bcd60e51b8152602060048201526014602482015273546f6f206d616e7920617574686f72697469657360601b6044820152606401610a08565b60005b8281101561139c57600084848381811061126e5761126e6149a2565b90506020020160208101906112839190614308565b6001600160a01b0316036112a95760405162461bcd60e51b8152600401610a0890614a44565b6112db8484838181106112be576112be6149a2565b90506020020160208101906112d39190614308565b6001906138af565b6113215760405162461bcd60e51b8152602060048201526017602482015276105d5d1a1bdc9a5d1e48185b1c9958591e481859191959604a1b6044820152606401610a08565b7f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c361993848483818110611354576113546149a2565b90506020020160208101906113699190614308565b604080516001600160a01b039092168252600160208301520160405180910390a180611394816149b8565b915050611252565b50505050565b60006113ad60015490565b905090565b604080516080810182526000808252602082018190529181018290526060810191909152600f600084846040516020016113ed929190614895565b60408051601f198184030181529181528151602092830120835282820193909352908201600020825160808101845281546001600160a01b03908116825260018301549382019390935260028201548316938101939093526003015416606082015290505b92915050565b600754600160a01b900460ff16156114825760405162461bcd60e51b8152600401610a089061486b565b6001600160a01b0386166114d85760405162461bcd60e51b815260206004820152601a60248201527f496e636f727265637420726563656976657220616464726573730000000000006044820152606401610a08565b60008060006114e8888888613921565b925092509250886001600160a01b0316886001600160a01b0316846001600160a01b03167feaa11317bb61110cf1035a22a7b6b4c716b909b47954d51ee13de1627fdf0f5085858b8b8b604051610d12959493929190614a6a565b600754600160a01b900460ff161561156d5760405162461bcd60e51b8152600401610a089061486b565b6001600160a01b0384166115c35760405162461bcd60e51b815260206004820152601a60248201527f496e636f727265637420726563656976657220616464726573730000000000006044820152606401610a08565b60008060006115d3868686613921565b925092509250866001600160a01b0316866001600160a01b0316846001600160a01b03167fc9e84ed7aa56cf1771d0373f4b6380ccc9c7cdae154f287abf95c48f72e7f0cf85858960405161163b939291909283526020830191909152604082015260600190565b60405180910390a450505050505050565b6001600160a01b0381166000908152601460205260408120549081900361169d5750506000805260146020527f4f26c3876aa9f4b92579780beea1161a61f87ebf1ec6ee865b299e447ecba99c5490565b80620186a0036116ab575060005b919050565b336116c36000546001600160a01b031690565b6001600160a01b0316146116e95760405162461bcd60e51b8152600401610a08906149d1565b6001600160a01b0382166000818152600960205260408082205490516370a0823160e01b8152306004820152919290916370a0823190602401602060405180830381865afa15801561173f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117639190614aa8565b61176d91906148f6565b90506117836001600160a01b038416838361370c565b7f2c5650189f92c7058626efc371b51fe7e71f37dacb696bc7cad0b1320931974a8383836040516117b693929190614ac1565b60405180910390a1505050565b336117d66000546001600160a01b031690565b6001600160a01b0316146117fc5760405162461bcd60e51b8152600401610a08906149d1565b6001600160a01b0382166118225760405162461bcd60e51b8152600401610a0890614a44565b6001600160a01b0382166000818152600a6020908152604091829020805460ff19168515159081179091558251938452908301527feabe320fe7911eab2e5125ac393caa5937659b712f0c3ac43316c61d4bc088019101611183565b6000546001600160a01b03163314806118a557503360009081526002602052604090205415155b806118bf5750336000908152600a602052604090205460ff165b6118c857600080fd5b6007805460ff60a01b1916600160a01b179055604051600181527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e906020015b60405180910390a1565b336119256000546001600160a01b031690565b6001600160a01b03161461194b5760405162461bcd60e51b8152600401610a08906149d1565b600b54801580159061195c57504281105b6119785760405162461bcd60e51b8152600401610a0890614a06565b620186a08211156119ba5760405162461bcd60e51b815260206004820152600c60248201526b546f6f20686967682066656560a01b6044820152606401610a08565b6001600160a01b038316600081815260146020908152604091829020859055815192835282018490527fa065abcf8156e439379371f7924f05c22b16f14de6a1448c5bcbdc525b46dd8591016117b6565b33611a1e6000546001600160a01b031690565b6001600160a01b031614611a445760405162461bcd60e51b8152600401610a08906149d1565b600b548015801590611a5557504281105b611a715760405162461bcd60e51b8152600401610a0890614a06565b6007805460ff60a01b19169055604051600081527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e9060200160405180910390a150565b33611ac86000546001600160a01b031690565b6001600160a01b031614611aee5760405162461bcd60e51b8152600401610a08906149d1565b6001600160a01b038116611b145760405162461bcd60e51b8152600401610a0890614a44565b6040805180820182526001600160a01b038316808252426001600160401b0381166020938401819052600c80546001600160e01b0319168417600160a01b909202919091179055835191825291810182905290917fd990f8f4f90cd3307c50ab3d095cfb65516e999b7584aee60c0af83eb48118de9101611183565b33611ba36000546001600160a01b031690565b6001600160a01b031614611bc95760405162461bcd60e51b8152600401610a08906149d1565b611bd64262015180614a31565b600b8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611908565b600d546001600160a01b03163314611c655760405162461bcd60e51b815260206004820152601a60248201527f63616c6c6572206973206e6f742074686520666f756e646572730000000000006044820152606401610a08565b6001600160a01b038116611cbb5760405162461bcd60e51b815260206004820152601d60248201527f6e6577206f776e657220697320746865207a65726f20616464726573730000006044820152606401610a08565b600d546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600d80546001600160a01b0319166001600160a01b0392909216919091179055565b33611d2a6000546001600160a01b031690565b6001600160a01b031614611d505760405162461bcd60e51b8152600401610a08906149d1565b600b548015801590611d6157504281105b611d7d5760405162461bcd60e51b8152600401610a0890614a06565b60005b83811015611e58578260126000878785818110611d9f57611d9f6149a2565b9050602002016020810190611db49190614308565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790557f769e5b6d0e1e39e7afbc891ae32dbc689cd164ac034d66bc633096c559b79287858583818110611e0f57611e0f6149a2565b9050602002016020810190611e249190614308565b604080516001600160a01b03909216825285151560208301520160405180910390a180611e50816149b8565b915050611d80565b5050505050565b468703611ea35760405162461bcd60e51b815260206004820152601260248201527127b7363c903337b932b4b3b7103a37b5b2b760711b6044820152606401610a08565b60008888604051602001611eb8929190614895565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b031615611f2c5760405162461bcd60e51b8152602060048201526013602482015272151bdad95b88185b1c9958591e481859191959606a1b6044820152606401610a08565b600089898989898989604051602001611f4b9796959493929190614ae5565b604051602081830303815290604052805190602001209050611f6f60008285613440565b60008787604051602001611f84929190614b36565b604051602081830303815290604052905060008686604051602001611faa929190614b5a565b60408051601f19818403018152919052600654909150600090611fda906001600160a01b03908116908f16613c15565b9050806001600160a01b0316631624f6c684848e6040518463ffffffff1660e01b815260040161200c93929190614b77565b600060405180830381600087803b15801561202657600080fd5b505af115801561203a573d6000803e3d6000fd5b505050508c600f600087815260200190815260200160002060000160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508b600f60008781526020019081526020016000206001018190555080600f600087815260200190815260200160002060020160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508460106000836001600160a01b03166001600160a01b031681526020019081526020016000208190555061210d8160036138af90919063ffffffff16565b507f7cedf5820723679f9a981ba7249d0ab5c6ecdb2f98392ef5a29051153b9e5a7d818e8e60405161214193929190614ac1565b60405180910390a150505050505050505050505050565b3361216b6000546001600160a01b031690565b6001600160a01b0316146121915760405162461bcd60e51b8152600401610a08906149d1565b600b5480158015906121a257504281105b6121be5760405162461bcd60e51b8152600401610a0890614a06565b82158015906121cf57506001548311155b80156121db5750828211155b6122195760405162461bcd60e51b815260206004820152600f60248201526e15dc9bdb99c81d1a1c995cda1bdb19608a1b6044820152606401610a08565b601382905560058390556040518381527f46e8115bf463f9c29a9424fe152addef1bfaf2b43180d19bb7c2c78cc0ff1ebf906020016117b6565b606060016000018054806020026020016040519081016040528092919081815260200182805480156122ae57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612290575b5050505050905090565b336122cb6000546001600160a01b031690565b6001600160a01b0316146122f15760405162461bcd60e51b8152600401610a08906149d1565b6000600b8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611908565b6001600160a01b038116600090815260106020526040902054156123845760405162461bcd60e51b8152602060048201526013602482015272151bdad95b88185b1c9958591e481859191959606a1b6044820152606401610a08565b6000816001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa1580156123c4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526123ec919081019061492c565b90506000826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801561242e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612456919081019061492c565b90506000836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612498573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124bc9190614909565b60ff169050600084466040516020016124d6929190614895565b60408051601f1981840301815291815281516020928301206000818152600f845282812080546001600160a01b038b166001600160a01b03199182168117835546600184015560029092018054909116905581526010909352912081905590506125416003866138af565b50846001600160a01b03167fef4ec9b3cfaa22dd32688bf4ac3c820e8b468ffb6452f61717fb9d845f3c5263468487876040516125819493929190614bb0565b60405180910390a25050505050565b600754600160a01b900460ff16156125ba5760405162461bcd60e51b8152600401610a089061486b565b60008481526008602090815260408083208a845290915290205460ff16156126245760405162461bcd60e51b815260206004820152601d60248201527f5472616e73616374696f6e20616c72656164792070726f6365737365640000006044820152606401610a08565b60008989604051602001612639929190614895565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b03166126865760405162461bcd60e51b8152600401610a08906148b7565b60016008600087815260200190815260200160002060008a815260200190815260200160002060006101000a81548160ff0219169083151502179055506000600f600083815260200190815260200160002060030160009054906101000a90046001600160a01b0316905060008b8b8a8a8d8b46308d8d6040516020016127169a99989796959493929190614be1565b604051602081830303815290604052805190602001209050612739828286613440565b50506000818152600f60205260409020600201546001600160a01b0316843b1515801561276f57506001600160a01b0385163014155b1561293e576001600160a01b03811615801561279457506001600160a01b038b166001145b1561280b5750600e54604051631490ba2d60e31b81528b916001600160a01b03169063a485d1689089906127d4908c90869084908c908c90600401614c62565b6000604051808303818588803b1580156127ed57600080fd5b505af1158015612801573d6000803e3d6000fd5b50505050506129f0565b6001600160a01b0381161561288557600e546040516340c10f1960e01b81526001600160a01b03918216600482015260248101899052908216906340c10f1990604401600060405180830381600087803b15801561286857600080fd5b505af115801561287c573d6000803e3d6000fd5b505050506128cf565b506001600160a01b038a16600090815260096020526040812080548c928992916128b09084906148f6565b9091555050600e546128cf906001600160a01b0383811691168961370c565b600e54604051631490ba2d60e31b81526001600160a01b039091169063a485d16890612907908b9085908c908b908b90600401614c62565b600060405180830381600087803b15801561292157600080fd5b505af1158015612935573d6000803e3d6000fd5b505050506129f0565b6001600160a01b03811615612982576040516340c10f1960e01b81526001600160a01b038981166004830152602482018990528216906340c10f1990604401612907565b50896000196001600160a01b038216016129ae576129a96001600160a01b03891688613643565b6129f0565b6001600160a01b038116600090815260096020526040812080548992906129d69084906148f6565b909155506129f090506001600160a01b038216898961370c565b604080518b8152602081018990529081018a9052606081018790526001600160a01b038681166080830152808a1691838216918e16907f3d5595f71187e446858be0c0fa22a3dd315023362b3b056c5eada14baecfc1019060a00160405180910390a45050505050505050505050565b33612a736000546001600160a01b031690565b6001600160a01b031614612a995760405162461bcd60e51b8152600401610a08906149d1565b60005b81811015612b9d57612ad6838383818110612ab957612ab96149a2565b9050602002016020810190612ace9190614308565b600190613cb5565b612b225760405162461bcd60e51b815260206004820152601860248201527f417574686f7269747920646f6573206e6f7420657869737400000000000000006044820152606401610a08565b7f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c361993838383818110612b5557612b556149a2565b9050602002016020810190612b6a9190614308565b604080516001600160a01b039092168252600060208301520160405180910390a180612b95816149b8565b915050612a9c565b505050565b600d546001600160a01b0316331480612bc557506000546001600160a01b031633145b612c1d5760405162461bcd60e51b815260206004820152602360248201527f4f776e61626c653a2063616c6c6572206973206e6f742074686520666f756e6460448201526265727360e81b6064820152608401610a08565b6001600160a01b038116612c825760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a08565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b33612cf06000546001600160a01b031690565b6001600160a01b031614612d165760405162461bcd60e51b8152600401610a08906149d1565b600b548015801590612d2757504281105b612d435760405162461bcd60e51b8152600401610a0890614a06565b6001600160a01b038216612d695760405162461bcd60e51b8152600401610a0890614a44565b600780546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527f41d2755f00068d89c23ebc6f1e73ce119a6236a44517ca061f544a3f91c9bca491016117b6565b6001600160a01b03891615801590612de357506001600160a01b03881615155b8015612df857506000546001600160a01b0316155b8015612e0c57506001600160a01b03871615155b612e1557600080fd5b600080546001600160a01b03199081166001600160a01b038c81169182178455600d8054909316908c16179091556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a36001600160a01b038616612ec45760405162461bcd60e51b815260206004820152601960248201527f57726f6e6720746f6b656e496d706c656d656e746174696f6e000000000000006044820152606401610a08565b84600003612f065760405162461bcd60e51b815260206004820152600f60248201526e15dc9bdb99c81d1a1c995cda1bdb19608a1b6044820152606401610a08565b60ff83612f1260015490565b612f1c9190614a31565b10612f605760405162461bcd60e51b8152602060048201526014602482015273546f6f206d616e7920617574686f72697469657360601b6044820152606401610a08565b60005b83811015613090576000858583818110612f7f57612f7f6149a2565b9050602002016020810190612f949190614308565b6001600160a01b031603612fba5760405162461bcd60e51b8152600401610a0890614a44565b612fcf8585838181106112be576112be6149a2565b6130155760405162461bcd60e51b8152602060048201526017602482015276105d5d1a1bdc9a5d1e48185b1c9958591e481859191959604a1b6044820152606401610a08565b7f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c361993858583818110613048576130486149a2565b905060200201602081019061305d9190614308565b604080516001600160a01b039092168252600160208301520160405180910390a180613088816149b8565b915050612f63565b50600680546001600160a01b0319166001600160a01b0388161790556040516130b890613fc9565b604051809103906000f0801580156130d4573d6000803e3d6000fd5b50600e80546001600160a01b03199081166001600160a01b0393841617909155600780549091169189169182179055604080516000815260208101929092527f41d2755f00068d89c23ebc6f1e73ce119a6236a44517ca061f544a3f91c9bca4910160405180910390a160058590556040518581527f46e8115bf463f9c29a9424fe152addef1bfaf2b43180d19bb7c2c78cc0ff1ebf9060200160405180910390a16001601260008686600081811061318f5761318f6149a2565b90506020020160208101906131a49190614308565b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055507f769e5b6d0e1e39e7afbc891ae32dbc689cd164ac034d66bc633096c559b792878484600081811061320f5761320f6149a2565b90506020020160208101906132249190614308565b604080516001600160a01b039092168252600160208301520160405180910390a160016013819055600b819055604051600091613265914690602001614895565b60408051601f1981840301815282825280516020918201206000818152600f835292832080546001600160a01b03191660019081178255469181018290559384905260109092527f8c6065603763fec3f5742441d3833f3f43b982453612d76adb39a885e3006b5f819055935090917fef4ec9b3cfaa22dd32688bf4ac3c820e8b468ffb6452f61717fb9d845f3c52639161330a916012908890889082908290614cc6565b60405180910390a250505050505050505050565b336133316000546001600160a01b031690565b6001600160a01b0316146133575760405162461bcd60e51b8152600401610a08906149d1565b600b54801580159061336857504281105b6133845760405162461bcd60e51b8152600401610a0890614a06565b60005b83811015611e585782601160008787858181106133a6576133a66149a2565b90506020020135815260200190815260200160002060006101000a81548160ff0219169083151502179055507f96fb1460e35cd6722dbde21ee5de56c0c1e73920214010e33b2591763744fd8b858583818110613405576134056149a2565b90506020020135846040516134269291909182521515602082015260400190565b60405180910390a180613438816149b8565b915050613387565b613497826040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b915060008080805b84518110156135775760006134cd878784815181106134c0576134c06149a2565b6020026020010151613df7565b6001600160a01b0381166000908152600260205260409020549091506001811b81158015906134fc5750848116155b1561354357938417938561350f816149b8565b6001600160a01b03851660009081526012602052604090205490975060ff16159050613543578661353f816149b8565b9750505b896001600160a01b0316836001600160a01b03160361356157600099505b505050808061356f906149b8565b91505061349f565b508160055411156135ca5760405162461bcd60e51b815260206004820152601760248201527f52657175697265206d6f7265207369676e6174757265730000000000000000006044820152606401610a08565b6001600160a01b0386161580156135e357506013548310155b61363b5760405162461bcd60e51b8152602060048201526024808201527f54686520726571756972656420617574686f726974696573206469646e27742060448201526339b4b3b760e11b6064820152608401610a08565b505050505050565b604080516000808252602082019092526001600160a01b03841690839060405161366d9190614d06565b60006040518083038185875af1925050503d80600081146136aa576040519150601f19603f3d011682016040523d82523d6000602084013e6136af565b606091505b5050905080612b9d5760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610a08565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916137689190614d06565b6000604051808303816000865af19150503d80600081146137a5576040519150601f19603f3d011682016040523d82523d6000602084013e6137aa565b606091505b50915091508180156137d45750805115806137d45750808060200190518101906137d49190614d22565b611e585760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610a08565b8154600090821061387e5760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604482015261647360f01b6064820152608401610a08565b826000018281548110613893576138936149a2565b6000918252602090912001546001600160a01b03169392505050565b6001600160a01b038116600090815260018301602052604081205461391957508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b03861690811790915585549082528286019093526040902091909155611452565b506000611452565b6000818152601160205260408120548190819060ff1680156139435750468414155b61398f5760405162461bcd60e51b815260206004820152601f60248201527f44657374696e6174696f6e20636861696e206e6f7420737570706f72746564006044820152606401610a08565b600061399a8761164c565b90508015613a5857620f42406139b08288614d3f565b6139ba9190614d56565b90506139c681876148f6565b91508015613a53576000196001600160a01b038816016139fb576007546139f6906001600160a01b031682613643565b613a17565b600754613a17906001600160a01b038981169133911684613e76565b7f6ded982279c8387ad8a63e73385031a3807c1862e633f06e09d11bcb6e282f60338883604051613a4a93929190614ac1565b60405180910390a15b613a5c565b8591505b6001600160a01b03871660009081526010602052604081205490819003613aba5760405162461bcd60e51b8152602060048201526012602482015271151bdad95b881dd85cdb89dd08185919195960721b6044820152606401610a08565b6000818152600f6020526040902080546001909101546001600160a01b0391821696509450881660001901613b2c5734871115613b275760405162461bcd60e51b815260206004820152600b60248201526a57726f6e672076616c756560a81b6044820152606401610a08565b613c0a565b6000818152600f60205260409020600201546001600160a01b03808a16911603613bc75760405163079cc67960e41b8152336004820152602481018490526001600160a01b038916906379cc6790906044016020604051808303816000875af1158015613b9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bc19190614d22565b50613c0a565b6001600160a01b03881660009081526009602052604081208054859290613bef908490614a31565b90915550613c0a90506001600160a01b038916333086613e76565b505093509350939050565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b0381166114525760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401610a08565b6001600160a01b03811660009081526001830160205260408120548015613ded576000613ce36001836148f6565b8554909150600090613cf7906001906148f6565b90506000866000018281548110613d1057613d106149a2565b60009182526020909120015487546001600160a01b0390911691508190889085908110613d3f57613d3f6149a2565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055613d73836001614a31565b6001600160a01b03821660009081526001890160205260409020558654879080613d9f57613d9f614d78565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03881682526001898101909152604082209190915594506114529350505050565b6000915050611452565b600080600080613e0685613f9a565b6040805160008152602081018083528b905260ff8516918101919091526060810183905260808101829052929550909350915060019060a0016020604051602081039080840390855afa158015613e61573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b600080856001600160a01b03166323b872dd868686604051602401613e9d93929190614ac1565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051613ed69190614d06565b6000604051808303816000865af19150503d8060008114613f13576040519150601f19603f3d011682016040523d82523d6000602084013e613f18565b606091505b5091509150818015613f42575080511580613f42575080806020019051810190613f429190614d22565b61363b5760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608401610a08565b60008060008351604114613fad57600080fd5b5050506020810151604082015160609092015160001a92909190565b610b0680614d8f83390190565b80356001600160a01b03811681146116ab57600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561402b5761402b613fed565b604052919050565b60006001600160401b0382111561404c5761404c613fed565b50601f01601f191660200190565b600082601f83011261406b57600080fd5b813561407e61407982614033565b614003565b81815284602083860101111561409357600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f8301126140c157600080fd5b813560206001600160401b03808311156140dd576140dd613fed565b8260051b6140ec838201614003565b938452858101830193838101908886111561410657600080fd5b84880192505b85831015614142578235848111156141245760008081fd5b6141328a87838c010161405a565b835250918401919084019061410c565b98975050505050505050565b600080600080600080600060e0888a03121561416957600080fd5b61417288613fd6565b9650602088013595506040880135945061418e60608901613fd6565b93506080880135925060a0880135915060c08801356001600160401b038111156141b757600080fd5b6141c38a828b016140b0565b91505092959891949750929550565b60005b838110156141ed5781810151838201526020016141d5565b50506000910152565b6000815180845261420e8160208601602086016141d2565b601f01601f19169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b838110156142be57888303603f19018552815180516001600160a01b031684528781015160ff16888501528681015160808886018190529061428d828701826141f6565b915050606080830151925085820381870152506142aa81836141f6565b968901969450505090860190600101614249565b509098975050505050505050565b6000806000606084860312156142e157600080fd5b6142ea84613fd6565b9250602084013591506142ff60408501613fd6565b90509250925092565b60006020828403121561431a57600080fd5b61432382613fd6565b9392505050565b60008083601f84011261433c57600080fd5b5081356001600160401b0381111561435357600080fd5b6020830191508360208260051b850101111561436e57600080fd5b9250929050565b6000806020838503121561438857600080fd5b82356001600160401b0381111561439e57600080fd5b6143aa8582860161432a565b90969095509350505050565b600080604083850312156143c957600080fd5b6143d283613fd6565b946020939093013593505050565b60008060008060008060c087890312156143f957600080fd5b61440287613fd6565b955061441060208801613fd6565b9450604087013593506060870135925061442c60808801613fd6565b915060a08701356001600160401b0381111561444757600080fd5b61445389828a0161405a565b9150509295509295509295565b6000806000806080858703121561447657600080fd5b61447f85613fd6565b935061448d60208601613fd6565b93969395505050506040820135916060013590565b600080604083850312156144b557600080fd5b6144be83613fd6565b91506144cc60208401613fd6565b90509250929050565b80151581146144e357600080fd5b50565b600080604083850312156144f957600080fd5b61450283613fd6565b91506020830135614512816144d5565b809150509250929050565b60006020828403121561452f57600080fd5b5035919050565b60008060006040848603121561454b57600080fd5b83356001600160401b0381111561456157600080fd5b61456d8682870161432a565b9094509250506020840135614581816144d5565b809150509250925092565b60008083601f84011261459e57600080fd5b5081356001600160401b038111156145b557600080fd5b60208301915083602082850101111561436e57600080fd5b60008060008060008060008060c0898b0312156145e957600080fd5b6145f289613fd6565b9750602089013596506040890135955060608901356001600160401b038082111561461c57600080fd5b6146288c838d0161458c565b909750955060808b013591508082111561464157600080fd5b61464d8c838d0161458c565b909550935060a08b013591508082111561466657600080fd5b506146738b828c016140b0565b9150509295985092959890939650565b6000806040838503121561469657600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b818110156146e65783516001600160a01b0316835292840192918401916001016146c1565b50909695505050505050565b60008060008060008060008060006101208a8c03121561471157600080fd5b61471a8a613fd6565b985060208a0135975060408a0135965061473660608b01613fd6565b955060808a0135945060a08a0135935061475260c08b01613fd6565b925060e08a01356001600160401b038082111561476e57600080fd5b61477a8d838e0161405a565b93506101008c013591508082111561479157600080fd5b5061479e8c828d016140b0565b9150509295985092959850929598565b600080600080600080600080600060e08a8c0312156147cc57600080fd5b6147d58a613fd6565b98506147e360208b01613fd6565b97506147f160408b01613fd6565b96506147ff60608b01613fd6565b955060808a0135945060a08a01356001600160401b038082111561482257600080fd5b61482e8d838e0161432a565b909650945060c08c013591508082111561484757600080fd5b506148548c828d0161458c565b915080935050809150509295985092959850929598565b60208082526010908201526f213934b233b29034b990333937bd32b760811b604082015260600190565b60609290921b6bffffffffffffffffffffffff19168252601482015260340190565b6020808252600f908201526e1d1bdad95b881b9bdd08195e1a5cdd608a1b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b81810381811115611452576114526148e0565b60006020828403121561491b57600080fd5b815160ff8116811461432357600080fd5b60006020828403121561493e57600080fd5b81516001600160401b0381111561495457600080fd5b8201601f8101841361496557600080fd5b805161497361407982614033565b81815285602083850101111561498857600080fd5b6149998260208301602086016141d2565b95945050505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016149ca576149ca6148e0565b5060010190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601190820152704e6f7420696e207365747570206d6f646560781b604082015260600190565b80820180821115611452576114526148e0565b6020808252600c908201526b5a65726f206164647265737360a01b604082015260600190565b85815284602082015283604082015260018060a01b038316606082015260a060808201526000614a9d60a08301846141f6565b979650505050505050565b600060208284031215614aba57600080fd5b5051919050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6bffffffffffffffffffffffff198860601b16815286601482015285603482015283856054830137600084820160548101600081528486823750600093016054019283525090979650505050505050565b6702bb930b83832b2160c51b81528183600883013760009101600801908152919050565b605760f81b81528183600183013760009101600101908152919050565b606081526000614b8a60608301866141f6565b8281036020840152614b9c81866141f6565b91505060ff83166040830152949350505050565b848152836020820152608060408201526000614bcf60808301856141f6565b8281036060840152614a9d81856141f6565b60006bffffffffffffffffffffffff19808d60601b1683528b6014840152808b60601b1660348401528960488401528860688401528760888401528660a8840152808660601b1660c8840152808560601b1660dc840152508251614c4c8160f08501602087016141d2565b9190910160f0019b9a5050505050505050505050565b6001600160a01b0386811682528581166020830152604082018590528316606082015260a060808201819052600090614a9d908301846141f6565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b868152856020820152608060408201526000614ce6608083018688614c9d565b8281036060840152614cf9818587614c9d565b9998505050505050505050565b60008251614d188184602087016141d2565b9190910192915050565b600060208284031215614d3457600080fd5b8151614323816144d5565b8082028115828204841417611452576114526148e0565b600082614d7357634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603160045260246000fdfe608060405234801561001057600080fd5b50600080546001600160a01b03191633179055610ad4806100326000396000f3fe60806040526004361061003f5760003560e01c80635431c94e146100445780638943ec0214610066578063a485d16814610086578063e78cea9214610099575b600080fd5b34801561005057600080fd5b5061006461005f36600461081e565b6100d5565b005b34801561007257600080fd5b50610064610081366004610857565b610294565b6100646100943660046108f6565b6102ea565b3480156100a557600080fd5b506000546100b9906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b60008054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061014a91906109e9565b6001600160a01b0316336001600160a01b03161461019c5760405162461bcd60e51b815260206004820152600a60248201526927b7363c9037bbb732b960b11b60448201526064015b60405180910390fd5b60006001600160a01b0383166101c65750476101c16001600160a01b03831682610510565b610244565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa15801561020a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061022e9190610a0d565b90506102446001600160a01b03841683836105de565b604080516001600160a01b038086168252841660208201529081018290527f0f51b71e5e9ee881072b57bf4022b60435e0000ad377b5c1434da39471002b559060600160405180910390a1505050565b6000546001600160a01b038581169116146102e45760405162461bcd60e51b815260206004820152601060248201526f4f6e6c792066726f6d2062726964676560801b6044820152606401610193565b50505050565b6000546001600160a01b031633146103325760405162461bcd60e51b815260206004820152600b60248201526a4f6e6c792062726964676560a81b6044820152606401610193565b6000196001600160a01b038516016103e95734925060006103538447610a26565b90506000836001600160a01b031685846040516103709190610a4d565b60006040518083038185875af1925050503d80600081146103ad576040519150601f19603f3d011682016040523d82523d6000602084013e6103b2565b606091505b5050905080156103c9576103c68247610a26565b94505b84156103e2576103e26001600160a01b03881686610510565b5050610509565b6103fd6001600160a01b03851683856106f2565b6000826001600160a01b03166000836040516104199190610a4d565b60006040518083038185875af1925050503d8060008114610456576040519150601f19603f3d011682016040523d82523d6000602084013e61045b565b606091505b5050905080156104d857604051636eb1769f60e11b81523060048201526001600160a01b03848116602483015286169063dd62ed3e90604401602060405180830381865afa1580156104b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d59190610a0d565b93505b8315610507576104f36001600160a01b0386168460006106f2565b6105076001600160a01b03861687866105de565b505b5050505050565b604080516000808252602082019092526001600160a01b03841690839060405161053a9190610a4d565b60006040518083038185875af1925050503d8060008114610577576040519150601f19603f3d011682016040523d82523d6000602084013e61057c565b606091505b50509050806105d95760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610193565b505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b179052915160009283929087169161063a9190610a4d565b6000604051808303816000865af19150503d8060008114610677576040519150601f19603f3d011682016040523d82523d6000602084013e61067c565b606091505b50915091508180156106a65750805115806106a65750808060200190518101906106a69190610a7c565b6105095760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610193565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b179052915160009283929087169161074e9190610a4d565b6000604051808303816000865af19150503d806000811461078b576040519150601f19603f3d011682016040523d82523d6000602084013e610790565b606091505b50915091508180156107ba5750805115806107ba5750808060200190518101906107ba9190610a7c565b6105095760405162461bcd60e51b815260206004820152601e60248201527f5472616e7366657248656c7065723a20415050524f56455f4641494c454400006044820152606401610193565b6001600160a01b038116811461081b57600080fd5b50565b6000806040838503121561083157600080fd5b823561083c81610806565b9150602083013561084c81610806565b809150509250929050565b6000806000806060858703121561086d57600080fd5b843561087881610806565b935060208501359250604085013567ffffffffffffffff8082111561089c57600080fd5b818701915087601f8301126108b057600080fd5b8135818111156108bf57600080fd5b8860208285010111156108d157600080fd5b95989497505060200194505050565b634e487b7160e01b600052604160045260246000fd5b600080600080600060a0868803121561090e57600080fd5b853561091981610806565b9450602086013561092981610806565b935060408601359250606086013561094081610806565b9150608086013567ffffffffffffffff8082111561095d57600080fd5b818801915088601f83011261097157600080fd5b813581811115610983576109836108e0565b604051601f8201601f19908116603f011681019083821181831017156109ab576109ab6108e0565b816040528281528b60208487010111156109c457600080fd5b8260208601602083013760006020848301015280955050505050509295509295909350565b6000602082840312156109fb57600080fd5b8151610a0681610806565b9392505050565b600060208284031215610a1f57600080fd5b5051919050565b81810381811115610a4757634e487b7160e01b600052601160045260246000fd5b92915050565b6000825160005b81811015610a6e5760208186018101518583015201610a54565b506000920191825250919050565b600060208284031215610a8e57600080fd5b81518015158114610a0657600080fdfea26469706673582212208afe667ddb88db78c3484d988496ed61ef38a3f5b7fcea15a41c39ac1c0b566e64736f6c63430008130033a264697066735822122089a9415157d8f781cf8ced25f5811663759b67f6eabcfaff6a1c203a5fa516eb64736f6c63430008130033
Deployed ByteCode
0x6080604052600436106102885760003560e01c8063648a58961161015a578063d04567f3116100c1578063f2fde38b1161007a578063f2fde38b14610876578063f391b57314610896578063f46901ed146108c6578063fa087671146108e6578063fa220f621461093f578063fab9fa531461095f57600080fd5b8063d04567f314610799578063d48bfca7146107ae578063df42fd36146107ce578063e4d7a86314610809578063e6074da714610829578063e8eccb661461085657600080fd5b80638f715701116101135780638f715701146106e257806393c32e06146106f7578063a0fd9ec814610717578063a85c33cd14610737578063b9c3620914610757578063c21b48651461077757600080fd5b8063648a58961461060f5780636a28f0001461062f5780636b9f97ef146106445780636c65fd6a146106645780638d60cded146106945780638da5cb5b146106c457600080fd5b80633cb3e9dc116101fe5780635417b02c116101b75780635417b02c146104e057806354cf428a1461050057806359770438146105205780635d799f87146105ba5780635e14e319146105da57806362a5af3b146105fa57600080fd5b80633cb3e9dc1461040d578063411b007e1461042357806342cde4e81461044357806343d7cce61461045957806344ddcb60146104ba578063487cda0d146104cd57600080fd5b8063273cbaa011610250578063273cbaa014610356578063278fa3e9146103785780632a94a9c8146103985780632ca0814b146103b85780632f3a3d5d146103d85780633af84ac4146103f857600080fd5b8063017e7e581461028d578063054f7d9c146102ca57806313bf8126146102fb57806316a27ecd1461031f5780631c9499e814610334575b600080fd5b34801561029957600080fd5b506007546102ad906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102d657600080fd5b506007546102eb90600160a01b900460ff1681565b60405190151581526020016102c1565b34801561030757600080fd5b50610311600b5481565b6040519081526020016102c1565b34801561032b57600080fd5b506102ad61097f565b34801561034057600080fd5b5061035461034f36600461414e565b610a17565b005b34801561036257600080fd5b5061036b610d25565b6040516102c19190614222565b34801561038457600080fd5b506103546103933660046142cc565b610f4f565b3480156103a457600080fd5b506103546103b3366004614308565b6110d3565b3480156103c457600080fd5b506103546103d3366004614375565b61118f565b3480156103e457600080fd5b506006546102ad906001600160a01b031681565b34801561040457600080fd5b506103116113a2565b34801561041957600080fd5b5061031160135481565b34801561042f57600080fd5b50600d546102ad906001600160a01b031681565b34801561044f57600080fd5b5061031160055481565b34801561046557600080fd5b506104796104743660046143b6565b6113b2565b6040516102c1919081516001600160a01b03908116825260208084015190830152604080840151821690830152606092830151169181019190915260800190565b6103546104c83660046143e0565b611458565b6103546104db366004614460565b611543565b3480156104ec57600080fd5b506103116104fb366004614308565b61164c565b34801561050c57600080fd5b50600e546102ad906001600160a01b031681565b34801561052c57600080fd5b5061047961053b366004614308565b60408051608080820183526000808352602080840182905283850182905260609384018290526001600160a01b03958616825260108152848220548252600f8152908490208451928301855280548616835260018101549183019190915260028101548516938201939093526003909201549092169181019190915290565b3480156105c657600080fd5b506103546105d53660046144a2565b6116b0565b3480156105e657600080fd5b506103546105f53660046144e6565b6117c3565b34801561060657600080fd5b5061035461187e565b34801561061b57600080fd5b5061035461062a3660046143b6565b611912565b34801561063b57600080fd5b50610354611a0b565b34801561065057600080fd5b5061035461065f366004614308565b611ab5565b34801561067057600080fd5b506102eb61067f366004614308565b600a6020526000908152604090205460ff1681565b3480156106a057600080fd5b506102eb6106af36600461451d565b60116020526000908152604090205460ff1681565b3480156106d057600080fd5b506000546001600160a01b03166102ad565b3480156106ee57600080fd5b50610354611b90565b34801561070357600080fd5b50610354610712366004614308565b611c0b565b34801561072357600080fd5b50610354610732366004614536565b611d17565b34801561074357600080fd5b506103546107523660046145cd565b611e5f565b34801561076357600080fd5b50610354610772366004614683565b612158565b34801561078357600080fd5b5061078c612253565b6040516102c191906146a5565b3480156107a557600080fd5b506103546122b8565b3480156107ba57600080fd5b506103546107c9366004614308565b612328565b3480156107da57600080fd5b506102eb6107e9366004614683565b600860209081526000928352604080842090915290825290205460ff1681565b34801561081557600080fd5b506103546108243660046146f2565b612590565b34801561083557600080fd5b50610311610844366004614308565b60096020526000908152604090205481565b34801561086257600080fd5b50610354610871366004614375565b612a60565b34801561088257600080fd5b50610354610891366004614308565b612ba2565b3480156108a257600080fd5b506102eb6108b1366004614308565b60126020526000908152604090205460ff1681565b3480156108d257600080fd5b506103546108e1366004614308565b612cdd565b3480156108f257600080fd5b50600c54610918906001600160a01b03811690600160a01b90046001600160401b031682565b604080516001600160a01b0390931683526001600160401b039091166020830152016102c1565b34801561094b57600080fd5b5061035461095a3660046147ae565b612dc3565b34801561096b57600080fd5b5061035461097a366004614536565b61331e565b60408051808201909152600c546001600160a01b0381168252600160a01b90046001600160401b03166020820181905260009190421180156109ca575080516001600160a01b031615155b610a115760405162461bcd60e51b8152602060048201526013602482015272155c19dc985919481b9bdd08185b1b1bddd959606a1b60448201526064015b60405180910390fd5b51919050565b600754600160a01b900460ff1615610a415760405162461bcd60e51b8152600401610a089061486b565b600082815260086020908152604080832088845290915290205460ff1615610aab5760405162461bcd60e51b815260206004820152601d60248201527f5472616e73616374696f6e20616c72656164792070726f6365737365640000006044820152606401610a08565b60008787604051602001610ac0929190614895565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b0316610b0d5760405162461bcd60e51b8152600401610a08906148b7565b60008381526008602090815260408083208984528252808320805460ff19166001179055838352600f825280832060030154905160608c811b6bffffffffffffffffffffffff1990811694830194909452603482018c905289811b8416605483015260688201899052608882018b905260a882018890524660c883015230901b90921660e88301526001600160a01b0316919060fc01604051602081830303815290604052805190602001209050610bc6828286613440565b50506000818152600f60205260409020600201546001600160a01b03168015610c50576040516340c10f1960e01b81526001600160a01b038781166004830152602482018790528216906340c10f1990604401600060405180830381600087803b158015610c3357600080fd5b505af1158015610c47573d6000803e3d6000fd5b50505050610cbe565b50876000196001600160a01b03821601610c7c57610c776001600160a01b03871686613643565b610cbe565b6001600160a01b03811660009081526009602052604081208054879290610ca49084906148f6565b90915550610cbe90506001600160a01b038216878761370c565b6040805189815260208101879052908101889052606081018590526001600160a01b0380881691838216918c16907f11d59cd9a05f00f00dae480666f9155193ed03ea6f17496757f3adcc07c2670d906080015b60405180910390a4505050505050505050565b60606000610d3260035490565b90506000816001600160401b03811115610d4e57610d4e613fed565b604051908082528060200260200182016040528015610da257816020015b6040805160808101825260008082526020820152606091810182905281810191909152815260200190600190039081610d6c5790505b50905060005b82811015610f48576000610dbd600383613820565b90506040518060800160405280826001600160a01b03168152602001826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3b9190614909565b60ff168152602001826001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015610e81573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ea9919081019061492c565b8152602001826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610eec573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f14919081019061492c565b815250838381518110610f2957610f296149a2565b6020026020010181905250508080610f40906149b8565b915050610da8565b5092915050565b33610f626000546001600160a01b031690565b6001600160a01b031614610f885760405162461bcd60e51b8152600401610a08906149d1565b60008383604051602001610f9d929190614895565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b0316610fea5760405162461bcd60e51b8152600401610a08906148b7565b6000818152600f60205260409020600301546001600160a01b03166110515760405162461bcd60e51b815260206004820152601c60248201527f6368616e676520617574686f72697479206e6f7420616c6c6f776564000000006044820152606401610a08565b6001600160a01b03821661106457600080fd5b6000818152600f602090815260409182902060030180546001600160a01b0319166001600160a01b038681169182179092558351878152928301528616917fee5ad7c073e09e589f00215f80efe0e7c6d5b9c4d19f5b85660a348b28ae867f910160405180910390a250505050565b336110e66000546001600160a01b031690565b6001600160a01b03161461110c5760405162461bcd60e51b8152600401610a08906149d1565b600b54801580159061111d57504281105b6111395760405162461bcd60e51b8152600401610a0890614a06565b600e80546001600160a01b0319166001600160a01b0384169081179091556040519081527f850b65e0a4a0af8155b0d56212b309166a3618bcd7ba7c1e83f09f3e721f294c906020015b60405180910390a15050565b336111a26000546001600160a01b031690565b6001600160a01b0316146111c85760405162461bcd60e51b8152600401610a08906149d1565b600b5480158015906111d957504281105b6111f55760405162461bcd60e51b8152600401610a0890614a06565b60ff8261120160015490565b61120b9190614a31565b1061124f5760405162461bcd60e51b8152602060048201526014602482015273546f6f206d616e7920617574686f72697469657360601b6044820152606401610a08565b60005b8281101561139c57600084848381811061126e5761126e6149a2565b90506020020160208101906112839190614308565b6001600160a01b0316036112a95760405162461bcd60e51b8152600401610a0890614a44565b6112db8484838181106112be576112be6149a2565b90506020020160208101906112d39190614308565b6001906138af565b6113215760405162461bcd60e51b8152602060048201526017602482015276105d5d1a1bdc9a5d1e48185b1c9958591e481859191959604a1b6044820152606401610a08565b7f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c361993848483818110611354576113546149a2565b90506020020160208101906113699190614308565b604080516001600160a01b039092168252600160208301520160405180910390a180611394816149b8565b915050611252565b50505050565b60006113ad60015490565b905090565b604080516080810182526000808252602082018190529181018290526060810191909152600f600084846040516020016113ed929190614895565b60408051601f198184030181529181528151602092830120835282820193909352908201600020825160808101845281546001600160a01b03908116825260018301549382019390935260028201548316938101939093526003015416606082015290505b92915050565b600754600160a01b900460ff16156114825760405162461bcd60e51b8152600401610a089061486b565b6001600160a01b0386166114d85760405162461bcd60e51b815260206004820152601a60248201527f496e636f727265637420726563656976657220616464726573730000000000006044820152606401610a08565b60008060006114e8888888613921565b925092509250886001600160a01b0316886001600160a01b0316846001600160a01b03167feaa11317bb61110cf1035a22a7b6b4c716b909b47954d51ee13de1627fdf0f5085858b8b8b604051610d12959493929190614a6a565b600754600160a01b900460ff161561156d5760405162461bcd60e51b8152600401610a089061486b565b6001600160a01b0384166115c35760405162461bcd60e51b815260206004820152601a60248201527f496e636f727265637420726563656976657220616464726573730000000000006044820152606401610a08565b60008060006115d3868686613921565b925092509250866001600160a01b0316866001600160a01b0316846001600160a01b03167fc9e84ed7aa56cf1771d0373f4b6380ccc9c7cdae154f287abf95c48f72e7f0cf85858960405161163b939291909283526020830191909152604082015260600190565b60405180910390a450505050505050565b6001600160a01b0381166000908152601460205260408120549081900361169d5750506000805260146020527f4f26c3876aa9f4b92579780beea1161a61f87ebf1ec6ee865b299e447ecba99c5490565b80620186a0036116ab575060005b919050565b336116c36000546001600160a01b031690565b6001600160a01b0316146116e95760405162461bcd60e51b8152600401610a08906149d1565b6001600160a01b0382166000818152600960205260408082205490516370a0823160e01b8152306004820152919290916370a0823190602401602060405180830381865afa15801561173f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117639190614aa8565b61176d91906148f6565b90506117836001600160a01b038416838361370c565b7f2c5650189f92c7058626efc371b51fe7e71f37dacb696bc7cad0b1320931974a8383836040516117b693929190614ac1565b60405180910390a1505050565b336117d66000546001600160a01b031690565b6001600160a01b0316146117fc5760405162461bcd60e51b8152600401610a08906149d1565b6001600160a01b0382166118225760405162461bcd60e51b8152600401610a0890614a44565b6001600160a01b0382166000818152600a6020908152604091829020805460ff19168515159081179091558251938452908301527feabe320fe7911eab2e5125ac393caa5937659b712f0c3ac43316c61d4bc088019101611183565b6000546001600160a01b03163314806118a557503360009081526002602052604090205415155b806118bf5750336000908152600a602052604090205460ff165b6118c857600080fd5b6007805460ff60a01b1916600160a01b179055604051600181527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e906020015b60405180910390a1565b336119256000546001600160a01b031690565b6001600160a01b03161461194b5760405162461bcd60e51b8152600401610a08906149d1565b600b54801580159061195c57504281105b6119785760405162461bcd60e51b8152600401610a0890614a06565b620186a08211156119ba5760405162461bcd60e51b815260206004820152600c60248201526b546f6f20686967682066656560a01b6044820152606401610a08565b6001600160a01b038316600081815260146020908152604091829020859055815192835282018490527fa065abcf8156e439379371f7924f05c22b16f14de6a1448c5bcbdc525b46dd8591016117b6565b33611a1e6000546001600160a01b031690565b6001600160a01b031614611a445760405162461bcd60e51b8152600401610a08906149d1565b600b548015801590611a5557504281105b611a715760405162461bcd60e51b8152600401610a0890614a06565b6007805460ff60a01b19169055604051600081527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e9060200160405180910390a150565b33611ac86000546001600160a01b031690565b6001600160a01b031614611aee5760405162461bcd60e51b8152600401610a08906149d1565b6001600160a01b038116611b145760405162461bcd60e51b8152600401610a0890614a44565b6040805180820182526001600160a01b038316808252426001600160401b0381166020938401819052600c80546001600160e01b0319168417600160a01b909202919091179055835191825291810182905290917fd990f8f4f90cd3307c50ab3d095cfb65516e999b7584aee60c0af83eb48118de9101611183565b33611ba36000546001600160a01b031690565b6001600160a01b031614611bc95760405162461bcd60e51b8152600401610a08906149d1565b611bd64262015180614a31565b600b8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611908565b600d546001600160a01b03163314611c655760405162461bcd60e51b815260206004820152601a60248201527f63616c6c6572206973206e6f742074686520666f756e646572730000000000006044820152606401610a08565b6001600160a01b038116611cbb5760405162461bcd60e51b815260206004820152601d60248201527f6e6577206f776e657220697320746865207a65726f20616464726573730000006044820152606401610a08565b600d546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600d80546001600160a01b0319166001600160a01b0392909216919091179055565b33611d2a6000546001600160a01b031690565b6001600160a01b031614611d505760405162461bcd60e51b8152600401610a08906149d1565b600b548015801590611d6157504281105b611d7d5760405162461bcd60e51b8152600401610a0890614a06565b60005b83811015611e58578260126000878785818110611d9f57611d9f6149a2565b9050602002016020810190611db49190614308565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790557f769e5b6d0e1e39e7afbc891ae32dbc689cd164ac034d66bc633096c559b79287858583818110611e0f57611e0f6149a2565b9050602002016020810190611e249190614308565b604080516001600160a01b03909216825285151560208301520160405180910390a180611e50816149b8565b915050611d80565b5050505050565b468703611ea35760405162461bcd60e51b815260206004820152601260248201527127b7363c903337b932b4b3b7103a37b5b2b760711b6044820152606401610a08565b60008888604051602001611eb8929190614895565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b031615611f2c5760405162461bcd60e51b8152602060048201526013602482015272151bdad95b88185b1c9958591e481859191959606a1b6044820152606401610a08565b600089898989898989604051602001611f4b9796959493929190614ae5565b604051602081830303815290604052805190602001209050611f6f60008285613440565b60008787604051602001611f84929190614b36565b604051602081830303815290604052905060008686604051602001611faa929190614b5a565b60408051601f19818403018152919052600654909150600090611fda906001600160a01b03908116908f16613c15565b9050806001600160a01b0316631624f6c684848e6040518463ffffffff1660e01b815260040161200c93929190614b77565b600060405180830381600087803b15801561202657600080fd5b505af115801561203a573d6000803e3d6000fd5b505050508c600f600087815260200190815260200160002060000160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508b600f60008781526020019081526020016000206001018190555080600f600087815260200190815260200160002060020160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508460106000836001600160a01b03166001600160a01b031681526020019081526020016000208190555061210d8160036138af90919063ffffffff16565b507f7cedf5820723679f9a981ba7249d0ab5c6ecdb2f98392ef5a29051153b9e5a7d818e8e60405161214193929190614ac1565b60405180910390a150505050505050505050505050565b3361216b6000546001600160a01b031690565b6001600160a01b0316146121915760405162461bcd60e51b8152600401610a08906149d1565b600b5480158015906121a257504281105b6121be5760405162461bcd60e51b8152600401610a0890614a06565b82158015906121cf57506001548311155b80156121db5750828211155b6122195760405162461bcd60e51b815260206004820152600f60248201526e15dc9bdb99c81d1a1c995cda1bdb19608a1b6044820152606401610a08565b601382905560058390556040518381527f46e8115bf463f9c29a9424fe152addef1bfaf2b43180d19bb7c2c78cc0ff1ebf906020016117b6565b606060016000018054806020026020016040519081016040528092919081815260200182805480156122ae57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612290575b5050505050905090565b336122cb6000546001600160a01b031690565b6001600160a01b0316146122f15760405162461bcd60e51b8152600401610a08906149d1565b6000600b8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611908565b6001600160a01b038116600090815260106020526040902054156123845760405162461bcd60e51b8152602060048201526013602482015272151bdad95b88185b1c9958591e481859191959606a1b6044820152606401610a08565b6000816001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa1580156123c4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526123ec919081019061492c565b90506000826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801561242e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612456919081019061492c565b90506000836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612498573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124bc9190614909565b60ff169050600084466040516020016124d6929190614895565b60408051601f1981840301815291815281516020928301206000818152600f845282812080546001600160a01b038b166001600160a01b03199182168117835546600184015560029092018054909116905581526010909352912081905590506125416003866138af565b50846001600160a01b03167fef4ec9b3cfaa22dd32688bf4ac3c820e8b468ffb6452f61717fb9d845f3c5263468487876040516125819493929190614bb0565b60405180910390a25050505050565b600754600160a01b900460ff16156125ba5760405162461bcd60e51b8152600401610a089061486b565b60008481526008602090815260408083208a845290915290205460ff16156126245760405162461bcd60e51b815260206004820152601d60248201527f5472616e73616374696f6e20616c72656164792070726f6365737365640000006044820152606401610a08565b60008989604051602001612639929190614895565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b03166126865760405162461bcd60e51b8152600401610a08906148b7565b60016008600087815260200190815260200160002060008a815260200190815260200160002060006101000a81548160ff0219169083151502179055506000600f600083815260200190815260200160002060030160009054906101000a90046001600160a01b0316905060008b8b8a8a8d8b46308d8d6040516020016127169a99989796959493929190614be1565b604051602081830303815290604052805190602001209050612739828286613440565b50506000818152600f60205260409020600201546001600160a01b0316843b1515801561276f57506001600160a01b0385163014155b1561293e576001600160a01b03811615801561279457506001600160a01b038b166001145b1561280b5750600e54604051631490ba2d60e31b81528b916001600160a01b03169063a485d1689089906127d4908c90869084908c908c90600401614c62565b6000604051808303818588803b1580156127ed57600080fd5b505af1158015612801573d6000803e3d6000fd5b50505050506129f0565b6001600160a01b0381161561288557600e546040516340c10f1960e01b81526001600160a01b03918216600482015260248101899052908216906340c10f1990604401600060405180830381600087803b15801561286857600080fd5b505af115801561287c573d6000803e3d6000fd5b505050506128cf565b506001600160a01b038a16600090815260096020526040812080548c928992916128b09084906148f6565b9091555050600e546128cf906001600160a01b0383811691168961370c565b600e54604051631490ba2d60e31b81526001600160a01b039091169063a485d16890612907908b9085908c908b908b90600401614c62565b600060405180830381600087803b15801561292157600080fd5b505af1158015612935573d6000803e3d6000fd5b505050506129f0565b6001600160a01b03811615612982576040516340c10f1960e01b81526001600160a01b038981166004830152602482018990528216906340c10f1990604401612907565b50896000196001600160a01b038216016129ae576129a96001600160a01b03891688613643565b6129f0565b6001600160a01b038116600090815260096020526040812080548992906129d69084906148f6565b909155506129f090506001600160a01b038216898961370c565b604080518b8152602081018990529081018a9052606081018790526001600160a01b038681166080830152808a1691838216918e16907f3d5595f71187e446858be0c0fa22a3dd315023362b3b056c5eada14baecfc1019060a00160405180910390a45050505050505050505050565b33612a736000546001600160a01b031690565b6001600160a01b031614612a995760405162461bcd60e51b8152600401610a08906149d1565b60005b81811015612b9d57612ad6838383818110612ab957612ab96149a2565b9050602002016020810190612ace9190614308565b600190613cb5565b612b225760405162461bcd60e51b815260206004820152601860248201527f417574686f7269747920646f6573206e6f7420657869737400000000000000006044820152606401610a08565b7f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c361993838383818110612b5557612b556149a2565b9050602002016020810190612b6a9190614308565b604080516001600160a01b039092168252600060208301520160405180910390a180612b95816149b8565b915050612a9c565b505050565b600d546001600160a01b0316331480612bc557506000546001600160a01b031633145b612c1d5760405162461bcd60e51b815260206004820152602360248201527f4f776e61626c653a2063616c6c6572206973206e6f742074686520666f756e6460448201526265727360e81b6064820152608401610a08565b6001600160a01b038116612c825760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a08565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b33612cf06000546001600160a01b031690565b6001600160a01b031614612d165760405162461bcd60e51b8152600401610a08906149d1565b600b548015801590612d2757504281105b612d435760405162461bcd60e51b8152600401610a0890614a06565b6001600160a01b038216612d695760405162461bcd60e51b8152600401610a0890614a44565b600780546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527f41d2755f00068d89c23ebc6f1e73ce119a6236a44517ca061f544a3f91c9bca491016117b6565b6001600160a01b03891615801590612de357506001600160a01b03881615155b8015612df857506000546001600160a01b0316155b8015612e0c57506001600160a01b03871615155b612e1557600080fd5b600080546001600160a01b03199081166001600160a01b038c81169182178455600d8054909316908c16179091556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a36001600160a01b038616612ec45760405162461bcd60e51b815260206004820152601960248201527f57726f6e6720746f6b656e496d706c656d656e746174696f6e000000000000006044820152606401610a08565b84600003612f065760405162461bcd60e51b815260206004820152600f60248201526e15dc9bdb99c81d1a1c995cda1bdb19608a1b6044820152606401610a08565b60ff83612f1260015490565b612f1c9190614a31565b10612f605760405162461bcd60e51b8152602060048201526014602482015273546f6f206d616e7920617574686f72697469657360601b6044820152606401610a08565b60005b83811015613090576000858583818110612f7f57612f7f6149a2565b9050602002016020810190612f949190614308565b6001600160a01b031603612fba5760405162461bcd60e51b8152600401610a0890614a44565b612fcf8585838181106112be576112be6149a2565b6130155760405162461bcd60e51b8152602060048201526017602482015276105d5d1a1bdc9a5d1e48185b1c9958591e481859191959604a1b6044820152606401610a08565b7f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c361993858583818110613048576130486149a2565b905060200201602081019061305d9190614308565b604080516001600160a01b039092168252600160208301520160405180910390a180613088816149b8565b915050612f63565b50600680546001600160a01b0319166001600160a01b0388161790556040516130b890613fc9565b604051809103906000f0801580156130d4573d6000803e3d6000fd5b50600e80546001600160a01b03199081166001600160a01b0393841617909155600780549091169189169182179055604080516000815260208101929092527f41d2755f00068d89c23ebc6f1e73ce119a6236a44517ca061f544a3f91c9bca4910160405180910390a160058590556040518581527f46e8115bf463f9c29a9424fe152addef1bfaf2b43180d19bb7c2c78cc0ff1ebf9060200160405180910390a16001601260008686600081811061318f5761318f6149a2565b90506020020160208101906131a49190614308565b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055507f769e5b6d0e1e39e7afbc891ae32dbc689cd164ac034d66bc633096c559b792878484600081811061320f5761320f6149a2565b90506020020160208101906132249190614308565b604080516001600160a01b039092168252600160208301520160405180910390a160016013819055600b819055604051600091613265914690602001614895565b60408051601f1981840301815282825280516020918201206000818152600f835292832080546001600160a01b03191660019081178255469181018290559384905260109092527f8c6065603763fec3f5742441d3833f3f43b982453612d76adb39a885e3006b5f819055935090917fef4ec9b3cfaa22dd32688bf4ac3c820e8b468ffb6452f61717fb9d845f3c52639161330a916012908890889082908290614cc6565b60405180910390a250505050505050505050565b336133316000546001600160a01b031690565b6001600160a01b0316146133575760405162461bcd60e51b8152600401610a08906149d1565b600b54801580159061336857504281105b6133845760405162461bcd60e51b8152600401610a0890614a06565b60005b83811015611e585782601160008787858181106133a6576133a66149a2565b90506020020135815260200190815260200160002060006101000a81548160ff0219169083151502179055507f96fb1460e35cd6722dbde21ee5de56c0c1e73920214010e33b2591763744fd8b858583818110613405576134056149a2565b90506020020135846040516134269291909182521515602082015260400190565b60405180910390a180613438816149b8565b915050613387565b613497826040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b915060008080805b84518110156135775760006134cd878784815181106134c0576134c06149a2565b6020026020010151613df7565b6001600160a01b0381166000908152600260205260409020549091506001811b81158015906134fc5750848116155b1561354357938417938561350f816149b8565b6001600160a01b03851660009081526012602052604090205490975060ff16159050613543578661353f816149b8565b9750505b896001600160a01b0316836001600160a01b03160361356157600099505b505050808061356f906149b8565b91505061349f565b508160055411156135ca5760405162461bcd60e51b815260206004820152601760248201527f52657175697265206d6f7265207369676e6174757265730000000000000000006044820152606401610a08565b6001600160a01b0386161580156135e357506013548310155b61363b5760405162461bcd60e51b8152602060048201526024808201527f54686520726571756972656420617574686f726974696573206469646e27742060448201526339b4b3b760e11b6064820152608401610a08565b505050505050565b604080516000808252602082019092526001600160a01b03841690839060405161366d9190614d06565b60006040518083038185875af1925050503d80600081146136aa576040519150601f19603f3d011682016040523d82523d6000602084013e6136af565b606091505b5050905080612b9d5760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610a08565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916137689190614d06565b6000604051808303816000865af19150503d80600081146137a5576040519150601f19603f3d011682016040523d82523d6000602084013e6137aa565b606091505b50915091508180156137d45750805115806137d45750808060200190518101906137d49190614d22565b611e585760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610a08565b8154600090821061387e5760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604482015261647360f01b6064820152608401610a08565b826000018281548110613893576138936149a2565b6000918252602090912001546001600160a01b03169392505050565b6001600160a01b038116600090815260018301602052604081205461391957508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b03861690811790915585549082528286019093526040902091909155611452565b506000611452565b6000818152601160205260408120548190819060ff1680156139435750468414155b61398f5760405162461bcd60e51b815260206004820152601f60248201527f44657374696e6174696f6e20636861696e206e6f7420737570706f72746564006044820152606401610a08565b600061399a8761164c565b90508015613a5857620f42406139b08288614d3f565b6139ba9190614d56565b90506139c681876148f6565b91508015613a53576000196001600160a01b038816016139fb576007546139f6906001600160a01b031682613643565b613a17565b600754613a17906001600160a01b038981169133911684613e76565b7f6ded982279c8387ad8a63e73385031a3807c1862e633f06e09d11bcb6e282f60338883604051613a4a93929190614ac1565b60405180910390a15b613a5c565b8591505b6001600160a01b03871660009081526010602052604081205490819003613aba5760405162461bcd60e51b8152602060048201526012602482015271151bdad95b881dd85cdb89dd08185919195960721b6044820152606401610a08565b6000818152600f6020526040902080546001909101546001600160a01b0391821696509450881660001901613b2c5734871115613b275760405162461bcd60e51b815260206004820152600b60248201526a57726f6e672076616c756560a81b6044820152606401610a08565b613c0a565b6000818152600f60205260409020600201546001600160a01b03808a16911603613bc75760405163079cc67960e41b8152336004820152602481018490526001600160a01b038916906379cc6790906044016020604051808303816000875af1158015613b9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bc19190614d22565b50613c0a565b6001600160a01b03881660009081526009602052604081208054859290613bef908490614a31565b90915550613c0a90506001600160a01b038916333086613e76565b505093509350939050565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b0381166114525760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401610a08565b6001600160a01b03811660009081526001830160205260408120548015613ded576000613ce36001836148f6565b8554909150600090613cf7906001906148f6565b90506000866000018281548110613d1057613d106149a2565b60009182526020909120015487546001600160a01b0390911691508190889085908110613d3f57613d3f6149a2565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055613d73836001614a31565b6001600160a01b03821660009081526001890160205260409020558654879080613d9f57613d9f614d78565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03881682526001898101909152604082209190915594506114529350505050565b6000915050611452565b600080600080613e0685613f9a565b6040805160008152602081018083528b905260ff8516918101919091526060810183905260808101829052929550909350915060019060a0016020604051602081039080840390855afa158015613e61573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b600080856001600160a01b03166323b872dd868686604051602401613e9d93929190614ac1565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051613ed69190614d06565b6000604051808303816000865af19150503d8060008114613f13576040519150601f19603f3d011682016040523d82523d6000602084013e613f18565b606091505b5091509150818015613f42575080511580613f42575080806020019051810190613f429190614d22565b61363b5760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608401610a08565b60008060008351604114613fad57600080fd5b5050506020810151604082015160609092015160001a92909190565b610b0680614d8f83390190565b80356001600160a01b03811681146116ab57600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561402b5761402b613fed565b604052919050565b60006001600160401b0382111561404c5761404c613fed565b50601f01601f191660200190565b600082601f83011261406b57600080fd5b813561407e61407982614033565b614003565b81815284602083860101111561409357600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f8301126140c157600080fd5b813560206001600160401b03808311156140dd576140dd613fed565b8260051b6140ec838201614003565b938452858101830193838101908886111561410657600080fd5b84880192505b85831015614142578235848111156141245760008081fd5b6141328a87838c010161405a565b835250918401919084019061410c565b98975050505050505050565b600080600080600080600060e0888a03121561416957600080fd5b61417288613fd6565b9650602088013595506040880135945061418e60608901613fd6565b93506080880135925060a0880135915060c08801356001600160401b038111156141b757600080fd5b6141c38a828b016140b0565b91505092959891949750929550565b60005b838110156141ed5781810151838201526020016141d5565b50506000910152565b6000815180845261420e8160208601602086016141d2565b601f01601f19169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b838110156142be57888303603f19018552815180516001600160a01b031684528781015160ff16888501528681015160808886018190529061428d828701826141f6565b915050606080830151925085820381870152506142aa81836141f6565b968901969450505090860190600101614249565b509098975050505050505050565b6000806000606084860312156142e157600080fd5b6142ea84613fd6565b9250602084013591506142ff60408501613fd6565b90509250925092565b60006020828403121561431a57600080fd5b61432382613fd6565b9392505050565b60008083601f84011261433c57600080fd5b5081356001600160401b0381111561435357600080fd5b6020830191508360208260051b850101111561436e57600080fd5b9250929050565b6000806020838503121561438857600080fd5b82356001600160401b0381111561439e57600080fd5b6143aa8582860161432a565b90969095509350505050565b600080604083850312156143c957600080fd5b6143d283613fd6565b946020939093013593505050565b60008060008060008060c087890312156143f957600080fd5b61440287613fd6565b955061441060208801613fd6565b9450604087013593506060870135925061442c60808801613fd6565b915060a08701356001600160401b0381111561444757600080fd5b61445389828a0161405a565b9150509295509295509295565b6000806000806080858703121561447657600080fd5b61447f85613fd6565b935061448d60208601613fd6565b93969395505050506040820135916060013590565b600080604083850312156144b557600080fd5b6144be83613fd6565b91506144cc60208401613fd6565b90509250929050565b80151581146144e357600080fd5b50565b600080604083850312156144f957600080fd5b61450283613fd6565b91506020830135614512816144d5565b809150509250929050565b60006020828403121561452f57600080fd5b5035919050565b60008060006040848603121561454b57600080fd5b83356001600160401b0381111561456157600080fd5b61456d8682870161432a565b9094509250506020840135614581816144d5565b809150509250925092565b60008083601f84011261459e57600080fd5b5081356001600160401b038111156145b557600080fd5b60208301915083602082850101111561436e57600080fd5b60008060008060008060008060c0898b0312156145e957600080fd5b6145f289613fd6565b9750602089013596506040890135955060608901356001600160401b038082111561461c57600080fd5b6146288c838d0161458c565b909750955060808b013591508082111561464157600080fd5b61464d8c838d0161458c565b909550935060a08b013591508082111561466657600080fd5b506146738b828c016140b0565b9150509295985092959890939650565b6000806040838503121561469657600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b818110156146e65783516001600160a01b0316835292840192918401916001016146c1565b50909695505050505050565b60008060008060008060008060006101208a8c03121561471157600080fd5b61471a8a613fd6565b985060208a0135975060408a0135965061473660608b01613fd6565b955060808a0135945060a08a0135935061475260c08b01613fd6565b925060e08a01356001600160401b038082111561476e57600080fd5b61477a8d838e0161405a565b93506101008c013591508082111561479157600080fd5b5061479e8c828d016140b0565b9150509295985092959850929598565b600080600080600080600080600060e08a8c0312156147cc57600080fd5b6147d58a613fd6565b98506147e360208b01613fd6565b97506147f160408b01613fd6565b96506147ff60608b01613fd6565b955060808a0135945060a08a01356001600160401b038082111561482257600080fd5b61482e8d838e0161432a565b909650945060c08c013591508082111561484757600080fd5b506148548c828d0161458c565b915080935050809150509295985092959850929598565b60208082526010908201526f213934b233b29034b990333937bd32b760811b604082015260600190565b60609290921b6bffffffffffffffffffffffff19168252601482015260340190565b6020808252600f908201526e1d1bdad95b881b9bdd08195e1a5cdd608a1b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b81810381811115611452576114526148e0565b60006020828403121561491b57600080fd5b815160ff8116811461432357600080fd5b60006020828403121561493e57600080fd5b81516001600160401b0381111561495457600080fd5b8201601f8101841361496557600080fd5b805161497361407982614033565b81815285602083850101111561498857600080fd5b6149998260208301602086016141d2565b95945050505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016149ca576149ca6148e0565b5060010190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601190820152704e6f7420696e207365747570206d6f646560781b604082015260600190565b80820180821115611452576114526148e0565b6020808252600c908201526b5a65726f206164647265737360a01b604082015260600190565b85815284602082015283604082015260018060a01b038316606082015260a060808201526000614a9d60a08301846141f6565b979650505050505050565b600060208284031215614aba57600080fd5b5051919050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6bffffffffffffffffffffffff198860601b16815286601482015285603482015283856054830137600084820160548101600081528486823750600093016054019283525090979650505050505050565b6702bb930b83832b2160c51b81528183600883013760009101600801908152919050565b605760f81b81528183600183013760009101600101908152919050565b606081526000614b8a60608301866141f6565b8281036020840152614b9c81866141f6565b91505060ff83166040830152949350505050565b848152836020820152608060408201526000614bcf60808301856141f6565b8281036060840152614a9d81856141f6565b60006bffffffffffffffffffffffff19808d60601b1683528b6014840152808b60601b1660348401528960488401528860688401528760888401528660a8840152808660601b1660c8840152808560601b1660dc840152508251614c4c8160f08501602087016141d2565b9190910160f0019b9a5050505050505050505050565b6001600160a01b0386811682528581166020830152604082018590528316606082015260a060808201819052600090614a9d908301846141f6565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b868152856020820152608060408201526000614ce6608083018688614c9d565b8281036060840152614cf9818587614c9d565b9998505050505050505050565b60008251614d188184602087016141d2565b9190910192915050565b600060208284031215614d3457600080fd5b8151614323816144d5565b8082028115828204841417611452576114526148e0565b600082614d7357634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603160045260246000fdfe608060405234801561001057600080fd5b50600080546001600160a01b03191633179055610ad4806100326000396000f3fe60806040526004361061003f5760003560e01c80635431c94e146100445780638943ec0214610066578063a485d16814610086578063e78cea9214610099575b600080fd5b34801561005057600080fd5b5061006461005f36600461081e565b6100d5565b005b34801561007257600080fd5b50610064610081366004610857565b610294565b6100646100943660046108f6565b6102ea565b3480156100a557600080fd5b506000546100b9906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b60008054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061014a91906109e9565b6001600160a01b0316336001600160a01b03161461019c5760405162461bcd60e51b815260206004820152600a60248201526927b7363c9037bbb732b960b11b60448201526064015b60405180910390fd5b60006001600160a01b0383166101c65750476101c16001600160a01b03831682610510565b610244565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa15801561020a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061022e9190610a0d565b90506102446001600160a01b03841683836105de565b604080516001600160a01b038086168252841660208201529081018290527f0f51b71e5e9ee881072b57bf4022b60435e0000ad377b5c1434da39471002b559060600160405180910390a1505050565b6000546001600160a01b038581169116146102e45760405162461bcd60e51b815260206004820152601060248201526f4f6e6c792066726f6d2062726964676560801b6044820152606401610193565b50505050565b6000546001600160a01b031633146103325760405162461bcd60e51b815260206004820152600b60248201526a4f6e6c792062726964676560a81b6044820152606401610193565b6000196001600160a01b038516016103e95734925060006103538447610a26565b90506000836001600160a01b031685846040516103709190610a4d565b60006040518083038185875af1925050503d80600081146103ad576040519150601f19603f3d011682016040523d82523d6000602084013e6103b2565b606091505b5050905080156103c9576103c68247610a26565b94505b84156103e2576103e26001600160a01b03881686610510565b5050610509565b6103fd6001600160a01b03851683856106f2565b6000826001600160a01b03166000836040516104199190610a4d565b60006040518083038185875af1925050503d8060008114610456576040519150601f19603f3d011682016040523d82523d6000602084013e61045b565b606091505b5050905080156104d857604051636eb1769f60e11b81523060048201526001600160a01b03848116602483015286169063dd62ed3e90604401602060405180830381865afa1580156104b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d59190610a0d565b93505b8315610507576104f36001600160a01b0386168460006106f2565b6105076001600160a01b03861687866105de565b505b5050505050565b604080516000808252602082019092526001600160a01b03841690839060405161053a9190610a4d565b60006040518083038185875af1925050503d8060008114610577576040519150601f19603f3d011682016040523d82523d6000602084013e61057c565b606091505b50509050806105d95760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610193565b505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b179052915160009283929087169161063a9190610a4d565b6000604051808303816000865af19150503d8060008114610677576040519150601f19603f3d011682016040523d82523d6000602084013e61067c565b606091505b50915091508180156106a65750805115806106a65750808060200190518101906106a69190610a7c565b6105095760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610193565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b179052915160009283929087169161074e9190610a4d565b6000604051808303816000865af19150503d806000811461078b576040519150601f19603f3d011682016040523d82523d6000602084013e610790565b606091505b50915091508180156107ba5750805115806107ba5750808060200190518101906107ba9190610a7c565b6105095760405162461bcd60e51b815260206004820152601e60248201527f5472616e7366657248656c7065723a20415050524f56455f4641494c454400006044820152606401610193565b6001600160a01b038116811461081b57600080fd5b50565b6000806040838503121561083157600080fd5b823561083c81610806565b9150602083013561084c81610806565b809150509250929050565b6000806000806060858703121561086d57600080fd5b843561087881610806565b935060208501359250604085013567ffffffffffffffff8082111561089c57600080fd5b818701915087601f8301126108b057600080fd5b8135818111156108bf57600080fd5b8860208285010111156108d157600080fd5b95989497505060200194505050565b634e487b7160e01b600052604160045260246000fd5b600080600080600060a0868803121561090e57600080fd5b853561091981610806565b9450602086013561092981610806565b935060408601359250606086013561094081610806565b9150608086013567ffffffffffffffff8082111561095d57600080fd5b818801915088601f83011261097157600080fd5b813581811115610983576109836108e0565b604051601f8201601f19908116603f011681019083821181831017156109ab576109ab6108e0565b816040528281528b60208487010111156109c457600080fd5b8260208601602083013760006020848301015280955050505050509295509295909350565b6000602082840312156109fb57600080fd5b8151610a0681610806565b9392505050565b600060208284031215610a1f57600080fd5b5051919050565b81810381811115610a4757634e487b7160e01b600052601160045260246000fd5b92915050565b6000825160005b81811015610a6e5760208186018101518583015201610a54565b506000920191825250919050565b600060208284031215610a8e57600080fd5b81518015158114610a0657600080fdfea26469706673582212208afe667ddb88db78c3484d988496ed61ef38a3f5b7fcea15a41c39ac1c0b566e64736f6c63430008130033a264697066735822122089a9415157d8f781cf8ced25f5811663759b67f6eabcfaff6a1c203a5fa516eb64736f6c63430008130033