Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- CallistoBridge
- Optimization enabled
- true
- Compiler version
- v0.8.19+commit.7dd6d404
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2024-09-26T15:24:50.436563Z
Contract source code
// SPDX-License-Identifier: No License (None)
pragma solidity ^0.8.0;
interface IERC223TokenCloned {
// initialize cloned token just for ERC223TokenCloned
function initialize(address newOwner, 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);
}
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");
_;
}
}
contract CallistoBridge is Ownable {
using TransferHelper for address;
using EnumerableSet for EnumerableSet.AddressSet;
EnumerableSet.AddressSet authorities; // authority has to sign claim transaction (message)
address constant MAX_NATIVE_COINS = address(31); // addresses from address(1) to MAX_NATIVE_COINS are considered as native coins
// CLO = address(1)
struct Token {
address token; // foreign token address
bool isWrapped; // is native token wrapped of foreign
}
struct Upgrade {
address newContract;
uint64 validFrom;
}
struct Fees {
uint256 inbound; // inbound transaction fee with 2 decimals
uint256 outbound; // outbound transaction fee with 2 decimals
}
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
uint256 public wrapNonce; // UNUSED
mapping(uint256 => mapping(bytes32 => bool)) public isTxProcessed; // chainID => txID => isProcessed
mapping(uint256 => mapping(address => Token)) public tokenPair; // chainID => native token address => Token struct
mapping(uint256 => mapping(address => address)) public tokenForeign; // chainID => foreign token address => native token
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;
address public founders;
address public requiredAuthority; // authority address that MUST sign swap transaction
mapping(address => address) public migration; // migration oldToken => newToken
bool public migrationSetupForbidden; // forbid adding migration tokens
address public contractCaller; // intermediate contract that calls third-party contract functions (toContract)
uint256 public functionMapping; // bitmap of locked functions (one bit per function)
Fees public fees; // bridge fees
event SetAuthority(address authority, bool isEnable);
event SetFeeTo(address previousFeeTo, address newFeeTo);
event SetThreshold(uint256 threshold);
event SetContractCaller(address newContractCaller);
event Deposit(address indexed token, address indexed sender, uint256 value, uint256 toChainId, address toToken);
event Claim(address indexed token, address indexed to, uint256 value, bytes32 txId, uint256 fromChainId, address fromToken);
event Fee(address indexed sender, address token, uint256 fee);
event CreatePair(address toToken, bool isWrapped, address fromToken, uint256 fromChainId);
event Frozen(bool status);
event RescuedERC20(address token, address to, uint256 value);
event SetFreezer(address freezer, bool isActive);
event SetupMode(uint time);
event UpgradeRequest(address newContract, uint256 validFrom);
event AddTokenMigration(address tokenFrom, address tokenTo);
event BridgeToContract(address indexed token, address indexed sender, uint256 value, uint256 toChainId, address toToken, address toContract, bytes data);
event ClaimToContract(address indexed token, address indexed to, uint256 value, bytes32 txId, uint256 fromChainId, address fromToken, address toContract);
// run only once from proxy
function initialize(address newOwner, address newFounders, address _tokenImplementation) external {
require(newOwner != address(0) && newFounders != address(0) && founders == address(0)); // run only once
_owner = newOwner;
founders = newFounders;
emit OwnershipTransferred(address(0), msg.sender);
require(_tokenImplementation != address(0), "Wrong tokenImplementation");
tokenImplementation = _tokenImplementation;
feeTo = msg.sender;
threshold = 1;
setupMode = 1; // allow setup after deployment
}
/*
constructor (address _tokenImplementation) {
require(_tokenImplementation != address(0), "Wrong tokenImplementation");
tokenImplementation = _tokenImplementation;
feeTo = msg.sender;
threshold = 1;
}
*/
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;
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);
}
function lockFunctions(uint256 _functionMapping) external onlyOwner {
functionMapping = _functionMapping;
}
// add authority
function setFreezer(address freezer, bool isActive) external onlyOwner {
require(freezer != address(0), "Zero address");
isFreezer[freezer] = isActive;
emit SetFreezer(freezer, isActive);
}
// add authority
function addAuthority(address authority) external onlyOwner onlySetup {
require(authority != address(0), "Zero address");
require(authorities.length() < 255, "Too many authorities");
require(authorities.add(authority), "Authority already added");
emit SetAuthority(authority, true);
}
// remove authority
function removeAuthority(address authority) external onlyOwner {
require(authorities.remove(authority), "Authority does not exist");
emit SetAuthority(authority, false);
}
// set authority address that MUST sign claim request
function setRequiredAuthority(address authority) external onlyOwner onlySetup {
requiredAuthority = authority;
}
// 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 fee receiver address
function setFees(Fees memory _fees) external onlyOwner onlySetup {
fees = _fees;
}
// set threshold - minimum number of signatures required to approve swap
function setThreshold(uint256 _threshold) external onlyOwner onlySetup {
require(_threshold != 0 && _threshold <= authorities.length(), "Wrong threshold");
threshold = _threshold;
emit SetThreshold(_threshold);
}
// set contractCaller address
function setContractCaller(address newContractCaller) external onlyOwner onlySetup {
contractCaller = newContractCaller;
emit SetContractCaller(newContractCaller);
}
function disableSetupMode() external onlyOwner {
setupMode = 0;
emit SetupMode(0);
}
function enableSetupMode() external onlyOwner {
setupMode = block.timestamp + 1 days;
emit SetupMode(setupMode);
}
// returns `nonce` to use in `createWrappedToken()` to create address starting with 0xCC.....
function calculateNonce(uint256 startNonce) external view returns(uint256 nonce, address addr) {
nonce = startNonce;
address implementation = tokenImplementation;
while (true) {
nonce++;
addr = Clones.predictDeterministicAddress(implementation, bytes32(nonce));
if (uint160(addr) & uint160(0xfF00000000000000000000000000000000000000) == uint160(0xCc00000000000000000000000000000000000000))
break;
}
}
function rescueERC20(address token, address to) external onlyOwner {
uint256 value = IERC223TokenCloned(token).balanceOf(address(this)) - tokenDeposits[token];
token.safeTransfer(to, value);
emit RescuedERC20(token, to, value);
}
// Create wrapped token for foreign token
function createWrappedToken(
address fromToken, // foreign token address
uint256 fromChainId, // foreign chain ID where token deployed
string memory name, // wrapped token name
string memory symbol, // wrapped token symbol
uint8 decimals, // wrapped token decimals (should be the same as in original token)
uint256 nonce // nonce to create wrapped token address begin with 0xCC....
)
external
onlyOwner
onlySetup
{
require(fromToken != address(0), "Wrong token address");
require(tokenForeign[fromChainId][fromToken] == address(0), "This token already wrapped");
address wrappedToken = Clones.cloneDeterministic(tokenImplementation, bytes32(nonce));
IERC223TokenCloned(wrappedToken).initialize(owner(), name, symbol, decimals);
tokenPair[fromChainId][wrappedToken] = Token(fromToken, true);
tokenForeign[fromChainId][fromToken] = wrappedToken;
emit CreatePair(wrappedToken, true, fromToken, fromChainId); //wrappedToken - wrapped token contract address
}
/**
* @dev Create pair between existing tokens on native and foreign chains
* @param toToken token address on native chain
* @param fromToken token address on foreign chain
* @param fromChainId foreign chain ID
* @param isWrapped `true` if `toToken` is our wrapped token otherwise `false`
*/
function createPair(address toToken, address fromToken, uint256 fromChainId, bool isWrapped) external onlyOwner onlySetup {
require(tokenPair[fromChainId][toToken].token == address(0), "Pair already exist");
tokenPair[fromChainId][toToken] = Token(fromToken, isWrapped);
tokenForeign[fromChainId][fromToken] = toToken;
emit CreatePair(toToken, isWrapped, fromToken, fromChainId);
}
/**
* @dev Delete unused pair
* @param toToken token address on native chain
* @param fromChainId foreign chain ID
*/
function deletePair(address toToken, uint256 fromChainId) external onlyOwner onlySetup {
delete tokenPair[fromChainId][toToken];
}
// 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(functionMapping & 2 == 0, "locked"); // check bit 1
require(receiver != address(0), "Incorrect receiver address");
address pair_token = _deposit(token, value, toChainId);
if (token == address(0xbf6c50889d3a620eb42C0F188b65aDe90De958c4) && // BUSDT token on the Callisto chain
pair_token == address(0xdAC17F958D2ee523a2206206994597C13D831ec7) && // USDT token on the ETH chain
toChainId == 1 ) // destination is ETH chain
{
// Since USDT token on ETH chain has 6 decimals we have to convert 18 decimals of BUSDT to 6 decimals
value = value / 10**12;
}
emit BridgeToContract(token, receiver, value, toChainId, pair_token, toContract, data);
}
// Claim tokens from the bridge and call the contract with 'data' parameters
function claimToContract(
address token, // token to receive
bytes32 txId, // deposit transaction hash on fromChain
address to, // user 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
payable
notFrozen
{
require(functionMapping & 4 == 0, "locked"); // check bit 2
require(!isTxProcessed[fromChainId][txId], "Transaction already processed");
Token memory pair = tokenPair[fromChainId][token];
require(pair.token != address(0), "There is no pair");
{
isTxProcessed[fromChainId][txId] = true;
// Check signature
address must = requiredAuthority;
bytes32 messageHash = keccak256(abi.encodePacked(token, to, value, txId, fromChainId, block.chainid, toContract, data));
messageHash = prefixed(messageHash);
uint256 uniqSig;
uint256 set; // maximum number of authorities is 255
for (uint i = 0; i < sig.length; i++) {
address authority = recoverSigner(messageHash, sig[i]);
if (authority == must) must = address(0);
uint256 index = authorities.indexOf(authority);
uint256 mask = 1 << index;
if (index != 0 && (set & mask) == 0 ) {
set |= mask;
uniqSig++;
}
}
require(threshold <= uniqSig, "Require more signatures");
require(must == address(0), "The required authority does not sign");
}
// fix decimals for USDT on ETH
if (token == address(0xbf6c50889d3a620eb42C0F188b65aDe90De958c4) && // BUSDT token on the Callisto chain
pair.token == address(0xdAC17F958D2ee523a2206206994597C13D831ec7) && // USDT token on the ETH chain
fromChainId == 1 ) // from ETH chain
{
// Since USDT token on ETH chain has 6 decimals we have to convert 6 decimals to 18 decimals of BUSDT
value = value * 10**12;
}
if (msg.value != 0) to.safeTransferETH(msg.value); // send CLO to user as bonus
// take fee
uint256 fee = value * fees.inbound / 10000;
if (fee != 0) {
value -= fee;
if (token <= MAX_NATIVE_COINS)
feeTo.safeTransferETH(fee);
else {
if(pair.isWrapped)
IERC223TokenCloned(token).mint(feeTo, fee);
else
token.safeTransfer(feeTo, fee);
}
emit Fee(to, token, fee);
}
// Call toContract
if(isContract(toContract) && toContract != address(this)) {
if (token <= MAX_NATIVE_COINS) {
IContractCaller(contractCaller).callContract{value: value}(to, token, value, toContract, data);
} else {
if(pair.isWrapped) {
IERC223TokenCloned(token).mint(contractCaller, value);
} else {
tokenDeposits[token] -= (value + fee);
token.safeTransfer(contractCaller, value);
}
IContractCaller(contractCaller).callContract(to, token, value, toContract, data);
}
} else { // if not contract
if (token <= MAX_NATIVE_COINS) {
to.safeTransferETH(value);
} else {
if(pair.isWrapped) {
IERC223TokenCloned(token).mint(to, value);
} else {
tokenDeposits[token] -= (value + fee);
token.safeTransfer(to, value);
}
}
}
emit ClaimToContract(token, to, value, txId, fromChainId, pair.token, toContract);
}
// Due to issue in Callisto Explorer when createPair with isWrapped = 0 it sends transaction with isWrapped = 1
// It makes this pair unusable without chance to fix it.
// function reversIsWrapped allow to reverse isWrapped value
function reversIsWrapped(address toToken, uint256 fromChainId) external onlyOwner onlySetup {
bool isWrapped = tokenPair[fromChainId][toToken].isWrapped;
tokenPair[fromChainId][toToken].isWrapped = !isWrapped;
}
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(functionMapping & 1 == 0, "locked"); // check bit 0
require(receiver != address(0), "Incorrect receiver address");
address pair_token = _deposit(token, value, toChainId);
if (token == address(0xbf6c50889d3a620eb42C0F188b65aDe90De958c4) && // BUSDT token on the Callisto chain
pair_token == address(0xdAC17F958D2ee523a2206206994597C13D831ec7) && // USDT token on the ETH chain
toChainId == 1 ) // destination is ETH chain
{
// Since USDT token on ETH chain has 6 decimals we have to convert 18 decimals of BUSDT to 6 decimals
value = value / 10**12;
}
emit Deposit(token, receiver, value, toChainId, pair_token);
}
function depositTokens(
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
{
address pair_token = _deposit(token, value, toChainId);
if (token == address(0xbf6c50889d3a620eb42C0F188b65aDe90De958c4) && // BUSDT token on the Callisto chain
pair_token == address(0xdAC17F958D2ee523a2206206994597C13D831ec7) && // USDT token on the ETH chain
toChainId == 1 ) // destination is ETH chain
{
// Since USDT token on ETH chain has 6 decimals we have to convert 18 decimals of BUSDT to 6 decimals
value = value / 10**12;
}
emit Deposit(token, msg.sender, value, toChainId, pair_token);
}
// ERC223 token transfer callback
// bytes _data = abi.encode(address receiver, uint256 toChainId)
function tokenReceived(address _from, uint _value, bytes calldata _data) external {
require(_data.length == 64, "Incorrect _data");
(
address receiver, // address of token receiver on destination chain
uint256 toChainId // destination chain Id where will be claimed tokens
) = abi.decode(_data, (address, uint256));
require(receiver != address(0), "Incorrect receiver address");
address token = msg.sender;
Token memory pair = tokenPair[toChainId][token];
require(pair.token != address(0), "There is no pair");
// take fee
uint256 fee = _value * fees.outbound / 10000;
if(fee != 0) {
_value -= fee;
token.safeTransfer(feeTo, fee);
emit Fee(_from, token, fee);
}
if(pair.isWrapped) {
IERC223TokenCloned(token).burn(_value);
} else {
tokenDeposits[token] += _value;
}
emit Deposit(token, receiver, _value, toChainId, pair.token);
}
// migrate from ERC20 to ERC223
function migrate(address token, uint value) external {
address newToken = migration[token];
require(newToken != address(0), "No migration token");
IERC223TokenCloned(token).burnFrom(msg.sender, value);
IERC223TokenCloned(newToken).mint(msg.sender, value);
}
/*
// setup token migration
function setupTokenMigration(address tokenFrom, address tokenTo) external onlyOwner onlySetup {
require(!migrationSetupForbidden);
// assign tokenImplementation here to avoid creation unnecessary function
tokenImplementation = address(0x4320e2310274dF1C1A46319044286389C6D16987); // ERC223 token implementation.
migration[tokenFrom] = tokenTo;
emit AddTokenMigration(tokenFrom, tokenTo);
}
// forbid setup token migration
function forbidMigrationSetup() external onlyOwner onlySetup {
migrationSetupForbidden = true;
}
*/
function _deposit(
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
)
internal
returns (address pair_token)
{
Token memory pair = tokenPair[toChainId][token];
require(pair.token != address(0), "There is no pair");
pair_token = pair.token;
uint256 fee;
if (token <= MAX_NATIVE_COINS) {
require(value <= msg.value, "Wrong value");
value = value * (10000 - fees.outbound) / 10000;
fee = msg.value - value;
} else {
fee = value * fees.outbound / 10000;
value -= fee;
if(pair.isWrapped) {
IERC223TokenCloned(token).burnFrom(msg.sender, value);
} else {
tokenDeposits[token] += value;
token.safeTransferFrom(msg.sender, address(this), value);
}
}
if (fee != 0) {
if (token <= MAX_NATIVE_COINS)
feeTo.safeTransferETH(fee);
else
token.safeTransferFrom(msg.sender, feeTo, fee);
emit Fee(msg.sender, token, fee);
}
}
// claim
function claim(
address token, // token to receive
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");
Token memory pair = tokenPair[fromChainId][token];
require(pair.token != address(0), "There is no pair");
isTxProcessed[fromChainId][txId] = true;
address must = requiredAuthority;
bytes32 messageHash = keccak256(abi.encodePacked(token, to, value, txId, fromChainId, block.chainid));
messageHash = prefixed(messageHash);
uint256 uniqSig;
uint256 set; // maximum number of authorities is 255
for (uint i = 0; i < sig.length; i++) {
address authority = recoverSigner(messageHash, sig[i]);
if (authority == must) must = address(0);
uint256 index = authorities.indexOf(authority);
uint256 mask = 1 << index;
if (index != 0 && (set & mask) == 0 ) {
set |= mask;
uniqSig++;
}
}
require(threshold <= uniqSig, "Require more signatures");
require(must == address(0), "The required authority does not sign");
if (token == address(0xbf6c50889d3a620eb42C0F188b65aDe90De958c4) && // BUSDT token on the Callisto chain
pair.token == address(0xdAC17F958D2ee523a2206206994597C13D831ec7) && // USDT token on the ETH chain
fromChainId == 1 ) // from ETH chain
{
// Since USDT token on ETH chain has 6 decimals we have to convert 6 decimals to 18 decimals of BUSDT
value = value * 10**12;
}
// take fee
uint256 fee = value * fees.inbound / 10000;
if (fee != 0) {
value -= fee;
if (token <= MAX_NATIVE_COINS)
feeTo.safeTransferETH(fee);
else {
if(pair.isWrapped)
IERC223TokenCloned(token).mint(feeTo, fee);
else
token.safeTransfer(feeTo, fee);
}
emit Fee(to, token, fee);
}
if (token <= MAX_NATIVE_COINS) {
to.safeTransferETH(value);
} else {
if(pair.isWrapped) {
IERC223TokenCloned(token).mint(to, value);
} else {
tokenDeposits[token] -= (value + fee);
token.safeTransfer(to, value);
}
}
emit Claim(token, to, value, txId, fromChainId, pair.token);
}
// Signature methods
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;
}
}
Contract ABI
[{"type":"event","name":"AddTokenMigration","inputs":[{"type":"address","name":"tokenFrom","internalType":"address","indexed":false},{"type":"address","name":"tokenTo","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"BridgeToContract","inputs":[{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"uint256","name":"toChainId","internalType":"uint256","indexed":false},{"type":"address","name":"toToken","internalType":"address","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":"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":"fromToken","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"ClaimToContract","inputs":[{"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":"fromToken","internalType":"address","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":"bool","name":"isWrapped","internalType":"bool","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":"token","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"uint256","name":"toChainId","internalType":"uint256","indexed":false},{"type":"address","name":"toToken","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Fee","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":true},{"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":"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":"SetThreshold","inputs":[{"type":"uint256","name":"threshold","internalType":"uint256","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":"ChangeFounder","inputs":[{"type":"address","name":"newFounders","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addAuthority","inputs":[{"type":"address","name":"authority","internalType":"address"}]},{"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":"view","outputs":[{"type":"uint256","name":"nonce","internalType":"uint256"},{"type":"address","name":"addr","internalType":"address"}],"name":"calculateNonce","inputs":[{"type":"uint256","name":"startNonce","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claim","inputs":[{"type":"address","name":"token","internalType":"address"},{"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":"payable","outputs":[],"name":"claimToContract","inputs":[{"type":"address","name":"token","internalType":"address"},{"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":"nonpayable","outputs":[],"name":"createPair","inputs":[{"type":"address","name":"toToken","internalType":"address"},{"type":"address","name":"fromToken","internalType":"address"},{"type":"uint256","name":"fromChainId","internalType":"uint256"},{"type":"bool","name":"isWrapped","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"createWrappedToken","inputs":[{"type":"address","name":"fromToken","internalType":"address"},{"type":"uint256","name":"fromChainId","internalType":"uint256"},{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"symbol","internalType":"string"},{"type":"uint8","name":"decimals","internalType":"uint8"},{"type":"uint256","name":"nonce","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deletePair","inputs":[{"type":"address","name":"toToken","internalType":"address"},{"type":"uint256","name":"fromChainId","internalType":"uint256"}]},{"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":"payable","outputs":[],"name":"depositTokens","inputs":[{"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":"uint256","name":"inbound","internalType":"uint256"},{"type":"uint256","name":"outbound","internalType":"uint256"}],"name":"fees","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":"uint256","name":"","internalType":"uint256"}],"name":"functionMapping","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":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"newOwner","internalType":"address"},{"type":"address","name":"newFounders","internalType":"address"},{"type":"address","name":"_tokenImplementation","internalType":"address"}]},{"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":"isTxProcessed","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"lockFunctions","inputs":[{"type":"uint256","name":"_functionMapping","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"migrate","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"migration","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"migrationSetupForbidden","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeAuthority","inputs":[{"type":"address","name":"authority","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"requestUpgrade","inputs":[{"type":"address","name":"newContract","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"requiredAuthority","inputs":[]},{"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":"reversIsWrapped","inputs":[{"type":"address","name":"toToken","internalType":"address"},{"type":"uint256","name":"fromChainId","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":"setFees","inputs":[{"type":"tuple","name":"_fees","internalType":"struct CallistoBridge.Fees","components":[{"type":"uint256","name":"inbound","internalType":"uint256"},{"type":"uint256","name":"outbound","internalType":"uint256"}]}]},{"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":"setRequiredAuthority","inputs":[{"type":"address","name":"authority","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setThreshold","inputs":[{"type":"uint256","name":"_threshold","internalType":"uint256"}]},{"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":"tokenForeign","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"tokenImplementation","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"token","internalType":"address"},{"type":"bool","name":"isWrapped","internalType":"bool"}],"name":"tokenPair","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"tokenReceived","inputs":[{"type":"address","name":"_from","internalType":"address"},{"type":"uint256","name":"_value","internalType":"uint256"},{"type":"bytes","name":"_data","internalType":"bytes"}]},{"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":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"wrapNonce","inputs":[]}]
Contract Creation Code
0x608060405234801561001057600080fd5b5061490d806100206000396000f3fe60806040526004361061031a5760003560e01c80636adf7412116101ab578063bfd06304116100f7578063db43968811610095578063f0f201271161006f578063f0f20127146109c6578063f2fde38b146109e6578063f46901ed14610a06578063fa08767114610a2657600080fd5b8063db4396881461094b578063df42fd361461095e578063e6074da71461099957600080fd5b8063c987c794116100d1578063c987c794146108d6578063cea9e110146108f6578063d04567f314610916578063d544e0101461092b57600080fd5b8063bfd0630414610874578063c0c53b8b14610894578063c21b4865146108b457600080fd5b80638f99523411610164578063a02a66ec1161013e578063a02a66ec146107fe578063abb718631461081e578063ad68ebf714610834578063b2e916d61461085457600080fd5b80638f9952341461078e578063960bfe04146107ae5780639af1d35a146107ce57600080fd5b80636adf7412146106d15780636b9f97ef146106eb5780636c65fd6a1461070b5780638943ec021461073b5780638da5cb5b1461075b5780638f7157011461077957600080fd5b80633f52c0f61161026a57806354cf428a116102235780635e14e319116101fd5780635e14e3191461065157806362a5af3b14610671578063685e2486146106865780636a28f000146106bc57600080fd5b806354cf428a146105f95780635c5b9f8f1461061e5780635d799f871461063157600080fd5b80633f52c0f614610567578063411b007e1461058757806342cde4e8146105a757806344ddcb60146105bd578063487cda0d146105d05780634dead732146105e357600080fd5b806326defa73116102d75780632f3a3d5d116102b15780632f3a3d5d146104d5578063384b2222146104f55780633af84ac4146105325780633cbdef561461054757600080fd5b806326defa73146104295780632a94a9c8146104495780632b1a7b581461046957600080fd5b8063017e7e581461031f578063054f7d9c1461035c57806313bf81261461038d57806316a27ecd146103b157806318d27b04146103c65780631c673ab8146103e8575b600080fd5b34801561032b57600080fd5b5060055461033f906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561036857600080fd5b5060055461037d90600160a01b900460ff1681565b6040519015158152602001610353565b34801561039957600080fd5b506103a3600c5481565b604051908152602001610353565b3480156103bd57600080fd5b5061033f610a7f565b3480156103d257600080fd5b506103e66103e1366004613d80565b610b17565b005b3480156103f457600080fd5b5061033f610403366004613db1565b60096020908152600092835260408084209091529082529020546001600160a01b031681565b34801561043557600080fd5b506103e6610444366004613de1565b610b55565b34801561045557600080fd5b506103e6610464366004613de1565b610cce565b34801561047557600080fd5b506104b6610484366004613db1565b60086020908152600092835260408084209091529082529020546001600160a01b03811690600160a01b900460ff1682565b604080516001600160a01b039093168352901515602083015201610353565b3480156104e157600080fd5b5060045461033f906001600160a01b031681565b34801561050157600080fd5b50610515610510366004613d80565b610d8a565b604080519283526001600160a01b03909116602083015201610353565b34801561053e57600080fd5b506103a3610dd1565b34801561055357600080fd5b506103e6610562366004613de1565b610de1565b34801561057357600080fd5b506103e6610582366004613e44565b610eed565b34801561059357600080fd5b50600e5461033f906001600160a01b031681565b3480156105b357600080fd5b506103a360035481565b6103e66105cb366004613f01565b610f62565b6103e66105de366004613f87565b6110ab565b3480156105ef57600080fd5b506103a360125481565b34801561060557600080fd5b5060115461033f9061010090046001600160a01b031681565b6103e661062c366004613fcd565b6111f0565b34801561063d57600080fd5b506103e661064c366004614002565b6112e9565b34801561065d57600080fd5b506103e661066c36600461403e565b61140d565b34801561067d57600080fd5b506103e66114c8565b34801561069257600080fd5b5061033f6106a1366004613de1565b6010602052600090815260409020546001600160a01b031681565b3480156106c857600080fd5b506103e661155c565b3480156106dd57600080fd5b5060115461037d9060ff1681565b3480156106f757600080fd5b506103e6610706366004613de1565b611607565b34801561071757600080fd5b5061037d610726366004613de1565b600b6020526000908152604090205460ff1681565b34801561074757600080fd5b506103e661075636600461406c565b6116ef565b34801561076757600080fd5b506000546001600160a01b031661033f565b34801561078557600080fd5b506103e6611954565b34801561079a57600080fd5b506103e66107a9366004614192565b6119cf565b3480156107ba57600080fd5b506103e66107c9366004613d80565b611f5d565b3480156107da57600080fd5b506013546014546107e9919082565b60408051928352602083019190915201610353565b34801561080a57600080fd5b506103e6610819366004613de1565b612047565b34801561082a57600080fd5b506103a360065481565b34801561084057600080fd5b506103e661084f366004614202565b6120d0565b34801561086057600080fd5b506103e661086f36600461422e565b612204565b34801561088057600080fd5b506103e661088f366004614281565b6123a0565b3480156108a057600080fd5b506103e66108af366004614323565b6126c3565b3480156108c057600080fd5b506108c96127e5565b604051610353919061436e565b3480156108e257600080fd5b506103e66108f1366004614202565b61284a565b34801561090257600080fd5b506103e6610911366004614202565b6128f3565b34801561092257600080fd5b506103e661298c565b34801561093757600080fd5b506103e6610946366004613de1565b6129fc565b6103e66109593660046143bb565b612acb565b34801561096a57600080fd5b5061037d610979366004614473565b600760209081526000928352604080842090915290825290205460ff1681565b3480156109a557600080fd5b506103a36109b4366004613de1565b600a6020526000908152604090205481565b3480156109d257600080fd5b50600f5461033f906001600160a01b031681565b3480156109f257600080fd5b506103e6610a01366004613de1565b613219565b348015610a1257600080fd5b506103e6610a21366004613de1565b613354565b348015610a3257600080fd5b50600d54610a58906001600160a01b03811690600160a01b90046001600160401b031682565b604080516001600160a01b0390931683526001600160401b03909116602083015201610353565b60408051808201909152600d546001600160a01b0381168252600160a01b90046001600160401b0316602082018190526000919042118015610aca575080516001600160a01b031615155b610b115760405162461bcd60e51b8152602060048201526013602482015272155c19dc985919481b9bdd08185b1b1bddd959606a1b60448201526064015b60405180910390fd5b51919050565b33610b2a6000546001600160a01b031690565b6001600160a01b031614610b505760405162461bcd60e51b8152600401610b0890614495565b601255565b33610b686000546001600160a01b031690565b6001600160a01b031614610b8e5760405162461bcd60e51b8152600401610b0890614495565b600c548015801590610b9f57504281105b610bbb5760405162461bcd60e51b8152600401610b08906144ca565b6001600160a01b038216610be15760405162461bcd60e51b8152600401610b08906144f5565b60ff610bec60015490565b10610c305760405162461bcd60e51b8152602060048201526014602482015273546f6f206d616e7920617574686f72697469657360601b6044820152606401610b08565b610c3b60018361343a565b610c875760405162461bcd60e51b815260206004820152601760248201527f417574686f7269747920616c72656164792061646465640000000000000000006044820152606401610b08565b604080516001600160a01b0384168152600160208201527f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c36199391015b60405180910390a15050565b33610ce16000546001600160a01b031690565b6001600160a01b031614610d075760405162461bcd60e51b8152600401610b0890614495565b600c548015801590610d1857504281105b610d345760405162461bcd60e51b8152600401610b08906144ca565b60118054610100600160a81b0319166101006001600160a01b038516908102919091179091556040519081527f850b65e0a4a0af8155b0d56212b309166a3618bcd7ba7c1e83f09f3e721f294c90602001610cc2565b60045481906000906001600160a01b03165b82610da681614531565b9350610db4905081846134ae565b915060016033609a1b031960ff60981b831601610d9c5750915091565b6000610ddc60015490565b905090565b600e546001600160a01b03163314610e3b5760405162461bcd60e51b815260206004820152601a60248201527f63616c6c6572206973206e6f742074686520666f756e646572730000000000006044820152606401610b08565b6001600160a01b038116610e915760405162461bcd60e51b815260206004820152601d60248201527f6e6577206f776e657220697320746865207a65726f20616464726573730000006044820152606401610b08565b600e546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600e80546001600160a01b0319166001600160a01b0392909216919091179055565b33610f006000546001600160a01b031690565b6001600160a01b031614610f265760405162461bcd60e51b8152600401610b0890614495565b600c548015801590610f3757504281105b610f535760405162461bcd60e51b8152600401610b08906144ca565b50805160135560200151601455565b600554600160a01b900460ff1615610f8c5760405162461bcd60e51b8152600401610b089061454a565b60125460021615610faf5760405162461bcd60e51b8152600401610b0890614574565b6001600160a01b038616610fd55760405162461bcd60e51b8152600401610b0890614594565b6000610fe286868661351b565b90506001600160a01b03861673bf6c50889d3a620eb42c0f188b65ade90de958c414801561102c57506001600160a01b03811673dac17f958d2ee523a2206206994597c13d831ec7145b80156110385750836001145b1561104f5761104c64e8d4a51000866145cb565b94505b866001600160a01b0316866001600160a01b03167f8e3af9ffa3a105195ae58520a6e3ab241268521cd0a0ca519896e650d4fbebe4878785888860405161109a95949392919061463d565b60405180910390a350505050505050565b600554600160a01b900460ff16156110d55760405162461bcd60e51b8152600401610b089061454a565b601254600116156110f85760405162461bcd60e51b8152600401610b0890614574565b6001600160a01b03841661111e5760405162461bcd60e51b8152600401610b0890614594565b600061112b84848461351b565b90506001600160a01b03841673bf6c50889d3a620eb42c0f188b65ade90de958c414801561117557506001600160a01b03811673dac17f958d2ee523a2206206994597c13d831ec7145b80156111815750816001145b156111985761119564e8d4a51000846145cb565b92505b60408051848152602081018490526001600160a01b03838116828401529151878316928716917ff5dd9317b9e63ac316ce44acc85f670b54b339cfa3e9076e1dd55065b922314b919081900360600190a35050505050565b600554600160a01b900460ff161561121a5760405162461bcd60e51b8152600401610b089061454a565b600061122784848461351b565b90506001600160a01b03841673bf6c50889d3a620eb42c0f188b65ade90de958c414801561127157506001600160a01b03811673dac17f958d2ee523a2206206994597c13d831ec7145b801561127d5750816001145b156112945761129164e8d4a51000846145cb565b92505b60408051848152602081018490526001600160a01b0383811682840152915133928716917ff5dd9317b9e63ac316ce44acc85f670b54b339cfa3e9076e1dd55065b922314b919081900360600190a350505050565b336112fc6000546001600160a01b031690565b6001600160a01b0316146113225760405162461bcd60e51b8152600401610b0890614495565b6001600160a01b0382166000818152600a60205260408082205490516370a0823160e01b8152306004820152919290916370a0823190602401602060405180830381865afa158015611378573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139c9190614681565b6113a6919061469a565b90506113bc6001600160a01b0384168383613782565b604080516001600160a01b038086168252841660208201529081018290527f2c5650189f92c7058626efc371b51fe7e71f37dacb696bc7cad0b1320931974a906060015b60405180910390a1505050565b336114206000546001600160a01b031690565b6001600160a01b0316146114465760405162461bcd60e51b8152600401610b0890614495565b6001600160a01b03821661146c5760405162461bcd60e51b8152600401610b08906144f5565b6001600160a01b0382166000818152600b6020908152604091829020805460ff19168515159081179091558251938452908301527feabe320fe7911eab2e5125ac393caa5937659b712f0c3ac43316c61d4bc088019101610cc2565b6000546001600160a01b03163314806114ef57503360009081526002602052604090205415155b806115095750336000908152600b602052604090205460ff165b61151257600080fd5b6005805460ff60a01b1916600160a01b179055604051600181527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e906020015b60405180910390a1565b3361156f6000546001600160a01b031690565b6001600160a01b0316146115955760405162461bcd60e51b8152600401610b0890614495565b600c5480158015906115a657504281105b6115c25760405162461bcd60e51b8152600401610b08906144ca565b6005805460ff60a01b19169055604051600081527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e906020015b60405180910390a150565b3361161a6000546001600160a01b031690565b6001600160a01b0316146116405760405162461bcd60e51b8152600401610b0890614495565b6001600160a01b0381166116665760405162461bcd60e51b8152600401610b08906144f5565b6000611675426203f4806146ad565b6040805180820182526001600160a01b0385168082526001600160401b0384166020909201829052600d80546001600160e01b031916909117600160a01b909202919091179055519091507fd990f8f4f90cd3307c50ab3d095cfb65516e999b7584aee60c0af83eb48118de90610cc290849084906146c0565b604081146117315760405162461bcd60e51b815260206004820152600f60248201526e496e636f7272656374205f6461746160881b6044820152606401610b08565b60008061174083850185614202565b90925090506001600160a01b03821661176b5760405162461bcd60e51b8152600401610b0890614594565b600081815260086020908152604080832033808552908352928190208151808301909252546001600160a01b038116808352600160a01b90910460ff16151592820192909252906117ce5760405162461bcd60e51b8152600401610b08906146d9565b601454600090612710906117e2908a614703565b6117ec91906145cb565b9050801561184d576117fe818961469a565b60055490985061181b906001600160a01b03858116911683613782565b886001600160a01b03166000805160206148b883398151915284836040516118449291906146c0565b60405180910390a25b8160200151156118c857604051630852cd8d60e31b8152600481018990526001600160a01b038416906342966c68906024016020604051808303816000875af115801561189e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c2919061471a565b506118f6565b6001600160a01b0383166000908152600a6020526040812080548a92906118f09084906146ad565b90915550505b8151604080518a8152602081018790526001600160a01b03928316818301529051878316928616917ff5dd9317b9e63ac316ce44acc85f670b54b339cfa3e9076e1dd55065b922314b919081900360600190a3505050505050505050565b336119676000546001600160a01b031690565b6001600160a01b03161461198d5760405162461bcd60e51b8152600401610b0890614495565b61199a42620151806146ad565b600c8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611552565b600554600160a01b900460ff16156119f95760405162461bcd60e51b8152600401610b089061454a565b600082815260076020908152604080832088845290915290205460ff1615611a635760405162461bcd60e51b815260206004820152601d60248201527f5472616e73616374696f6e20616c72656164792070726f6365737365640000006044820152606401610b08565b60008281526008602090815260408083206001600160a01b038a8116855290835292819020815180830190925254928316808252600160a01b90930460ff1615159181019190915290611ac85760405162461bcd60e51b8152600401610b08906146d9565b60008381526007602090815260408083208984528252808320805460ff19166001179055600f54905160608b811b6bffffffffffffffffffffffff199081169483019490945289901b90921660348301526048820187905260688201899052608882018690524660a88301526001600160a01b0316919060c801604051602081830303815290604052805190602001209050611b638161389f565b905060008060005b8651811015611c12576000611b9985898481518110611b8c57611b8c614737565b60200260200101516138f2565b9050856001600160a01b0316816001600160a01b031603611bb957600095505b6001600160a01b0381166000908152600260205260409020546001811b8115801590611be55750848116155b15611bfc579384179385611bf881614531565b9650505b5050508080611c0a90614531565b915050611b6b565b50816003541115611c5f5760405162461bcd60e51b815260206004820152601760248201527652657175697265206d6f7265207369676e61747572657360481b6044820152606401610b08565b6001600160a01b03841615611c865760405162461bcd60e51b8152600401610b089061474d565b6001600160a01b038b1673bf6c50889d3a620eb42c0f188b65ade90de958c4148015611ccf575084516001600160a01b031673dac17f958d2ee523a2206206994597c13d831ec7145b8015611cdb5750866001145b15611cf257611cef8864e8d4a51000614703565b97505b60135460009061271090611d06908b614703565b611d1091906145cb565b90508015611e1157611d22818a61469a565b9850601f6001600160a01b038d1611611d5057600554611d4b906001600160a01b031682613971565b611ddf565b856020015115611dc5576005546040516340c10f1960e01b81526001600160a01b038e8116926340c10f1992611d8e929091169085906004016146c0565b600060405180830381600087803b158015611da857600080fd5b505af1158015611dbc573d6000803e3d6000fd5b50505050611ddf565b600554611ddf906001600160a01b038e8116911683613782565b896001600160a01b03166000805160206148b88339815191528d83604051611e089291906146c0565b60405180910390a25b601f6001600160a01b038d1611611e3a57611e356001600160a01b038b168a613971565b611ef5565b856020015115611ea9576040516340c10f1960e01b81526001600160a01b038d16906340c10f1990611e72908d908d906004016146c0565b600060405180830381600087803b158015611e8c57600080fd5b505af1158015611ea0573d6000803e3d6000fd5b50505050611ef5565b611eb3818a6146ad565b6001600160a01b038d166000908152600a602052604081208054909190611edb90849061469a565b90915550611ef590506001600160a01b038d168b8b613782565b8551604080518b8152602081018e90529081018a90526001600160a01b039182166060820152818c16918e16907fc9e45b9f44cc745053533754942aa17989494514aeadbb624b4b5e34a0ce5fc29060800160405180910390a3505050505050505050505050565b33611f706000546001600160a01b031690565b6001600160a01b031614611f965760405162461bcd60e51b8152600401610b0890614495565b600c548015801590611fa757504281105b611fc35760405162461bcd60e51b8152600401610b08906144ca565b8115801590611fd457506001548211155b6120125760405162461bcd60e51b815260206004820152600f60248201526e15dc9bdb99c81d1a1c995cda1bdb19608a1b6044820152606401610b08565b60038290556040518281527f46e8115bf463f9c29a9424fe152addef1bfaf2b43180d19bb7c2c78cc0ff1ebf90602001610cc2565b3361205a6000546001600160a01b031690565b6001600160a01b0316146120805760405162461bcd60e51b8152600401610b0890614495565b600c54801580159061209157504281105b6120ad5760405162461bcd60e51b8152600401610b08906144ca565b50600f80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03808316600090815260106020526040902054168061212d5760405162461bcd60e51b815260206004820152601260248201527127379036b4b3b930ba34b7b7103a37b5b2b760711b6044820152606401610b08565b60405163079cc67960e41b81526001600160a01b038416906379cc67909061215b90339086906004016146c0565b6020604051808303816000875af115801561217a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061219e919061471a565b506040516340c10f1960e01b81526001600160a01b038216906340c10f19906121cd90339086906004016146c0565b600060405180830381600087803b1580156121e757600080fd5b505af11580156121fb573d6000803e3d6000fd5b50505050505050565b336122176000546001600160a01b031690565b6001600160a01b03161461223d5760405162461bcd60e51b8152600401610b0890614495565b600c54801580159061224e57504281105b61226a5760405162461bcd60e51b8152600401610b08906144ca565b60008381526008602090815260408083206001600160a01b03898116855292529091205416156122d15760405162461bcd60e51b815260206004820152601260248201527114185a5c88185b1c9958591e48195e1a5cdd60721b6044820152606401610b08565b6040805180820182526001600160a01b03868116808352851515602080850182815260008a8152600883528781208d87168083529084528882209751885493511515600160a01b026001600160a81b0319909416971696909617919091179095558885526009815285852083865281529385902080546001600160a01b0319168417905584519283529282019290925291820152606081018490527f4e37907d987e2429cd26da336a410ffe2d567dc727ed293e6c500023525af2959060800160405180910390a15050505050565b336123b36000546001600160a01b031690565b6001600160a01b0316146123d95760405162461bcd60e51b8152600401610b0890614495565b600c5480158015906123ea57504281105b6124065760405162461bcd60e51b8152600401610b08906144ca565b6001600160a01b0387166124525760405162461bcd60e51b815260206004820152601360248201527257726f6e6720746f6b656e206164647265737360681b6044820152606401610b08565b60008681526009602090815260408083206001600160a01b038b8116855292529091205416156124c45760405162461bcd60e51b815260206004820152601a60248201527f5468697320746f6b656e20616c726561647920777261707065640000000000006044820152606401610b08565b6004546000906124dd906001600160a01b031684613a3f565b9050806001600160a01b031663f6d2ee866125006000546001600160a01b031690565b8888886040518563ffffffff1660e01b81526004016125229493929190614791565b600060405180830381600087803b15801561253c57600080fd5b505af1158015612550573d6000803e3d6000fd5b505050506040518060400160405280896001600160a01b0316815260200160011515815250600860008981526020019081526020016000206000836001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548160ff021916908315150217905550905050806009600089815260200190815260200160002060008a6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055507f4e37907d987e2429cd26da336a410ffe2d567dc727ed293e6c500023525af2958160018a8a6040516126b194939291906001600160a01b039485168152921515602084015292166040820152606081019190915260800190565b60405180910390a15050505050505050565b6001600160a01b038316158015906126e357506001600160a01b03821615155b80156126f85750600e546001600160a01b0316155b61270157600080fd5b600080546001600160a01b038086166001600160a01b0319928316178355600e8054918616919092161790556040513391907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a36001600160a01b0381166127ae5760405162461bcd60e51b815260206004820152601960248201527f57726f6e6720746f6b656e496d706c656d656e746174696f6e000000000000006044820152606401610b08565b600480546001600160a01b039092166001600160a01b03199283161790556005805490911633179055505060016003819055600c55565b6060600160000180548060200260200160405190810160405280929190818152602001828054801561284057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612822575b5050505050905090565b3361285d6000546001600160a01b031690565b6001600160a01b0316146128835760405162461bcd60e51b8152600401610b0890614495565b600c54801580159061289457504281105b6128b05760405162461bcd60e51b8152600401610b08906144ca565b5060009081526008602090815260408083206001600160a01b0394909416835292905220805460ff60a01b198116600160a01b9182900460ff1615909102179055565b336129066000546001600160a01b031690565b6001600160a01b03161461292c5760405162461bcd60e51b8152600401610b0890614495565b600c54801580159061293d57504281105b6129595760405162461bcd60e51b8152600401610b08906144ca565b5060009081526008602090815260408083206001600160a01b0390941683529290522080546001600160a81b0319169055565b3361299f6000546001600160a01b031690565b6001600160a01b0316146129c55760405162461bcd60e51b8152600401610b0890614495565b6000600c8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611552565b33612a0f6000546001600160a01b031690565b6001600160a01b031614612a355760405162461bcd60e51b8152600401610b0890614495565b612a40600182613adf565b612a8c5760405162461bcd60e51b815260206004820152601860248201527f417574686f7269747920646f6573206e6f7420657869737400000000000000006044820152606401610b08565b604080516001600160a01b0383168152600060208201527f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c36199391016115fc565b600554600160a01b900460ff1615612af55760405162461bcd60e51b8152600401610b089061454a565b60125460041615612b185760405162461bcd60e51b8152600401610b0890614574565b60008481526007602090815260408083208a845290915290205460ff1615612b825760405162461bcd60e51b815260206004820152601d60248201527f5472616e73616374696f6e20616c72656164792070726f6365737365640000006044820152606401610b08565b60008481526008602090815260408083206001600160a01b038c8116855290835292819020815180830190925254928316808252600160a01b90930460ff1615159181019190915290612be75760405162461bcd60e51b8152600401610b08906146d9565b60008581526007602090815260408083208b84528252808320805460ff19166001179055600f5490516001600160a01b039091169291612c37918d918c918c918f918d9146918e918e91016147dc565b604051602081830303815290604052805190602001209050612c588161389f565b905060008060005b8651811015612cfa576000612c8185898481518110611b8c57611b8c614737565b9050856001600160a01b0316816001600160a01b031603612ca157600095505b6001600160a01b0381166000908152600260205260409020546001811b8115801590612ccd5750848116155b15612ce4579384179385612ce081614531565b9650505b5050508080612cf290614531565b915050612c60565b50816003541115612d475760405162461bcd60e51b815260206004820152601760248201527652657175697265206d6f7265207369676e61747572657360481b6044820152606401610b08565b6001600160a01b03841615612d6e5760405162461bcd60e51b8152600401610b089061474d565b505050506001600160a01b03891673bf6c50889d3a620eb42c0f188b65ade90de958c4148015612dbb575080516001600160a01b031673dac17f958d2ee523a2206206994597c13d831ec7145b8015612dc75750846001145b15612dde57612ddb8664e8d4a51000614703565b95505b3415612df757612df76001600160a01b03881634613971565b60135460009061271090612e0b9089614703565b612e1591906145cb565b90508015612f1657612e27818861469a565b9650601f6001600160a01b038b1611612e5557600554612e50906001600160a01b031682613971565b612ee4565b816020015115612eca576005546040516340c10f1960e01b81526001600160a01b038c8116926340c10f1992612e93929091169085906004016146c0565b600060405180830381600087803b158015612ead57600080fd5b505af1158015612ec1573d6000803e3d6000fd5b50505050612ee4565b600554612ee4906001600160a01b038c8116911683613782565b876001600160a01b03166000805160206148b88339815191528b83604051612f0d9291906146c0565b60405180910390a25b843b15158015612f2f57506001600160a01b0385163014155b156130fe57601f6001600160a01b038b1611612fba57601154604051631490ba2d60e31b81526101009091046001600160a01b03169063a485d168908990612f83908c908f9084908c908c9060040161484a565b6000604051808303818588803b158015612f9c57600080fd5b505af1158015612fb0573d6000803e3d6000fd5b50505050506131ab565b816020015115613035576011546040516340c10f1960e01b81526001600160a01b03808d16926340c10f1992612ffe92610100909204909116908b906004016146c0565b600060405180830381600087803b15801561301857600080fd5b505af115801561302c573d6000803e3d6000fd5b5050505061308b565b61303f81886146ad565b6001600160a01b038b166000908152600a60205260408120805490919061306790849061469a565b909155505060115461308b906001600160a01b038c81169161010090041689613782565b601154604051631490ba2d60e31b81526101009091046001600160a01b03169063a485d168906130c7908b908e908c908b908b9060040161484a565b600060405180830381600087803b1580156130e157600080fd5b505af11580156130f5573d6000803e3d6000fd5b505050506131ab565b601f6001600160a01b038b1611613127576131226001600160a01b03891688613971565b6131ab565b81602001511561315f576040516340c10f1960e01b81526001600160a01b038b16906340c10f19906130c7908b908b906004016146c0565b61316981886146ad565b6001600160a01b038b166000908152600a60205260408120805490919061319190849061469a565b909155506131ab90506001600160a01b038b168989613782565b815160408051898152602081018c90529081018890526001600160a01b0391821660608201528682166080820152818a16918c16907f28c02ecb5177e8f760c85b230b3c9ca9529c7412274a05918bfe438f55dd46429060a00160405180910390a350505050505050505050565b600e546001600160a01b031633148061323c57506000546001600160a01b031633145b6132945760405162461bcd60e51b815260206004820152602360248201527f4f776e61626c653a2063616c6c6572206973206e6f742074686520666f756e6460448201526265727360e81b6064820152608401610b08565b6001600160a01b0381166132f95760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b08565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b336133676000546001600160a01b031690565b6001600160a01b03161461338d5760405162461bcd60e51b8152600401610b0890614495565b600c54801580159061339e57504281105b6133ba5760405162461bcd60e51b8152600401610b08906144ca565b6001600160a01b0382166133e05760405162461bcd60e51b8152600401610b08906144f5565b600580546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527f41d2755f00068d89c23ebc6f1e73ce119a6236a44517ca061f544a3f91c9bca49101611400565b6001600160a01b03811660009081526001830160205260408120546134a457508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b038616908117909155855490825282860190935260409020919091556134a8565b5060005b92915050565b6000613514838330604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b8152606093841b60148201526f5af43d82803e903d91602b57fd5bf3ff60801b6028820152921b6038830152604c8201526037808220606c830152605591012090565b9392505050565b60008181526008602090815260408083206001600160a01b038781168552908352818420825180840190935254908116808352600160a01b90910460ff161515928201929092529061357f5760405162461bcd60e51b8152600401610b08906146d9565b805191506000601f6001600160a01b0387161161360c57348511156135d45760405162461bcd60e51b815260206004820152600b60248201526a57726f6e672076616c756560a81b6044820152606401610b08565b601454612710906135e5908261469a565b6135ef9087614703565b6135f991906145cb565b9450613605853461469a565b90506136f9565b6014546127109061361d9087614703565b61362791906145cb565b9050613633818661469a565b94508160200151156136b65760405163079cc67960e41b81526001600160a01b038716906379cc67909061366d90339089906004016146c0565b6020604051808303816000875af115801561368c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136b0919061471a565b506136f9565b6001600160a01b0386166000908152600a6020526040812080548792906136de9084906146ad565b909155506136f990506001600160a01b038716333088613c21565b801561377957601f6001600160a01b0387161161372b57600554613726906001600160a01b031682613971565b613747565b600554613747906001600160a01b038881169133911684613c21565b336001600160a01b03166000805160206148b883398151915287836040516137709291906146c0565b60405180910390a25b50509392505050565b600080846001600160a01b031663a9059cbb85856040516024016137a79291906146c0565b6040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506040516137e09190614885565b6000604051808303816000865af19150503d806000811461381d576040519150601f19603f3d011682016040523d82523d6000602084013e613822565b606091505b509150915081801561384c57508051158061384c57508080602001905181019061384c919061471a565b6138985760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610b08565b5050505050565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b60008060008061390185613d51565b6040805160008152602081018083528b905260ff8516918101919091526060810183905260808101829052929550909350915060019060a0016020604051602081039080840390855afa15801561395c573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b604080516000808252602082019092526001600160a01b03841690839060405161399b9190614885565b60006040518083038185875af1925050503d80600081146139d8576040519150601f19603f3d011682016040523d82523d6000602084013e6139dd565b606091505b5050905080613a3a5760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610b08565b505050565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b0381166134a85760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401610b08565b6001600160a01b03811660009081526001830160205260408120548015613c17576000613b0d60018361469a565b8554909150600090613b219060019061469a565b90506000866000018281548110613b3a57613b3a614737565b60009182526020909120015487546001600160a01b0390911691508190889085908110613b6957613b69614737565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055613b9d8360016146ad565b6001600160a01b03821660009081526001890160205260409020558654879080613bc957613bc96148a1565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03881682526001898101909152604082209190915594506134a89350505050565b60009150506134a8565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691613c859190614885565b6000604051808303816000865af19150503d8060008114613cc2576040519150601f19603f3d011682016040523d82523d6000602084013e613cc7565b606091505b5091509150818015613cf1575080511580613cf1575080806020019051810190613cf1919061471a565b613d495760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608401610b08565b505050505050565b60008060008351604114613d6457600080fd5b5050506020810151604082015160609092015160001a92909190565b600060208284031215613d9257600080fd5b5035919050565b6001600160a01b0381168114613dae57600080fd5b50565b60008060408385031215613dc457600080fd5b823591506020830135613dd681613d99565b809150509250929050565b600060208284031215613df357600080fd5b813561351481613d99565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715613e3c57613e3c613dfe565b604052919050565b600060408284031215613e5657600080fd5b604051604081018181106001600160401b0382111715613e7857613e78613dfe565b604052823581526020928301359281019290925250919050565b600082601f830112613ea357600080fd5b81356001600160401b03811115613ebc57613ebc613dfe565b613ecf601f8201601f1916602001613e14565b818152846020838601011115613ee457600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c08789031215613f1a57600080fd5b8635613f2581613d99565b95506020870135613f3581613d99565b945060408701359350606087013592506080870135613f5381613d99565b915060a08701356001600160401b03811115613f6e57600080fd5b613f7a89828a01613e92565b9150509295509295509295565b60008060008060808587031215613f9d57600080fd5b8435613fa881613d99565b93506020850135613fb881613d99565b93969395505050506040820135916060013590565b600080600060608486031215613fe257600080fd5b8335613fed81613d99565b95602085013595506040909401359392505050565b6000806040838503121561401557600080fd5b823561402081613d99565b91506020830135613dd681613d99565b8015158114613dae57600080fd5b6000806040838503121561405157600080fd5b823561405c81613d99565b91506020830135613dd681614030565b6000806000806060858703121561408257600080fd5b843561408d81613d99565b93506020850135925060408501356001600160401b03808211156140b057600080fd5b818701915087601f8301126140c457600080fd5b8135818111156140d357600080fd5b8860208285010111156140e557600080fd5b95989497505060200194505050565b600082601f83011261410557600080fd5b813560206001600160401b038083111561412157614121613dfe565b8260051b614130838201613e14565b938452858101830193838101908886111561414a57600080fd5b84880192505b85831015614186578235848111156141685760008081fd5b6141768a87838c0101613e92565b8352509184019190840190614150565b98975050505050505050565b60008060008060008060c087890312156141ab57600080fd5b86356141b681613d99565b95506020870135945060408701356141cd81613d99565b9350606087013592506080870135915060a08701356001600160401b038111156141f657600080fd5b613f7a89828a016140f4565b6000806040838503121561421557600080fd5b823561422081613d99565b946020939093013593505050565b6000806000806080858703121561424457600080fd5b843561424f81613d99565b9350602085013561425f81613d99565b925060408501359150606085013561427681614030565b939692955090935050565b60008060008060008060c0878903121561429a57600080fd5b86356142a581613d99565b95506020870135945060408701356001600160401b03808211156142c857600080fd5b6142d48a838b01613e92565b955060608901359150808211156142ea57600080fd5b506142f789828a01613e92565b935050608087013560ff8116811461430e57600080fd5b8092505060a087013590509295509295509295565b60008060006060848603121561433857600080fd5b833561434381613d99565b9250602084013561435381613d99565b9150604084013561436381613d99565b809150509250925092565b6020808252825182820181905260009190848201906040850190845b818110156143af5783516001600160a01b03168352928401929184019160010161438a565b50909695505050505050565b600080600080600080600080610100898b0312156143d857600080fd5b88356143e381613d99565b97506020890135965060408901356143fa81613d99565b9550606089013594506080890135935060a089013561441881613d99565b925060c08901356001600160401b038082111561443457600080fd5b6144408c838d01613e92565b935060e08b013591508082111561445657600080fd5b506144638b828c016140f4565b9150509295985092959890939650565b6000806040838503121561448657600080fd5b50508035926020909101359150565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601190820152704e6f7420696e207365747570206d6f646560781b604082015260600190565b6020808252600c908201526b5a65726f206164647265737360a01b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6000600182016145435761454361451b565b5060010190565b60208082526010908201526f213934b233b29034b990333937bd32b760811b604082015260600190565b6020808252600690820152651b1bd8dad95960d21b604082015260600190565b6020808252601a908201527f496e636f72726563742072656365697665722061646472657373000000000000604082015260600190565b6000826145e857634e487b7160e01b600052601260045260246000fd5b500490565b60005b838110156146085781810151838201526020016145f0565b50506000910152565b600081518084526146298160208601602086016145ed565b601f01601f19169290920160200192915050565b858152602081018590526001600160a01b0384811660408301528316606082015260a06080820181905260009061467690830184614611565b979650505050505050565b60006020828403121561469357600080fd5b5051919050565b818103818111156134a8576134a861451b565b808201808211156134a8576134a861451b565b6001600160a01b03929092168252602082015260400190565b60208082526010908201526f2a3432b9329034b9903737903830b4b960811b604082015260600190565b80820281158282048414176134a8576134a861451b565b60006020828403121561472c57600080fd5b815161351481614030565b634e487b7160e01b600052603260045260246000fd5b60208082526024908201527f54686520726571756972656420617574686f7269747920646f6573206e6f742060408201526339b4b3b760e11b606082015260800190565b6001600160a01b03851681526080602082018190526000906147b590830186614611565b82810360408401526147c78186614611565b91505060ff8316606083015295945050505050565b60006bffffffffffffffffffffffff19808b60601b168352808a60601b166014840152886028840152876048840152866068840152856088840152808560601b1660a88401525082516148368160bc8501602087016145ed565b9190910160bc019998505050505050505050565b6001600160a01b0386811682528581166020830152604082018590528316606082015260a06080820181905260009061467690830184614611565b600082516148978184602087016145ed565b9190910192915050565b634e487b7160e01b600052603160045260246000fdfe6ded982279c8387ad8a63e73385031a3807c1862e633f06e09d11bcb6e282f60a26469706673582212208d35c1c7cbe6154599a5b0dd8f4d4105793804aa5a8320a47991e66d09f206b264736f6c63430008130033
Deployed ByteCode
0x60806040526004361061031a5760003560e01c80636adf7412116101ab578063bfd06304116100f7578063db43968811610095578063f0f201271161006f578063f0f20127146109c6578063f2fde38b146109e6578063f46901ed14610a06578063fa08767114610a2657600080fd5b8063db4396881461094b578063df42fd361461095e578063e6074da71461099957600080fd5b8063c987c794116100d1578063c987c794146108d6578063cea9e110146108f6578063d04567f314610916578063d544e0101461092b57600080fd5b8063bfd0630414610874578063c0c53b8b14610894578063c21b4865146108b457600080fd5b80638f99523411610164578063a02a66ec1161013e578063a02a66ec146107fe578063abb718631461081e578063ad68ebf714610834578063b2e916d61461085457600080fd5b80638f9952341461078e578063960bfe04146107ae5780639af1d35a146107ce57600080fd5b80636adf7412146106d15780636b9f97ef146106eb5780636c65fd6a1461070b5780638943ec021461073b5780638da5cb5b1461075b5780638f7157011461077957600080fd5b80633f52c0f61161026a57806354cf428a116102235780635e14e319116101fd5780635e14e3191461065157806362a5af3b14610671578063685e2486146106865780636a28f000146106bc57600080fd5b806354cf428a146105f95780635c5b9f8f1461061e5780635d799f871461063157600080fd5b80633f52c0f614610567578063411b007e1461058757806342cde4e8146105a757806344ddcb60146105bd578063487cda0d146105d05780634dead732146105e357600080fd5b806326defa73116102d75780632f3a3d5d116102b15780632f3a3d5d146104d5578063384b2222146104f55780633af84ac4146105325780633cbdef561461054757600080fd5b806326defa73146104295780632a94a9c8146104495780632b1a7b581461046957600080fd5b8063017e7e581461031f578063054f7d9c1461035c57806313bf81261461038d57806316a27ecd146103b157806318d27b04146103c65780631c673ab8146103e8575b600080fd5b34801561032b57600080fd5b5060055461033f906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561036857600080fd5b5060055461037d90600160a01b900460ff1681565b6040519015158152602001610353565b34801561039957600080fd5b506103a3600c5481565b604051908152602001610353565b3480156103bd57600080fd5b5061033f610a7f565b3480156103d257600080fd5b506103e66103e1366004613d80565b610b17565b005b3480156103f457600080fd5b5061033f610403366004613db1565b60096020908152600092835260408084209091529082529020546001600160a01b031681565b34801561043557600080fd5b506103e6610444366004613de1565b610b55565b34801561045557600080fd5b506103e6610464366004613de1565b610cce565b34801561047557600080fd5b506104b6610484366004613db1565b60086020908152600092835260408084209091529082529020546001600160a01b03811690600160a01b900460ff1682565b604080516001600160a01b039093168352901515602083015201610353565b3480156104e157600080fd5b5060045461033f906001600160a01b031681565b34801561050157600080fd5b50610515610510366004613d80565b610d8a565b604080519283526001600160a01b03909116602083015201610353565b34801561053e57600080fd5b506103a3610dd1565b34801561055357600080fd5b506103e6610562366004613de1565b610de1565b34801561057357600080fd5b506103e6610582366004613e44565b610eed565b34801561059357600080fd5b50600e5461033f906001600160a01b031681565b3480156105b357600080fd5b506103a360035481565b6103e66105cb366004613f01565b610f62565b6103e66105de366004613f87565b6110ab565b3480156105ef57600080fd5b506103a360125481565b34801561060557600080fd5b5060115461033f9061010090046001600160a01b031681565b6103e661062c366004613fcd565b6111f0565b34801561063d57600080fd5b506103e661064c366004614002565b6112e9565b34801561065d57600080fd5b506103e661066c36600461403e565b61140d565b34801561067d57600080fd5b506103e66114c8565b34801561069257600080fd5b5061033f6106a1366004613de1565b6010602052600090815260409020546001600160a01b031681565b3480156106c857600080fd5b506103e661155c565b3480156106dd57600080fd5b5060115461037d9060ff1681565b3480156106f757600080fd5b506103e6610706366004613de1565b611607565b34801561071757600080fd5b5061037d610726366004613de1565b600b6020526000908152604090205460ff1681565b34801561074757600080fd5b506103e661075636600461406c565b6116ef565b34801561076757600080fd5b506000546001600160a01b031661033f565b34801561078557600080fd5b506103e6611954565b34801561079a57600080fd5b506103e66107a9366004614192565b6119cf565b3480156107ba57600080fd5b506103e66107c9366004613d80565b611f5d565b3480156107da57600080fd5b506013546014546107e9919082565b60408051928352602083019190915201610353565b34801561080a57600080fd5b506103e6610819366004613de1565b612047565b34801561082a57600080fd5b506103a360065481565b34801561084057600080fd5b506103e661084f366004614202565b6120d0565b34801561086057600080fd5b506103e661086f36600461422e565b612204565b34801561088057600080fd5b506103e661088f366004614281565b6123a0565b3480156108a057600080fd5b506103e66108af366004614323565b6126c3565b3480156108c057600080fd5b506108c96127e5565b604051610353919061436e565b3480156108e257600080fd5b506103e66108f1366004614202565b61284a565b34801561090257600080fd5b506103e6610911366004614202565b6128f3565b34801561092257600080fd5b506103e661298c565b34801561093757600080fd5b506103e6610946366004613de1565b6129fc565b6103e66109593660046143bb565b612acb565b34801561096a57600080fd5b5061037d610979366004614473565b600760209081526000928352604080842090915290825290205460ff1681565b3480156109a557600080fd5b506103a36109b4366004613de1565b600a6020526000908152604090205481565b3480156109d257600080fd5b50600f5461033f906001600160a01b031681565b3480156109f257600080fd5b506103e6610a01366004613de1565b613219565b348015610a1257600080fd5b506103e6610a21366004613de1565b613354565b348015610a3257600080fd5b50600d54610a58906001600160a01b03811690600160a01b90046001600160401b031682565b604080516001600160a01b0390931683526001600160401b03909116602083015201610353565b60408051808201909152600d546001600160a01b0381168252600160a01b90046001600160401b0316602082018190526000919042118015610aca575080516001600160a01b031615155b610b115760405162461bcd60e51b8152602060048201526013602482015272155c19dc985919481b9bdd08185b1b1bddd959606a1b60448201526064015b60405180910390fd5b51919050565b33610b2a6000546001600160a01b031690565b6001600160a01b031614610b505760405162461bcd60e51b8152600401610b0890614495565b601255565b33610b686000546001600160a01b031690565b6001600160a01b031614610b8e5760405162461bcd60e51b8152600401610b0890614495565b600c548015801590610b9f57504281105b610bbb5760405162461bcd60e51b8152600401610b08906144ca565b6001600160a01b038216610be15760405162461bcd60e51b8152600401610b08906144f5565b60ff610bec60015490565b10610c305760405162461bcd60e51b8152602060048201526014602482015273546f6f206d616e7920617574686f72697469657360601b6044820152606401610b08565b610c3b60018361343a565b610c875760405162461bcd60e51b815260206004820152601760248201527f417574686f7269747920616c72656164792061646465640000000000000000006044820152606401610b08565b604080516001600160a01b0384168152600160208201527f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c36199391015b60405180910390a15050565b33610ce16000546001600160a01b031690565b6001600160a01b031614610d075760405162461bcd60e51b8152600401610b0890614495565b600c548015801590610d1857504281105b610d345760405162461bcd60e51b8152600401610b08906144ca565b60118054610100600160a81b0319166101006001600160a01b038516908102919091179091556040519081527f850b65e0a4a0af8155b0d56212b309166a3618bcd7ba7c1e83f09f3e721f294c90602001610cc2565b60045481906000906001600160a01b03165b82610da681614531565b9350610db4905081846134ae565b915060016033609a1b031960ff60981b831601610d9c5750915091565b6000610ddc60015490565b905090565b600e546001600160a01b03163314610e3b5760405162461bcd60e51b815260206004820152601a60248201527f63616c6c6572206973206e6f742074686520666f756e646572730000000000006044820152606401610b08565b6001600160a01b038116610e915760405162461bcd60e51b815260206004820152601d60248201527f6e6577206f776e657220697320746865207a65726f20616464726573730000006044820152606401610b08565b600e546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600e80546001600160a01b0319166001600160a01b0392909216919091179055565b33610f006000546001600160a01b031690565b6001600160a01b031614610f265760405162461bcd60e51b8152600401610b0890614495565b600c548015801590610f3757504281105b610f535760405162461bcd60e51b8152600401610b08906144ca565b50805160135560200151601455565b600554600160a01b900460ff1615610f8c5760405162461bcd60e51b8152600401610b089061454a565b60125460021615610faf5760405162461bcd60e51b8152600401610b0890614574565b6001600160a01b038616610fd55760405162461bcd60e51b8152600401610b0890614594565b6000610fe286868661351b565b90506001600160a01b03861673bf6c50889d3a620eb42c0f188b65ade90de958c414801561102c57506001600160a01b03811673dac17f958d2ee523a2206206994597c13d831ec7145b80156110385750836001145b1561104f5761104c64e8d4a51000866145cb565b94505b866001600160a01b0316866001600160a01b03167f8e3af9ffa3a105195ae58520a6e3ab241268521cd0a0ca519896e650d4fbebe4878785888860405161109a95949392919061463d565b60405180910390a350505050505050565b600554600160a01b900460ff16156110d55760405162461bcd60e51b8152600401610b089061454a565b601254600116156110f85760405162461bcd60e51b8152600401610b0890614574565b6001600160a01b03841661111e5760405162461bcd60e51b8152600401610b0890614594565b600061112b84848461351b565b90506001600160a01b03841673bf6c50889d3a620eb42c0f188b65ade90de958c414801561117557506001600160a01b03811673dac17f958d2ee523a2206206994597c13d831ec7145b80156111815750816001145b156111985761119564e8d4a51000846145cb565b92505b60408051848152602081018490526001600160a01b03838116828401529151878316928716917ff5dd9317b9e63ac316ce44acc85f670b54b339cfa3e9076e1dd55065b922314b919081900360600190a35050505050565b600554600160a01b900460ff161561121a5760405162461bcd60e51b8152600401610b089061454a565b600061122784848461351b565b90506001600160a01b03841673bf6c50889d3a620eb42c0f188b65ade90de958c414801561127157506001600160a01b03811673dac17f958d2ee523a2206206994597c13d831ec7145b801561127d5750816001145b156112945761129164e8d4a51000846145cb565b92505b60408051848152602081018490526001600160a01b0383811682840152915133928716917ff5dd9317b9e63ac316ce44acc85f670b54b339cfa3e9076e1dd55065b922314b919081900360600190a350505050565b336112fc6000546001600160a01b031690565b6001600160a01b0316146113225760405162461bcd60e51b8152600401610b0890614495565b6001600160a01b0382166000818152600a60205260408082205490516370a0823160e01b8152306004820152919290916370a0823190602401602060405180830381865afa158015611378573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139c9190614681565b6113a6919061469a565b90506113bc6001600160a01b0384168383613782565b604080516001600160a01b038086168252841660208201529081018290527f2c5650189f92c7058626efc371b51fe7e71f37dacb696bc7cad0b1320931974a906060015b60405180910390a1505050565b336114206000546001600160a01b031690565b6001600160a01b0316146114465760405162461bcd60e51b8152600401610b0890614495565b6001600160a01b03821661146c5760405162461bcd60e51b8152600401610b08906144f5565b6001600160a01b0382166000818152600b6020908152604091829020805460ff19168515159081179091558251938452908301527feabe320fe7911eab2e5125ac393caa5937659b712f0c3ac43316c61d4bc088019101610cc2565b6000546001600160a01b03163314806114ef57503360009081526002602052604090205415155b806115095750336000908152600b602052604090205460ff165b61151257600080fd5b6005805460ff60a01b1916600160a01b179055604051600181527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e906020015b60405180910390a1565b3361156f6000546001600160a01b031690565b6001600160a01b0316146115955760405162461bcd60e51b8152600401610b0890614495565b600c5480158015906115a657504281105b6115c25760405162461bcd60e51b8152600401610b08906144ca565b6005805460ff60a01b19169055604051600081527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e906020015b60405180910390a150565b3361161a6000546001600160a01b031690565b6001600160a01b0316146116405760405162461bcd60e51b8152600401610b0890614495565b6001600160a01b0381166116665760405162461bcd60e51b8152600401610b08906144f5565b6000611675426203f4806146ad565b6040805180820182526001600160a01b0385168082526001600160401b0384166020909201829052600d80546001600160e01b031916909117600160a01b909202919091179055519091507fd990f8f4f90cd3307c50ab3d095cfb65516e999b7584aee60c0af83eb48118de90610cc290849084906146c0565b604081146117315760405162461bcd60e51b815260206004820152600f60248201526e496e636f7272656374205f6461746160881b6044820152606401610b08565b60008061174083850185614202565b90925090506001600160a01b03821661176b5760405162461bcd60e51b8152600401610b0890614594565b600081815260086020908152604080832033808552908352928190208151808301909252546001600160a01b038116808352600160a01b90910460ff16151592820192909252906117ce5760405162461bcd60e51b8152600401610b08906146d9565b601454600090612710906117e2908a614703565b6117ec91906145cb565b9050801561184d576117fe818961469a565b60055490985061181b906001600160a01b03858116911683613782565b886001600160a01b03166000805160206148b883398151915284836040516118449291906146c0565b60405180910390a25b8160200151156118c857604051630852cd8d60e31b8152600481018990526001600160a01b038416906342966c68906024016020604051808303816000875af115801561189e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c2919061471a565b506118f6565b6001600160a01b0383166000908152600a6020526040812080548a92906118f09084906146ad565b90915550505b8151604080518a8152602081018790526001600160a01b03928316818301529051878316928616917ff5dd9317b9e63ac316ce44acc85f670b54b339cfa3e9076e1dd55065b922314b919081900360600190a3505050505050505050565b336119676000546001600160a01b031690565b6001600160a01b03161461198d5760405162461bcd60e51b8152600401610b0890614495565b61199a42620151806146ad565b600c8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611552565b600554600160a01b900460ff16156119f95760405162461bcd60e51b8152600401610b089061454a565b600082815260076020908152604080832088845290915290205460ff1615611a635760405162461bcd60e51b815260206004820152601d60248201527f5472616e73616374696f6e20616c72656164792070726f6365737365640000006044820152606401610b08565b60008281526008602090815260408083206001600160a01b038a8116855290835292819020815180830190925254928316808252600160a01b90930460ff1615159181019190915290611ac85760405162461bcd60e51b8152600401610b08906146d9565b60008381526007602090815260408083208984528252808320805460ff19166001179055600f54905160608b811b6bffffffffffffffffffffffff199081169483019490945289901b90921660348301526048820187905260688201899052608882018690524660a88301526001600160a01b0316919060c801604051602081830303815290604052805190602001209050611b638161389f565b905060008060005b8651811015611c12576000611b9985898481518110611b8c57611b8c614737565b60200260200101516138f2565b9050856001600160a01b0316816001600160a01b031603611bb957600095505b6001600160a01b0381166000908152600260205260409020546001811b8115801590611be55750848116155b15611bfc579384179385611bf881614531565b9650505b5050508080611c0a90614531565b915050611b6b565b50816003541115611c5f5760405162461bcd60e51b815260206004820152601760248201527652657175697265206d6f7265207369676e61747572657360481b6044820152606401610b08565b6001600160a01b03841615611c865760405162461bcd60e51b8152600401610b089061474d565b6001600160a01b038b1673bf6c50889d3a620eb42c0f188b65ade90de958c4148015611ccf575084516001600160a01b031673dac17f958d2ee523a2206206994597c13d831ec7145b8015611cdb5750866001145b15611cf257611cef8864e8d4a51000614703565b97505b60135460009061271090611d06908b614703565b611d1091906145cb565b90508015611e1157611d22818a61469a565b9850601f6001600160a01b038d1611611d5057600554611d4b906001600160a01b031682613971565b611ddf565b856020015115611dc5576005546040516340c10f1960e01b81526001600160a01b038e8116926340c10f1992611d8e929091169085906004016146c0565b600060405180830381600087803b158015611da857600080fd5b505af1158015611dbc573d6000803e3d6000fd5b50505050611ddf565b600554611ddf906001600160a01b038e8116911683613782565b896001600160a01b03166000805160206148b88339815191528d83604051611e089291906146c0565b60405180910390a25b601f6001600160a01b038d1611611e3a57611e356001600160a01b038b168a613971565b611ef5565b856020015115611ea9576040516340c10f1960e01b81526001600160a01b038d16906340c10f1990611e72908d908d906004016146c0565b600060405180830381600087803b158015611e8c57600080fd5b505af1158015611ea0573d6000803e3d6000fd5b50505050611ef5565b611eb3818a6146ad565b6001600160a01b038d166000908152600a602052604081208054909190611edb90849061469a565b90915550611ef590506001600160a01b038d168b8b613782565b8551604080518b8152602081018e90529081018a90526001600160a01b039182166060820152818c16918e16907fc9e45b9f44cc745053533754942aa17989494514aeadbb624b4b5e34a0ce5fc29060800160405180910390a3505050505050505050505050565b33611f706000546001600160a01b031690565b6001600160a01b031614611f965760405162461bcd60e51b8152600401610b0890614495565b600c548015801590611fa757504281105b611fc35760405162461bcd60e51b8152600401610b08906144ca565b8115801590611fd457506001548211155b6120125760405162461bcd60e51b815260206004820152600f60248201526e15dc9bdb99c81d1a1c995cda1bdb19608a1b6044820152606401610b08565b60038290556040518281527f46e8115bf463f9c29a9424fe152addef1bfaf2b43180d19bb7c2c78cc0ff1ebf90602001610cc2565b3361205a6000546001600160a01b031690565b6001600160a01b0316146120805760405162461bcd60e51b8152600401610b0890614495565b600c54801580159061209157504281105b6120ad5760405162461bcd60e51b8152600401610b08906144ca565b50600f80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03808316600090815260106020526040902054168061212d5760405162461bcd60e51b815260206004820152601260248201527127379036b4b3b930ba34b7b7103a37b5b2b760711b6044820152606401610b08565b60405163079cc67960e41b81526001600160a01b038416906379cc67909061215b90339086906004016146c0565b6020604051808303816000875af115801561217a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061219e919061471a565b506040516340c10f1960e01b81526001600160a01b038216906340c10f19906121cd90339086906004016146c0565b600060405180830381600087803b1580156121e757600080fd5b505af11580156121fb573d6000803e3d6000fd5b50505050505050565b336122176000546001600160a01b031690565b6001600160a01b03161461223d5760405162461bcd60e51b8152600401610b0890614495565b600c54801580159061224e57504281105b61226a5760405162461bcd60e51b8152600401610b08906144ca565b60008381526008602090815260408083206001600160a01b03898116855292529091205416156122d15760405162461bcd60e51b815260206004820152601260248201527114185a5c88185b1c9958591e48195e1a5cdd60721b6044820152606401610b08565b6040805180820182526001600160a01b03868116808352851515602080850182815260008a8152600883528781208d87168083529084528882209751885493511515600160a01b026001600160a81b0319909416971696909617919091179095558885526009815285852083865281529385902080546001600160a01b0319168417905584519283529282019290925291820152606081018490527f4e37907d987e2429cd26da336a410ffe2d567dc727ed293e6c500023525af2959060800160405180910390a15050505050565b336123b36000546001600160a01b031690565b6001600160a01b0316146123d95760405162461bcd60e51b8152600401610b0890614495565b600c5480158015906123ea57504281105b6124065760405162461bcd60e51b8152600401610b08906144ca565b6001600160a01b0387166124525760405162461bcd60e51b815260206004820152601360248201527257726f6e6720746f6b656e206164647265737360681b6044820152606401610b08565b60008681526009602090815260408083206001600160a01b038b8116855292529091205416156124c45760405162461bcd60e51b815260206004820152601a60248201527f5468697320746f6b656e20616c726561647920777261707065640000000000006044820152606401610b08565b6004546000906124dd906001600160a01b031684613a3f565b9050806001600160a01b031663f6d2ee866125006000546001600160a01b031690565b8888886040518563ffffffff1660e01b81526004016125229493929190614791565b600060405180830381600087803b15801561253c57600080fd5b505af1158015612550573d6000803e3d6000fd5b505050506040518060400160405280896001600160a01b0316815260200160011515815250600860008981526020019081526020016000206000836001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548160ff021916908315150217905550905050806009600089815260200190815260200160002060008a6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055507f4e37907d987e2429cd26da336a410ffe2d567dc727ed293e6c500023525af2958160018a8a6040516126b194939291906001600160a01b039485168152921515602084015292166040820152606081019190915260800190565b60405180910390a15050505050505050565b6001600160a01b038316158015906126e357506001600160a01b03821615155b80156126f85750600e546001600160a01b0316155b61270157600080fd5b600080546001600160a01b038086166001600160a01b0319928316178355600e8054918616919092161790556040513391907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a36001600160a01b0381166127ae5760405162461bcd60e51b815260206004820152601960248201527f57726f6e6720746f6b656e496d706c656d656e746174696f6e000000000000006044820152606401610b08565b600480546001600160a01b039092166001600160a01b03199283161790556005805490911633179055505060016003819055600c55565b6060600160000180548060200260200160405190810160405280929190818152602001828054801561284057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612822575b5050505050905090565b3361285d6000546001600160a01b031690565b6001600160a01b0316146128835760405162461bcd60e51b8152600401610b0890614495565b600c54801580159061289457504281105b6128b05760405162461bcd60e51b8152600401610b08906144ca565b5060009081526008602090815260408083206001600160a01b0394909416835292905220805460ff60a01b198116600160a01b9182900460ff1615909102179055565b336129066000546001600160a01b031690565b6001600160a01b03161461292c5760405162461bcd60e51b8152600401610b0890614495565b600c54801580159061293d57504281105b6129595760405162461bcd60e51b8152600401610b08906144ca565b5060009081526008602090815260408083206001600160a01b0390941683529290522080546001600160a81b0319169055565b3361299f6000546001600160a01b031690565b6001600160a01b0316146129c55760405162461bcd60e51b8152600401610b0890614495565b6000600c8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611552565b33612a0f6000546001600160a01b031690565b6001600160a01b031614612a355760405162461bcd60e51b8152600401610b0890614495565b612a40600182613adf565b612a8c5760405162461bcd60e51b815260206004820152601860248201527f417574686f7269747920646f6573206e6f7420657869737400000000000000006044820152606401610b08565b604080516001600160a01b0383168152600060208201527f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c36199391016115fc565b600554600160a01b900460ff1615612af55760405162461bcd60e51b8152600401610b089061454a565b60125460041615612b185760405162461bcd60e51b8152600401610b0890614574565b60008481526007602090815260408083208a845290915290205460ff1615612b825760405162461bcd60e51b815260206004820152601d60248201527f5472616e73616374696f6e20616c72656164792070726f6365737365640000006044820152606401610b08565b60008481526008602090815260408083206001600160a01b038c8116855290835292819020815180830190925254928316808252600160a01b90930460ff1615159181019190915290612be75760405162461bcd60e51b8152600401610b08906146d9565b60008581526007602090815260408083208b84528252808320805460ff19166001179055600f5490516001600160a01b039091169291612c37918d918c918c918f918d9146918e918e91016147dc565b604051602081830303815290604052805190602001209050612c588161389f565b905060008060005b8651811015612cfa576000612c8185898481518110611b8c57611b8c614737565b9050856001600160a01b0316816001600160a01b031603612ca157600095505b6001600160a01b0381166000908152600260205260409020546001811b8115801590612ccd5750848116155b15612ce4579384179385612ce081614531565b9650505b5050508080612cf290614531565b915050612c60565b50816003541115612d475760405162461bcd60e51b815260206004820152601760248201527652657175697265206d6f7265207369676e61747572657360481b6044820152606401610b08565b6001600160a01b03841615612d6e5760405162461bcd60e51b8152600401610b089061474d565b505050506001600160a01b03891673bf6c50889d3a620eb42c0f188b65ade90de958c4148015612dbb575080516001600160a01b031673dac17f958d2ee523a2206206994597c13d831ec7145b8015612dc75750846001145b15612dde57612ddb8664e8d4a51000614703565b95505b3415612df757612df76001600160a01b03881634613971565b60135460009061271090612e0b9089614703565b612e1591906145cb565b90508015612f1657612e27818861469a565b9650601f6001600160a01b038b1611612e5557600554612e50906001600160a01b031682613971565b612ee4565b816020015115612eca576005546040516340c10f1960e01b81526001600160a01b038c8116926340c10f1992612e93929091169085906004016146c0565b600060405180830381600087803b158015612ead57600080fd5b505af1158015612ec1573d6000803e3d6000fd5b50505050612ee4565b600554612ee4906001600160a01b038c8116911683613782565b876001600160a01b03166000805160206148b88339815191528b83604051612f0d9291906146c0565b60405180910390a25b843b15158015612f2f57506001600160a01b0385163014155b156130fe57601f6001600160a01b038b1611612fba57601154604051631490ba2d60e31b81526101009091046001600160a01b03169063a485d168908990612f83908c908f9084908c908c9060040161484a565b6000604051808303818588803b158015612f9c57600080fd5b505af1158015612fb0573d6000803e3d6000fd5b50505050506131ab565b816020015115613035576011546040516340c10f1960e01b81526001600160a01b03808d16926340c10f1992612ffe92610100909204909116908b906004016146c0565b600060405180830381600087803b15801561301857600080fd5b505af115801561302c573d6000803e3d6000fd5b5050505061308b565b61303f81886146ad565b6001600160a01b038b166000908152600a60205260408120805490919061306790849061469a565b909155505060115461308b906001600160a01b038c81169161010090041689613782565b601154604051631490ba2d60e31b81526101009091046001600160a01b03169063a485d168906130c7908b908e908c908b908b9060040161484a565b600060405180830381600087803b1580156130e157600080fd5b505af11580156130f5573d6000803e3d6000fd5b505050506131ab565b601f6001600160a01b038b1611613127576131226001600160a01b03891688613971565b6131ab565b81602001511561315f576040516340c10f1960e01b81526001600160a01b038b16906340c10f19906130c7908b908b906004016146c0565b61316981886146ad565b6001600160a01b038b166000908152600a60205260408120805490919061319190849061469a565b909155506131ab90506001600160a01b038b168989613782565b815160408051898152602081018c90529081018890526001600160a01b0391821660608201528682166080820152818a16918c16907f28c02ecb5177e8f760c85b230b3c9ca9529c7412274a05918bfe438f55dd46429060a00160405180910390a350505050505050505050565b600e546001600160a01b031633148061323c57506000546001600160a01b031633145b6132945760405162461bcd60e51b815260206004820152602360248201527f4f776e61626c653a2063616c6c6572206973206e6f742074686520666f756e6460448201526265727360e81b6064820152608401610b08565b6001600160a01b0381166132f95760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b08565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b336133676000546001600160a01b031690565b6001600160a01b03161461338d5760405162461bcd60e51b8152600401610b0890614495565b600c54801580159061339e57504281105b6133ba5760405162461bcd60e51b8152600401610b08906144ca565b6001600160a01b0382166133e05760405162461bcd60e51b8152600401610b08906144f5565b600580546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527f41d2755f00068d89c23ebc6f1e73ce119a6236a44517ca061f544a3f91c9bca49101611400565b6001600160a01b03811660009081526001830160205260408120546134a457508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b038616908117909155855490825282860190935260409020919091556134a8565b5060005b92915050565b6000613514838330604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b8152606093841b60148201526f5af43d82803e903d91602b57fd5bf3ff60801b6028820152921b6038830152604c8201526037808220606c830152605591012090565b9392505050565b60008181526008602090815260408083206001600160a01b038781168552908352818420825180840190935254908116808352600160a01b90910460ff161515928201929092529061357f5760405162461bcd60e51b8152600401610b08906146d9565b805191506000601f6001600160a01b0387161161360c57348511156135d45760405162461bcd60e51b815260206004820152600b60248201526a57726f6e672076616c756560a81b6044820152606401610b08565b601454612710906135e5908261469a565b6135ef9087614703565b6135f991906145cb565b9450613605853461469a565b90506136f9565b6014546127109061361d9087614703565b61362791906145cb565b9050613633818661469a565b94508160200151156136b65760405163079cc67960e41b81526001600160a01b038716906379cc67909061366d90339089906004016146c0565b6020604051808303816000875af115801561368c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136b0919061471a565b506136f9565b6001600160a01b0386166000908152600a6020526040812080548792906136de9084906146ad565b909155506136f990506001600160a01b038716333088613c21565b801561377957601f6001600160a01b0387161161372b57600554613726906001600160a01b031682613971565b613747565b600554613747906001600160a01b038881169133911684613c21565b336001600160a01b03166000805160206148b883398151915287836040516137709291906146c0565b60405180910390a25b50509392505050565b600080846001600160a01b031663a9059cbb85856040516024016137a79291906146c0565b6040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506040516137e09190614885565b6000604051808303816000865af19150503d806000811461381d576040519150601f19603f3d011682016040523d82523d6000602084013e613822565b606091505b509150915081801561384c57508051158061384c57508080602001905181019061384c919061471a565b6138985760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610b08565b5050505050565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b60008060008061390185613d51565b6040805160008152602081018083528b905260ff8516918101919091526060810183905260808101829052929550909350915060019060a0016020604051602081039080840390855afa15801561395c573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b604080516000808252602082019092526001600160a01b03841690839060405161399b9190614885565b60006040518083038185875af1925050503d80600081146139d8576040519150601f19603f3d011682016040523d82523d6000602084013e6139dd565b606091505b5050905080613a3a5760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610b08565b505050565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b0381166134a85760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401610b08565b6001600160a01b03811660009081526001830160205260408120548015613c17576000613b0d60018361469a565b8554909150600090613b219060019061469a565b90506000866000018281548110613b3a57613b3a614737565b60009182526020909120015487546001600160a01b0390911691508190889085908110613b6957613b69614737565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055613b9d8360016146ad565b6001600160a01b03821660009081526001890160205260409020558654879080613bc957613bc96148a1565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03881682526001898101909152604082209190915594506134a89350505050565b60009150506134a8565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691613c859190614885565b6000604051808303816000865af19150503d8060008114613cc2576040519150601f19603f3d011682016040523d82523d6000602084013e613cc7565b606091505b5091509150818015613cf1575080511580613cf1575080806020019051810190613cf1919061471a565b613d495760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608401610b08565b505050505050565b60008060008351604114613d6457600080fd5b5050506020810151604082015160609092015160001a92909190565b600060208284031215613d9257600080fd5b5035919050565b6001600160a01b0381168114613dae57600080fd5b50565b60008060408385031215613dc457600080fd5b823591506020830135613dd681613d99565b809150509250929050565b600060208284031215613df357600080fd5b813561351481613d99565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715613e3c57613e3c613dfe565b604052919050565b600060408284031215613e5657600080fd5b604051604081018181106001600160401b0382111715613e7857613e78613dfe565b604052823581526020928301359281019290925250919050565b600082601f830112613ea357600080fd5b81356001600160401b03811115613ebc57613ebc613dfe565b613ecf601f8201601f1916602001613e14565b818152846020838601011115613ee457600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c08789031215613f1a57600080fd5b8635613f2581613d99565b95506020870135613f3581613d99565b945060408701359350606087013592506080870135613f5381613d99565b915060a08701356001600160401b03811115613f6e57600080fd5b613f7a89828a01613e92565b9150509295509295509295565b60008060008060808587031215613f9d57600080fd5b8435613fa881613d99565b93506020850135613fb881613d99565b93969395505050506040820135916060013590565b600080600060608486031215613fe257600080fd5b8335613fed81613d99565b95602085013595506040909401359392505050565b6000806040838503121561401557600080fd5b823561402081613d99565b91506020830135613dd681613d99565b8015158114613dae57600080fd5b6000806040838503121561405157600080fd5b823561405c81613d99565b91506020830135613dd681614030565b6000806000806060858703121561408257600080fd5b843561408d81613d99565b93506020850135925060408501356001600160401b03808211156140b057600080fd5b818701915087601f8301126140c457600080fd5b8135818111156140d357600080fd5b8860208285010111156140e557600080fd5b95989497505060200194505050565b600082601f83011261410557600080fd5b813560206001600160401b038083111561412157614121613dfe565b8260051b614130838201613e14565b938452858101830193838101908886111561414a57600080fd5b84880192505b85831015614186578235848111156141685760008081fd5b6141768a87838c0101613e92565b8352509184019190840190614150565b98975050505050505050565b60008060008060008060c087890312156141ab57600080fd5b86356141b681613d99565b95506020870135945060408701356141cd81613d99565b9350606087013592506080870135915060a08701356001600160401b038111156141f657600080fd5b613f7a89828a016140f4565b6000806040838503121561421557600080fd5b823561422081613d99565b946020939093013593505050565b6000806000806080858703121561424457600080fd5b843561424f81613d99565b9350602085013561425f81613d99565b925060408501359150606085013561427681614030565b939692955090935050565b60008060008060008060c0878903121561429a57600080fd5b86356142a581613d99565b95506020870135945060408701356001600160401b03808211156142c857600080fd5b6142d48a838b01613e92565b955060608901359150808211156142ea57600080fd5b506142f789828a01613e92565b935050608087013560ff8116811461430e57600080fd5b8092505060a087013590509295509295509295565b60008060006060848603121561433857600080fd5b833561434381613d99565b9250602084013561435381613d99565b9150604084013561436381613d99565b809150509250925092565b6020808252825182820181905260009190848201906040850190845b818110156143af5783516001600160a01b03168352928401929184019160010161438a565b50909695505050505050565b600080600080600080600080610100898b0312156143d857600080fd5b88356143e381613d99565b97506020890135965060408901356143fa81613d99565b9550606089013594506080890135935060a089013561441881613d99565b925060c08901356001600160401b038082111561443457600080fd5b6144408c838d01613e92565b935060e08b013591508082111561445657600080fd5b506144638b828c016140f4565b9150509295985092959890939650565b6000806040838503121561448657600080fd5b50508035926020909101359150565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601190820152704e6f7420696e207365747570206d6f646560781b604082015260600190565b6020808252600c908201526b5a65726f206164647265737360a01b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6000600182016145435761454361451b565b5060010190565b60208082526010908201526f213934b233b29034b990333937bd32b760811b604082015260600190565b6020808252600690820152651b1bd8dad95960d21b604082015260600190565b6020808252601a908201527f496e636f72726563742072656365697665722061646472657373000000000000604082015260600190565b6000826145e857634e487b7160e01b600052601260045260246000fd5b500490565b60005b838110156146085781810151838201526020016145f0565b50506000910152565b600081518084526146298160208601602086016145ed565b601f01601f19169290920160200192915050565b858152602081018590526001600160a01b0384811660408301528316606082015260a06080820181905260009061467690830184614611565b979650505050505050565b60006020828403121561469357600080fd5b5051919050565b818103818111156134a8576134a861451b565b808201808211156134a8576134a861451b565b6001600160a01b03929092168252602082015260400190565b60208082526010908201526f2a3432b9329034b9903737903830b4b960811b604082015260600190565b80820281158282048414176134a8576134a861451b565b60006020828403121561472c57600080fd5b815161351481614030565b634e487b7160e01b600052603260045260246000fd5b60208082526024908201527f54686520726571756972656420617574686f7269747920646f6573206e6f742060408201526339b4b3b760e11b606082015260800190565b6001600160a01b03851681526080602082018190526000906147b590830186614611565b82810360408401526147c78186614611565b91505060ff8316606083015295945050505050565b60006bffffffffffffffffffffffff19808b60601b168352808a60601b166014840152886028840152876048840152866068840152856088840152808560601b1660a88401525082516148368160bc8501602087016145ed565b9190910160bc019998505050505050505050565b6001600160a01b0386811682528581166020830152604082018590528316606082015260a06080820181905260009061467690830184614611565b600082516148978184602087016145ed565b9190910192915050565b634e487b7160e01b600052603160045260246000fdfe6ded982279c8387ad8a63e73385031a3807c1862e633f06e09d11bcb6e282f60a26469706673582212208d35c1c7cbe6154599a5b0dd8f4d4105793804aa5a8320a47991e66d09f206b264736f6c63430008130033