Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
18389966 | 457 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
AxelarGateway
Compiler Version
v0.8.9+commit.e5eed63a
Optimization Enabled:
Yes with 1000 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol'; import { IImplementation } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IImplementation.sol'; import { IContractIdentifier } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IContractIdentifier.sol'; import { IAxelarGateway } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol'; import { SafeTokenCall, SafeTokenTransfer, SafeTokenTransferFrom } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol'; import { ContractAddress } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/ContractAddress.sol'; import { Implementation } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradable/Implementation.sol'; import { IAxelarAuth } from './interfaces/IAxelarAuth.sol'; import { IBurnableMintableCappedERC20 } from './interfaces/IBurnableMintableCappedERC20.sol'; import { ITokenDeployer } from './interfaces/ITokenDeployer.sol'; import { ECDSA } from './ECDSA.sol'; import { DepositHandler } from './DepositHandler.sol'; import { EternalStorage } from './EternalStorage.sol'; /** * @title AxelarGateway Contract * @notice This contract serves as the gateway for cross-chain contract calls, * and token transfers within the Axelar network. * It includes functions for sending tokens, calling contracts, and validating contract calls. * The contract is managed via the decentralized governance mechanism on the Axelar network. * @dev EternalStorage is used to simplify storage for upgradability, and InterchainGovernance module is used for governance. */ contract AxelarGateway is IAxelarGateway, Implementation, EternalStorage { using SafeTokenCall for IERC20; using SafeTokenTransfer for IERC20; using SafeTokenTransferFrom for IERC20; using ContractAddress for address; error InvalidImplementation(); enum TokenType { InternalBurnable, InternalBurnableFrom, External } /** * @dev Deprecated slots. Should not be reused. */ // bytes32 internal constant KEY_ALL_TOKENS_FROZEN = keccak256('all-tokens-frozen'); // bytes32 internal constant PREFIX_TOKEN_FROZEN = keccak256('token-frozen'); /** * @dev Storage slot with the address of the current implementation. `keccak256('eip1967.proxy.implementation') - 1`. */ bytes32 internal constant KEY_IMPLEMENTATION = bytes32(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc); /** * @dev Storage slot with the address of the current governance. keccak256('governance')) - 1 */ bytes32 internal constant KEY_GOVERNANCE = bytes32(0xabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f909); /** * @dev Storage slot with the address of the current mint limiter. keccak256('mint-limiter')) - 1 */ bytes32 internal constant KEY_MINT_LIMITER = bytes32(0x627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d92); bytes32 internal constant PREFIX_COMMAND_EXECUTED = keccak256('command-executed'); bytes32 internal constant PREFIX_TOKEN_ADDRESS = keccak256('token-address'); bytes32 internal constant PREFIX_TOKEN_TYPE = keccak256('token-type'); bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED = keccak256('contract-call-approved'); bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED_WITH_MINT = keccak256('contract-call-approved-with-mint'); bytes32 internal constant PREFIX_TOKEN_MINT_LIMIT = keccak256('token-mint-limit'); bytes32 internal constant PREFIX_TOKEN_MINT_AMOUNT = keccak256('token-mint-amount'); bytes32 internal constant SELECTOR_BURN_TOKEN = keccak256('burnToken'); bytes32 internal constant SELECTOR_DEPLOY_TOKEN = keccak256('deployToken'); bytes32 internal constant SELECTOR_MINT_TOKEN = keccak256('mintToken'); bytes32 internal constant SELECTOR_APPROVE_CONTRACT_CALL = keccak256('approveContractCall'); bytes32 internal constant SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT = keccak256('approveContractCallWithMint'); bytes32 internal constant SELECTOR_TRANSFER_OPERATORSHIP = keccak256('transferOperatorship'); address public immutable authModule; address public immutable tokenDeployer; /** * @notice Constructs the AxelarGateway contract. * @param authModule_ The address of the authentication module * @param tokenDeployer_ The address of the token deployer */ constructor(address authModule_, address tokenDeployer_) { if (authModule_.code.length == 0) revert InvalidAuthModule(); if (tokenDeployer_.code.length == 0) revert InvalidTokenDeployer(); authModule = authModule_; tokenDeployer = tokenDeployer_; } /** * @notice Ensures that the caller of the function is the gateway contract itself. */ modifier onlySelf() { if (msg.sender != address(this)) revert NotSelf(); _; } /** * @notice Ensures that the caller of the function is the governance address. */ modifier onlyGovernance() { if (msg.sender != getAddress(KEY_GOVERNANCE)) revert NotGovernance(); _; } /** * @notice Ensures that the caller of the function is either the mint limiter or governance. */ modifier onlyMintLimiter() { if (msg.sender != getAddress(KEY_MINT_LIMITER) && msg.sender != getAddress(KEY_GOVERNANCE)) revert NotMintLimiter(); _; } /******************\ |* Public Methods *| \******************/ /** * @notice Send the specified token to the destination chain and address. * @param destinationChain The chain to send tokens to. A registered chain name on Axelar must be used here * @param destinationAddress The address on the destination chain to send tokens to * @param symbol The symbol of the token to send * @param amount The amount of tokens to send */ function sendToken( string calldata destinationChain, string calldata destinationAddress, string calldata symbol, uint256 amount ) external { _burnTokenFrom(msg.sender, symbol, amount); emit TokenSent(msg.sender, destinationChain, destinationAddress, symbol, amount); } /** * @notice Calls a contract on the specified destination chain with a given payload. * This function is the entry point for general message passing between chains. * @param destinationChain The chain where the destination contract exists. A registered chain name on Axelar must be used here * @param destinationContractAddress The address of the contract to call on the destination chain * @param payload The payload to be sent to the destination contract, usually representing an encoded function call with arguments */ function callContract( string calldata destinationChain, string calldata destinationContractAddress, bytes calldata payload ) external { emit ContractCall(msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload); } /** * @notice Calls a contract on the specified destination chain with a given payload and token amount. * This function is the entry point for general message passing with token transfer between chains. * @param destinationChain The chain where the destination contract exists. A registered chain name on Axelar must be used here * @param destinationContractAddress The address of the contract to call with tokens on the destination chain * @param payload The payload to be sent to the destination contract, usually representing an encoded function call with arguments * @param symbol The symbol of the token to be sent with the call * @param amount The amount of tokens to be sent with the call */ function callContractWithToken( string calldata destinationChain, string calldata destinationContractAddress, bytes calldata payload, string calldata symbol, uint256 amount ) external { _burnTokenFrom(msg.sender, symbol, amount); emit ContractCallWithToken(msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload, symbol, amount); } /** * @notice Checks whether a contract call has been approved by the gateway. * @param commandId The gateway command ID * @param sourceChain The source chain of the contract call * @param sourceAddress The source address of the contract call * @param contractAddress The contract address that will be called * @param payloadHash The hash of the payload for that will be sent with the call * @return bool A boolean value indicating whether the contract call has been approved by the gateway. */ function isContractCallApproved( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, address contractAddress, bytes32 payloadHash ) external view override returns (bool) { return getBool(_getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash)); } /** * @notice Checks whether a contract call with token has been approved by the gateway. * @param commandId The gateway command ID * @param sourceChain The source chain of the contract call * @param sourceAddress The source address of the contract call * @param contractAddress The contract address that will be called, and where tokens will be sent * @param payloadHash The hash of the payload for that will be sent with the call * @param symbol The symbol of the token to be sent with the call * @param amount The amount of tokens to be sent with the call * @return bool A boolean value indicating whether the contract call with token has been approved by the gateway. */ function isContractCallAndMintApproved( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, address contractAddress, bytes32 payloadHash, string calldata symbol, uint256 amount ) external view override returns (bool) { return getBool( _getIsContractCallApprovedWithMintKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount) ); } /** * @notice Called on the destination chain gateway by the recipient of the cross-chain contract call to validate it and only allow execution * if this function returns true. * @dev Once validated, the gateway marks the message as executed so the contract call is not executed twice. * @param commandId The gateway command ID * @param sourceChain The source chain of the contract call * @param sourceAddress The source address of the contract call * @param payloadHash The hash of the payload for that will be sent with the call * @return valid True if the contract call is approved, false otherwise */ function validateContractCall( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes32 payloadHash ) external override returns (bool valid) { bytes32 key = _getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, msg.sender, payloadHash); valid = getBool(key); if (valid) { _setBool(key, false); emit ContractCallExecuted(commandId); } } /** * @notice Called on the destination chain gateway to validate the approval of a contract call with token transfer and only * allow execution if this function returns true. * @dev Once validated, the gateway marks the message as executed so the contract call with token is not executed twice. * @param commandId The gateway command ID * @param sourceChain The source chain of the contract call * @param sourceAddress The source address of the contract call * @param payloadHash The hash of the payload for that will be sent with the call * @param symbol The symbol of the token to be sent with the call * @param amount The amount of tokens to be sent with the call * @return valid True if the contract call with token is approved, false otherwise */ function validateContractCallAndMint( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes32 payloadHash, string calldata symbol, uint256 amount ) external override returns (bool valid) { bytes32 key = _getIsContractCallApprovedWithMintKey(commandId, sourceChain, sourceAddress, msg.sender, payloadHash, symbol, amount); valid = getBool(key); if (valid) { // Prevent re-entrancy _setBool(key, false); emit ContractCallExecuted(commandId); _mintToken(symbol, msg.sender, amount); } } /***********\ |* Getters *| \***********/ /** * @notice Gets the address of governance, should be the address of InterchainGovernance. * @return address The address of governance. */ function governance() public view override returns (address) { return getAddress(KEY_GOVERNANCE); } /** * @notice Gets the address of the mint limiter, should be the address of Multisig. * @return address The address of the mint limiter. */ function mintLimiter() public view override returns (address) { return getAddress(KEY_MINT_LIMITER); } /** * @notice Gets the transfer limit for a specific token symbol within the configured epoch. * @param symbol The symbol of the token * @return uint The transfer limit for the given token. */ function tokenMintLimit(string memory symbol) public view override returns (uint256) { return getUint(_getTokenMintLimitKey(symbol)); } /** * @notice Gets the transfer amount for a specific token symbol within the configured epoch. * @param symbol The symbol of the token * @return uint The transfer amount for the given token. */ function tokenMintAmount(string memory symbol) public view override returns (uint256) { return getUint(_getTokenMintAmountKey(symbol, block.timestamp / 6 hours)); } /** * @dev This function is kept around to keep things working for internal * tokens that were deployed before the token freeze functionality was removed */ function allTokensFrozen() external pure override returns (bool) { return false; } /** * @notice Gets the address of the gateway implementation contract. * @return address The address of the gateway implementation. */ function implementation() public view override returns (address) { return getAddress(KEY_IMPLEMENTATION); } /** * @notice Gets the address of a specific token using its symbol. * @param symbol The symbol of the token * @return address The address of the token associated with the given symbol. */ function tokenAddresses(string memory symbol) public view override returns (address) { return getAddress(_getTokenAddressKey(symbol)); } /** * @dev Deprecated. This function is kept around to keep things working for internal tokens that were deployed before the token freeze functionality was removed */ function tokenFrozen(string memory) external pure override returns (bool) { return false; } /** * @notice Checks whether a command with a given command ID has been executed. * @param commandId The command ID to check * @return bool True if the command has been executed, false otherwise */ function isCommandExecuted(bytes32 commandId) public view override returns (bool) { return getBool(_getIsCommandExecutedKey(commandId)); } /** * @notice Gets the contract ID of the Axelar Gateway. * @return bytes32 The keccak256 hash of the string 'axelar-gateway' */ function contractId() public pure returns (bytes32) { return keccak256('axelar-gateway'); } /************************\ |* Governance Functions *| \************************/ /** * @notice Transfers the governance role to a new address. * @param newGovernance The address to transfer the governance role to. * @dev Only the current governance entity can call this function. */ function transferGovernance(address newGovernance) external override onlyGovernance { if (newGovernance == address(0)) revert InvalidGovernance(); _transferGovernance(newGovernance); } /** * @notice Transfers the mint limiter role to a new address. * @param newMintLimiter The address to transfer the mint limiter role to. * @dev Only the current mint limiter or the governance address can call this function. */ function transferMintLimiter(address newMintLimiter) external override onlyMintLimiter { if (newMintLimiter == address(0)) revert InvalidMintLimiter(); _transferMintLimiter(newMintLimiter); } /** * @notice Sets the transfer limits for an array of tokens. * @param symbols The array of token symbols to set the transfer limits for * @param limits The array of transfer limits corresponding to the symbols * @dev Only the mint limiter or the governance address can call this function. */ function setTokenMintLimits(string[] calldata symbols, uint256[] calldata limits) external override onlyMintLimiter { uint256 length = symbols.length; if (length != limits.length) revert InvalidSetMintLimitsParams(); for (uint256 i; i < length; ++i) { string memory symbol = symbols[i]; uint256 limit = limits[i]; if (tokenAddresses(symbol) == address(0)) revert TokenDoesNotExist(symbol); _setTokenMintLimit(symbol, limit); } } /** * @notice Upgrades the contract to a new implementation. * @param newImplementation The address of the new implementation * @param newImplementationCodeHash The code hash of the new implementation * @param setupParams Optional setup params for the new implementation * @dev Only the governance address can call this function. */ function upgrade( address newImplementation, bytes32 newImplementationCodeHash, bytes calldata setupParams ) external override onlyGovernance { if (newImplementationCodeHash != newImplementation.codehash) revert InvalidCodeHash(); if (contractId() != IContractIdentifier(newImplementation).contractId()) revert InvalidImplementation(); emit Upgraded(newImplementation); _setImplementation(newImplementation); if (setupParams.length != 0) { // slither-disable-next-line controlled-delegatecall (bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(IImplementation.setup.selector, setupParams)); if (!success) revert SetupFailed(); } } /**********************\ |* External Functions *| \**********************/ /** * @notice Sets up the governance and mint limiter roles, and transfers operatorship if necessary. * This function is called by the proxy during initial deployment, and optionally called during gateway upgrades. * @param params The encoded parameters containing the governance and mint limiter addresses, as well as the new operator data. * @dev Not publicly accessible as it's overshadowed in the proxy. */ function setup(bytes calldata params) external override(IImplementation, Implementation) onlyProxy { (address governance_, address mintLimiter_, bytes memory newOperatorsData) = abi.decode(params, (address, address, bytes)); if (governance_ != address(0)) _transferGovernance(governance_); if (mintLimiter_ != address(0)) _transferMintLimiter(mintLimiter_); if (newOperatorsData.length != 0) { emit OperatorshipTransferred(newOperatorsData); IAxelarAuth(authModule).transferOperatorship(newOperatorsData); } } /** * @notice Executes a batch of commands signed by the Axelar network. There are a finite set of command types that can be executed. * @param input The encoded input containing the data for the batch of commands, as well as the proof that verifies the integrity of the data. * @dev Each command has a corresponding commandID that is guaranteed to be unique from the Axelar network. * @dev This function allows retrying a commandID if the command initially failed to be processed. * @dev Ignores unknown commands or duplicate commandIDs. * @dev Emits an Executed event for successfully executed commands. */ // slither-disable-next-line cyclomatic-complexity function execute(bytes calldata input) external override { (bytes memory data, bytes memory proof) = abi.decode(input, (bytes, bytes)); bytes32 messageHash = ECDSA.toEthSignedMessageHash(keccak256(data)); // returns true for current operators // slither-disable-next-line reentrancy-no-eth bool allowOperatorshipTransfer = IAxelarAuth(authModule).validateProof(messageHash, proof); uint256 chainId; bytes32[] memory commandIds; string[] memory commands; bytes[] memory params; (chainId, commandIds, commands, params) = abi.decode(data, (uint256, bytes32[], string[], bytes[])); if (chainId != block.chainid) revert InvalidChainId(); uint256 commandsLength = commandIds.length; if (commandsLength != commands.length || commandsLength != params.length) revert InvalidCommands(); for (uint256 i; i < commandsLength; ++i) { bytes32 commandId = commandIds[i]; // Ignore if duplicate commandId received if (isCommandExecuted(commandId)) continue; bytes4 commandSelector; bytes32 commandHash = keccak256(abi.encodePacked(commands[i])); if (commandHash == SELECTOR_DEPLOY_TOKEN) { commandSelector = AxelarGateway.deployToken.selector; } else if (commandHash == SELECTOR_MINT_TOKEN) { commandSelector = AxelarGateway.mintToken.selector; } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL) { commandSelector = AxelarGateway.approveContractCall.selector; } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT) { commandSelector = AxelarGateway.approveContractCallWithMint.selector; } else if (commandHash == SELECTOR_BURN_TOKEN) { commandSelector = AxelarGateway.burnToken.selector; } else if (commandHash == SELECTOR_TRANSFER_OPERATORSHIP) { if (!allowOperatorshipTransfer) continue; allowOperatorshipTransfer = false; commandSelector = AxelarGateway.transferOperatorship.selector; } else { // Ignore unknown commands continue; } // Prevent a re-entrancy from executing this command before it can be marked as successful. _setCommandExecuted(commandId, true); // slither-disable-next-line calls-loop,reentrancy-no-eth (bool success, ) = address(this).call(abi.encodeWithSelector(commandSelector, params[i], commandId)); // slither-disable-next-line reentrancy-events if (success) emit Executed(commandId); else _setCommandExecuted(commandId, false); } } /******************\ |* Self Functions *| \******************/ /** * @notice Deploys a new token or registers an existing token in the gateway contract itself. * @param params Encoded parameters including the token name, symbol, decimals, cap, token address, and mint limit * @dev If the token address is not specified, a new token is deployed and registed as InternalBurnableFrom * @dev If the token address is specified, the token is marked as External. * @dev Emits a TokenDeployed event with the symbol and token address. */ function deployToken(bytes calldata params, bytes32) external onlySelf { (string memory name, string memory symbol, uint8 decimals, uint256 cap, address tokenAddress, uint256 mintLimit) = abi.decode( params, (string, string, uint8, uint256, address, uint256) ); // Ensure that this symbol has not been taken. if (tokenAddresses(symbol) != address(0)) revert TokenAlreadyExists(symbol); _setTokenMintLimit(symbol, mintLimit); if (tokenAddress == address(0)) { // If token address is not specified, it indicates a request to deploy one. bytes32 salt = keccak256(abi.encodePacked(symbol)); _setTokenType(symbol, TokenType.InternalBurnableFrom); // slither-disable-next-line reentrancy-no-eth,controlled-delegatecall (bool success, bytes memory data) = tokenDeployer.delegatecall( abi.encodeWithSelector(ITokenDeployer.deployToken.selector, name, symbol, decimals, cap, salt) ); if (!success) revert TokenDeployFailed(symbol); tokenAddress = abi.decode(data, (address)); } else { // If token address is specified, ensure that there is a contact at the specified address. if (tokenAddress.code.length == uint256(0)) revert TokenContractDoesNotExist(tokenAddress); // Mark that this symbol is an external token, which is needed to differentiate between operations on mint and burn. _setTokenType(symbol, TokenType.External); } // slither-disable-next-line reentrancy-events emit TokenDeployed(symbol, tokenAddress); _setTokenAddress(symbol, tokenAddress); } /** * @notice Transfers a specific amount of tokens to an account, based on the provided symbol. * @param params Encoded parameters including the token symbol, recipient address, and amount to mint. * @dev This function will revert if the token is not registered with the gatewaty. * @dev If the token type is External, a safe transfer is performed to the recipient account. * @dev If the token type is Internal (InternalBurnable or InternalBurnableFrom), the mint function is called on the token address. */ function mintToken(bytes calldata params, bytes32) external onlySelf { (string memory symbol, address account, uint256 amount) = abi.decode(params, (string, address, uint256)); _mintToken(symbol, account, amount); } /** * @notice Burns tokens of a given symbol, either through an external deposit handler or a token defined burn method. * @param params Encoded parameters including the token symbol and a salt value for the deposit handler */ function burnToken(bytes calldata params, bytes32) external onlySelf { (string memory symbol, bytes32 salt) = abi.decode(params, (string, bytes32)); address tokenAddress = tokenAddresses(symbol); if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol); if (_getTokenType(symbol) == TokenType.External) { address depositHandlerAddress = _getCreate2Address(salt, keccak256(abi.encodePacked(type(DepositHandler).creationCode))); if (depositHandlerAddress.isContract()) return; DepositHandler depositHandler = new DepositHandler{ salt: salt }(); (bool success, bytes memory returnData) = depositHandler.execute( tokenAddress, abi.encodeWithSelector(IERC20.transfer.selector, address(this), IERC20(tokenAddress).balanceOf(address(depositHandler))) ); if (!success || (returnData.length != uint256(0) && !abi.decode(returnData, (bool)))) revert BurnFailed(symbol); // NOTE: `depositHandler` must always be destroyed in the same runtime context that it is deployed. depositHandler.destroy(address(this)); } else { IBurnableMintableCappedERC20(tokenAddress).burn(salt); } } /** * @notice Approves a contract call. * @param params Encoded parameters including the source chain, source address, contract address, payload hash, transaction hash, and event index * @param commandId to associate with the approval */ function approveContractCall(bytes calldata params, bytes32 commandId) external onlySelf { ( string memory sourceChain, string memory sourceAddress, address contractAddress, bytes32 payloadHash, bytes32 sourceTxHash, uint256 sourceEventIndex ) = abi.decode(params, (string, string, address, bytes32, bytes32, uint256)); _setContractCallApproved(commandId, sourceChain, sourceAddress, contractAddress, payloadHash); emit ContractCallApproved(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, sourceTxHash, sourceEventIndex); } /** * @notice Approves a contract call with token transfer. * @param params Encoded parameters including the source chain, source address, contract address, payload hash, token symbol, * token amount, transaction hash, and event index. * @param commandId to associate with the approval */ function approveContractCallWithMint(bytes calldata params, bytes32 commandId) external onlySelf { ( string memory sourceChain, string memory sourceAddress, address contractAddress, bytes32 payloadHash, string memory symbol, uint256 amount, bytes32 sourceTxHash, uint256 sourceEventIndex ) = abi.decode(params, (string, string, address, bytes32, string, uint256, bytes32, uint256)); _setContractCallApprovedWithMint(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount); emit ContractCallApprovedWithMint( commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount, sourceTxHash, sourceEventIndex ); } /** * @notice Transfers operatorship with the provided data by calling the transferOperatorship function on the auth module. * @param newOperatorsData Encoded data for the new operators */ function transferOperatorship(bytes calldata newOperatorsData, bytes32) external onlySelf { emit OperatorshipTransferred(newOperatorsData); IAxelarAuth(authModule).transferOperatorship(newOperatorsData); } /********************\ |* Internal Methods *| \********************/ function _mintToken( string memory symbol, address account, uint256 amount ) internal { address tokenAddress = tokenAddresses(symbol); if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol); _setTokenMintAmount(symbol, tokenMintAmount(symbol) + amount); if (_getTokenType(symbol) == TokenType.External) { IERC20(tokenAddress).safeTransfer(account, amount); } else { IBurnableMintableCappedERC20(tokenAddress).mint(account, amount); } } /** * @notice Burns or locks a specific amount of tokens from a sender's account based on the provided symbol. * @param sender Address of the account from which to burn the tokens * @param symbol Symbol of the token to burn * @param amount Amount of tokens to burn * @dev Depending on the token type (External, InternalBurnableFrom, or InternalBurnable), the function either * transfers the tokens to gateway contract itself or calls a burn function on the token contract. */ function _burnTokenFrom( address sender, string memory symbol, uint256 amount ) internal { address tokenAddress = tokenAddresses(symbol); if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol); if (amount == 0) revert InvalidAmount(); TokenType tokenType = _getTokenType(symbol); if (tokenType == TokenType.External) { IERC20(tokenAddress).safeTransferFrom(sender, address(this), amount); } else if (tokenType == TokenType.InternalBurnableFrom) { IERC20(tokenAddress).safeCall(abi.encodeWithSelector(IBurnableMintableCappedERC20.burnFrom.selector, sender, amount)); } else { IERC20(tokenAddress).safeTransferFrom(sender, IBurnableMintableCappedERC20(tokenAddress).depositAddress(bytes32(0)), amount); IBurnableMintableCappedERC20(tokenAddress).burn(bytes32(0)); } } /********************\ |* Pure Key Getters *| \********************/ function _getTokenMintLimitKey(string memory symbol) internal pure returns (bytes32) { return keccak256(abi.encodePacked(PREFIX_TOKEN_MINT_LIMIT, symbol)); } function _getTokenMintAmountKey(string memory symbol, uint256 day) internal pure returns (bytes32) { return keccak256(abi.encode(PREFIX_TOKEN_MINT_AMOUNT, symbol, day)); } function _getTokenTypeKey(string memory symbol) internal pure returns (bytes32) { return keccak256(abi.encodePacked(PREFIX_TOKEN_TYPE, symbol)); } function _getTokenAddressKey(string memory symbol) internal pure returns (bytes32) { return keccak256(abi.encodePacked(PREFIX_TOKEN_ADDRESS, symbol)); } function _getIsCommandExecutedKey(bytes32 commandId) internal pure returns (bytes32) { return keccak256(abi.encodePacked(PREFIX_COMMAND_EXECUTED, commandId)); } function _getIsContractCallApprovedKey( bytes32 commandId, string memory sourceChain, string memory sourceAddress, address contractAddress, bytes32 payloadHash ) internal pure returns (bytes32) { return keccak256(abi.encode(PREFIX_CONTRACT_CALL_APPROVED, commandId, sourceChain, sourceAddress, contractAddress, payloadHash)); } function _getIsContractCallApprovedWithMintKey( bytes32 commandId, string memory sourceChain, string memory sourceAddress, address contractAddress, bytes32 payloadHash, string memory symbol, uint256 amount ) internal pure returns (bytes32) { return keccak256( abi.encode( PREFIX_CONTRACT_CALL_APPROVED_WITH_MINT, commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount ) ); } /********************\ |* Internal Getters *| \********************/ function _getCreate2Address(bytes32 salt, bytes32 codeHash) internal view returns (address) { return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, codeHash))))); } function _getTokenType(string memory symbol) internal view returns (TokenType) { return TokenType(getUint(_getTokenTypeKey(symbol))); } /********************\ |* Internal Setters *| \********************/ function _setTokenMintLimit(string memory symbol, uint256 limit) internal { emit TokenMintLimitUpdated(symbol, limit); _setUint(_getTokenMintLimitKey(symbol), limit); } function _setTokenMintAmount(string memory symbol, uint256 amount) internal { uint256 limit = tokenMintLimit(symbol); if (limit > 0 && amount > limit) revert ExceedMintLimit(symbol); _setUint(_getTokenMintAmountKey(symbol, block.timestamp / 6 hours), amount); } function _setTokenType(string memory symbol, TokenType tokenType) internal { _setUint(_getTokenTypeKey(symbol), uint256(tokenType)); } function _setTokenAddress(string memory symbol, address tokenAddress) internal { _setAddress(_getTokenAddressKey(symbol), tokenAddress); } function _setCommandExecuted(bytes32 commandId, bool executed) internal { _setBool(_getIsCommandExecutedKey(commandId), executed); } function _setContractCallApproved( bytes32 commandId, string memory sourceChain, string memory sourceAddress, address contractAddress, bytes32 payloadHash ) internal { _setBool(_getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash), true); } function _setContractCallApprovedWithMint( bytes32 commandId, string memory sourceChain, string memory sourceAddress, address contractAddress, bytes32 payloadHash, string memory symbol, uint256 amount ) internal { _setBool( _getIsContractCallApprovedWithMintKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount), true ); } function _setImplementation(address newImplementation) internal { _setAddress(KEY_IMPLEMENTATION, newImplementation); } function _transferGovernance(address newGovernance) internal { emit GovernanceTransferred(getAddress(KEY_GOVERNANCE), newGovernance); _setAddress(KEY_GOVERNANCE, newGovernance); } function _transferMintLimiter(address newMintLimiter) internal { emit MintLimiterTransferred(getAddress(KEY_MINT_LIMITER), newMintLimiter); _setAddress(KEY_MINT_LIMITER, newMintLimiter); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IGovernable } from './IGovernable.sol'; import { IImplementation } from './IImplementation.sol'; interface IAxelarGateway is IImplementation, IGovernable { /**********\ |* Errors *| \**********/ error NotSelf(); error InvalidCodeHash(); error SetupFailed(); error InvalidAuthModule(); error InvalidTokenDeployer(); error InvalidAmount(); error InvalidChainId(); error InvalidCommands(); error TokenDoesNotExist(string symbol); error TokenAlreadyExists(string symbol); error TokenDeployFailed(string symbol); error TokenContractDoesNotExist(address token); error BurnFailed(string symbol); error MintFailed(string symbol); error InvalidSetMintLimitsParams(); error ExceedMintLimit(string symbol); /**********\ |* Events *| \**********/ event TokenSent( address indexed sender, string destinationChain, string destinationAddress, string symbol, uint256 amount ); event ContractCall( address indexed sender, string destinationChain, string destinationContractAddress, bytes32 indexed payloadHash, bytes payload ); event ContractCallWithToken( address indexed sender, string destinationChain, string destinationContractAddress, bytes32 indexed payloadHash, bytes payload, string symbol, uint256 amount ); event Executed(bytes32 indexed commandId); event TokenDeployed(string symbol, address tokenAddresses); event ContractCallApproved( bytes32 indexed commandId, string sourceChain, string sourceAddress, address indexed contractAddress, bytes32 indexed payloadHash, bytes32 sourceTxHash, uint256 sourceEventIndex ); event ContractCallApprovedWithMint( bytes32 indexed commandId, string sourceChain, string sourceAddress, address indexed contractAddress, bytes32 indexed payloadHash, string symbol, uint256 amount, bytes32 sourceTxHash, uint256 sourceEventIndex ); event ContractCallExecuted(bytes32 indexed commandId); event TokenMintLimitUpdated(string symbol, uint256 limit); event OperatorshipTransferred(bytes newOperatorsData); event Upgraded(address indexed implementation); /********************\ |* Public Functions *| \********************/ function sendToken( string calldata destinationChain, string calldata destinationAddress, string calldata symbol, uint256 amount ) external; function callContract( string calldata destinationChain, string calldata contractAddress, bytes calldata payload ) external; function callContractWithToken( string calldata destinationChain, string calldata contractAddress, bytes calldata payload, string calldata symbol, uint256 amount ) external; function isContractCallApproved( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, address contractAddress, bytes32 payloadHash ) external view returns (bool); function isContractCallAndMintApproved( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, address contractAddress, bytes32 payloadHash, string calldata symbol, uint256 amount ) external view returns (bool); function validateContractCall( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes32 payloadHash ) external returns (bool); function validateContractCallAndMint( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes32 payloadHash, string calldata symbol, uint256 amount ) external returns (bool); /***********\ |* Getters *| \***********/ function authModule() external view returns (address); function tokenDeployer() external view returns (address); function tokenMintLimit(string memory symbol) external view returns (uint256); function tokenMintAmount(string memory symbol) external view returns (uint256); function allTokensFrozen() external view returns (bool); function implementation() external view returns (address); function tokenAddresses(string memory symbol) external view returns (address); function tokenFrozen(string memory symbol) external view returns (bool); function isCommandExecuted(bytes32 commandId) external view returns (bool); /************************\ |* Governance Functions *| \************************/ function setTokenMintLimits(string[] calldata symbols, uint256[] calldata limits) external; function upgrade( address newImplementation, bytes32 newImplementationCodeHash, bytes calldata setupParams ) external; /**********************\ |* External Functions *| \**********************/ function execute(bytes calldata input) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // General interface for upgradable contracts interface IContractIdentifier { /** * @notice Returns the contract ID. It can be used as a check during upgrades. * @dev Meant to be overridden in derived contracts. * @return bytes32 The contract ID */ function contractId() external pure returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { error InvalidAccount(); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title IGovernable Interface * @notice This is an interface used by the AxelarGateway contract to manage governance and mint limiter roles. */ interface IGovernable { error NotGovernance(); error NotMintLimiter(); error InvalidGovernance(); error InvalidMintLimiter(); event GovernanceTransferred(address indexed previousGovernance, address indexed newGovernance); event MintLimiterTransferred(address indexed previousGovernance, address indexed newGovernance); /** * @notice Returns the governance address. * @return address of the governance */ function governance() external view returns (address); /** * @notice Returns the mint limiter address. * @return address of the mint limiter */ function mintLimiter() external view returns (address); /** * @notice Transfer the governance role to another address. * @param newGovernance The new governance address */ function transferGovernance(address newGovernance) external; /** * @notice Transfer the mint limiter role to another address. * @param newGovernance The new mint limiter address */ function transferMintLimiter(address newGovernance) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IContractIdentifier } from './IContractIdentifier.sol'; interface IImplementation is IContractIdentifier { error NotProxy(); function setup(bytes calldata data) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title IOwnable Interface * @notice IOwnable is an interface that abstracts the implementation of a * contract with ownership control features. It's commonly used in upgradable * contracts and includes the functionality to get current owner, transfer * ownership, and propose and accept ownership. */ interface IOwnable { error NotOwner(); error InvalidOwner(); error InvalidOwnerAddress(); event OwnershipTransferStarted(address indexed newOwner); event OwnershipTransferred(address indexed newOwner); /** * @notice Returns the current owner of the contract. * @return address The address of the current owner */ function owner() external view returns (address); /** * @notice Returns the address of the pending owner of the contract. * @return address The address of the pending owner */ function pendingOwner() external view returns (address); /** * @notice Transfers ownership of the contract to a new address * @param newOwner The address to transfer ownership to */ function transferOwnership(address newOwner) external; /** * @notice Proposes to transfer the contract's ownership to a new address. * The new owner needs to accept the ownership explicitly. * @param newOwner The address to transfer ownership to */ function proposeOwnership(address newOwner) external; /** * @notice Transfers ownership to the pending owner. * @dev Can only be called by the pending owner */ function acceptOwnership() external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library ContractAddress { function isContract(address contractAddress) internal view returns (bool) { bytes32 existingCodeHash = contractAddress.codehash; // https://eips.ethereum.org/EIPS/eip-1052 // keccak256('') == 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 return existingCodeHash != bytes32(0) && existingCodeHash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC20 } from '../interfaces/IERC20.sol'; error TokenTransferFailed(); /* * @title SafeTokenCall * @dev This library is used for performing safe token transfers. */ library SafeTokenCall { /* * @notice Make a safe call to a token contract. * @param token The token contract to interact with. * @param callData The function call data. * @throws TokenTransferFailed error if transfer of token is not successful. */ function safeCall(IERC20 token, bytes memory callData) internal { (bool success, bytes memory returnData) = address(token).call(callData); bool transferred = success && (returnData.length == uint256(0) || abi.decode(returnData, (bool))); if (!transferred || address(token).code.length == 0) revert TokenTransferFailed(); } } /* * @title SafeTokenTransfer * @dev This library safely transfers tokens from the contract to a recipient. */ library SafeTokenTransfer { /* * @notice Transfer tokens to a recipient. * @param token The token contract. * @param receiver The recipient of the tokens. * @param amount The amount of tokens to transfer. */ function safeTransfer( IERC20 token, address receiver, uint256 amount ) internal { SafeTokenCall.safeCall(token, abi.encodeWithSelector(IERC20.transfer.selector, receiver, amount)); } } /* * @title SafeTokenTransferFrom * @dev This library helps to safely transfer tokens on behalf of a token holder. */ library SafeTokenTransferFrom { /* * @notice Transfer tokens on behalf of a token holder. * @param token The token contract. * @param from The address of the token holder. * @param to The address the tokens are to be sent to. * @param amount The amount of tokens to be transferred. */ function safeTransferFrom( IERC20 token, address from, address to, uint256 amount ) internal { SafeTokenCall.safeCall(token, abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, amount)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IImplementation } from '../interfaces/IImplementation.sol'; /** * @title Implementation * @notice This contract serves as a base for other contracts and enforces a proxy-first access restriction. * @dev Derived contracts must implement the setup function. */ abstract contract Implementation is IImplementation { address private immutable implementationAddress; /** * @dev Contract constructor that sets the implementation address to the address of this contract. */ constructor() { implementationAddress = address(this); } /** * @dev Modifier to require the caller to be the proxy contract. * Reverts if the caller is the current contract (i.e., the implementation contract itself). */ modifier onlyProxy() { if (implementationAddress == address(this)) revert NotProxy(); _; } /** * @notice Initializes contract parameters. * This function is intended to be overridden by derived contracts. * The overriding function must have the onlyProxy modifier. * @param params The parameters to be used for initialization */ function setup(bytes calldata params) external virtual; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; contract DepositHandler { error IsLocked(); error NotContract(); uint256 internal constant IS_NOT_LOCKED = uint256(1); uint256 internal constant IS_LOCKED = uint256(2); uint256 internal _lockedStatus = IS_NOT_LOCKED; modifier noReenter() { if (_lockedStatus == IS_LOCKED) revert IsLocked(); _lockedStatus = IS_LOCKED; _; _lockedStatus = IS_NOT_LOCKED; } function execute(address callee, bytes calldata data) external noReenter returns (bool success, bytes memory returnData) { if (callee.code.length == 0) revert NotContract(); (success, returnData) = callee.call(data); } // NOTE: The gateway should always destroy the `DepositHandler` in the same runtime context that deploys it. function destroy(address etherDestination) external noReenter { selfdestruct(payable(etherDestination)); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { error InvalidSignatureLength(); error InvalidS(); error InvalidV(); error InvalidSignature(); /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address signer) { // Check the signature length if (signature.length != 65) revert InvalidSignatureLength(); // Divide the signature in r, s and v variables bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. // solhint-disable-next-line no-inline-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) revert InvalidS(); if (v != 27 && v != 28) revert InvalidV(); // If the signature is valid (and not malleable), return the signer address if ((signer = ecrecover(hash, v, r, s)) == address(0)) revert InvalidSignature(); } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * replicates the behavior of the * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`] * JSON-RPC method. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked('\x19Ethereum Signed Message:\n32', hash)); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; /** * @title EternalStorage * @dev This contract holds all the necessary state variables to carry out the storage of any contract. */ contract EternalStorage { mapping(bytes32 => uint256) private _uintStorage; mapping(bytes32 => string) private _stringStorage; mapping(bytes32 => address) private _addressStorage; mapping(bytes32 => bytes) private _bytesStorage; mapping(bytes32 => bool) private _boolStorage; mapping(bytes32 => int256) private _intStorage; // *** Getter Methods *** function getUint(bytes32 key) public view returns (uint256) { return _uintStorage[key]; } function getString(bytes32 key) public view returns (string memory) { return _stringStorage[key]; } function getAddress(bytes32 key) public view returns (address) { return _addressStorage[key]; } function getBytes(bytes32 key) public view returns (bytes memory) { return _bytesStorage[key]; } function getBool(bytes32 key) public view returns (bool) { return _boolStorage[key]; } function getInt(bytes32 key) public view returns (int256) { return _intStorage[key]; } // *** Setter Methods *** function _setUint(bytes32 key, uint256 value) internal { _uintStorage[key] = value; } function _setString(bytes32 key, string memory value) internal { _stringStorage[key] = value; } function _setAddress(bytes32 key, address value) internal { _addressStorage[key] = value; } function _setBytes(bytes32 key, bytes memory value) internal { _bytesStorage[key] = value; } function _setBool(bytes32 key, bool value) internal { _boolStorage[key] = value; } function _setInt(bytes32 key, int256 value) internal { _intStorage[key] = value; } // *** Delete Methods *** function _deleteUint(bytes32 key) internal { delete _uintStorage[key]; } function _deleteString(bytes32 key) internal { delete _stringStorage[key]; } function _deleteAddress(bytes32 key) internal { delete _addressStorage[key]; } function _deleteBytes(bytes32 key) internal { delete _bytesStorage[key]; } function _deleteBool(bytes32 key) internal { delete _boolStorage[key]; } function _deleteInt(bytes32 key) internal { delete _intStorage[key]; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IOwnable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IOwnable.sol'; interface IAxelarAuth is IOwnable { function validateProof(bytes32 messageHash, bytes calldata proof) external returns (bool currentOperators); function transferOperatorship(bytes calldata params) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; import { IERC20Burn } from './IERC20Burn.sol'; import { IERC20BurnFrom } from './IERC20BurnFrom.sol'; import { IMintableCappedERC20 } from './IMintableCappedERC20.sol'; interface IBurnableMintableCappedERC20 is IERC20Burn, IERC20BurnFrom, IMintableCappedERC20 { function depositAddress(bytes32 salt) external view returns (address); function burn(bytes32 salt) external; function burnFrom(address account, uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { error InvalidAccount(); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; interface IERC20Burn { function burn(bytes32 salt) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; interface IERC20BurnFrom { function burnFrom(address account, uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; interface IERC20Permit { function DOMAIN_SEPARATOR() external view returns (bytes32); function nonces(address account) external view returns (uint256); function permit( address issuer, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; import { IERC20 } from './IERC20.sol'; import { IERC20Permit } from './IERC20Permit.sol'; import { IOwnable } from './IOwnable.sol'; interface IMintableCappedERC20 is IERC20, IERC20Permit, IOwnable { error CapExceeded(); function cap() external view returns (uint256); function mint(address account, uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; interface IOwnable { error NotOwner(); error InvalidOwner(); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); function owner() external view returns (address); function transferOwnership(address newOwner) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface ITokenDeployer { function deployToken( string calldata name, string calldata symbol, uint8 decimals, uint256 cap, bytes32 salt ) external returns (address tokenAddress); }
{ "evmVersion": "london", "optimizer": { "enabled": true, "runs": 1000, "details": { "peephole": true, "inliner": true, "jumpdestRemover": true, "orderLiterals": true, "deduplicate": true, "cse": true, "constantOptimizer": true, "yul": true, "yulDetails": { "stackAllocation": true } } }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"authModule_","type":"address"},{"internalType":"address","name":"tokenDeployer_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"string","name":"symbol","type":"string"}],"name":"BurnFailed","type":"error"},{"inputs":[{"internalType":"string","name":"symbol","type":"string"}],"name":"ExceedMintLimit","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidAuthModule","type":"error"},{"inputs":[],"name":"InvalidChainId","type":"error"},{"inputs":[],"name":"InvalidCodeHash","type":"error"},{"inputs":[],"name":"InvalidCommands","type":"error"},{"inputs":[],"name":"InvalidGovernance","type":"error"},{"inputs":[],"name":"InvalidImplementation","type":"error"},{"inputs":[],"name":"InvalidMintLimiter","type":"error"},{"inputs":[],"name":"InvalidSetMintLimitsParams","type":"error"},{"inputs":[],"name":"InvalidTokenDeployer","type":"error"},{"inputs":[{"internalType":"string","name":"symbol","type":"string"}],"name":"MintFailed","type":"error"},{"inputs":[],"name":"NotGovernance","type":"error"},{"inputs":[],"name":"NotMintLimiter","type":"error"},{"inputs":[],"name":"NotProxy","type":"error"},{"inputs":[],"name":"NotSelf","type":"error"},{"inputs":[],"name":"SetupFailed","type":"error"},{"inputs":[{"internalType":"string","name":"symbol","type":"string"}],"name":"TokenAlreadyExists","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"TokenContractDoesNotExist","type":"error"},{"inputs":[{"internalType":"string","name":"symbol","type":"string"}],"name":"TokenDeployFailed","type":"error"},{"inputs":[{"internalType":"string","name":"symbol","type":"string"}],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"TokenTransferFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"string","name":"destinationChain","type":"string"},{"indexed":false,"internalType":"string","name":"destinationContractAddress","type":"string"},{"indexed":true,"internalType":"bytes32","name":"payloadHash","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"payload","type":"bytes"}],"name":"ContractCall","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"commandId","type":"bytes32"},{"indexed":false,"internalType":"string","name":"sourceChain","type":"string"},{"indexed":false,"internalType":"string","name":"sourceAddress","type":"string"},{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"bytes32","name":"payloadHash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"sourceTxHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"sourceEventIndex","type":"uint256"}],"name":"ContractCallApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"commandId","type":"bytes32"},{"indexed":false,"internalType":"string","name":"sourceChain","type":"string"},{"indexed":false,"internalType":"string","name":"sourceAddress","type":"string"},{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"bytes32","name":"payloadHash","type":"bytes32"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"sourceTxHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"sourceEventIndex","type":"uint256"}],"name":"ContractCallApprovedWithMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"commandId","type":"bytes32"}],"name":"ContractCallExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"string","name":"destinationChain","type":"string"},{"indexed":false,"internalType":"string","name":"destinationContractAddress","type":"string"},{"indexed":true,"internalType":"bytes32","name":"payloadHash","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"payload","type":"bytes"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ContractCallWithToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"commandId","type":"bytes32"}],"name":"Executed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernance","type":"address"}],"name":"GovernanceTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernance","type":"address"}],"name":"MintLimiterTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"newOperatorsData","type":"bytes"}],"name":"OperatorshipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"address","name":"tokenAddresses","type":"address"}],"name":"TokenDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"limit","type":"uint256"}],"name":"TokenMintLimitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"string","name":"destinationChain","type":"string"},{"indexed":false,"internalType":"string","name":"destinationAddress","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"allTokensFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"params","type":"bytes"},{"internalType":"bytes32","name":"commandId","type":"bytes32"}],"name":"approveContractCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"params","type":"bytes"},{"internalType":"bytes32","name":"commandId","type":"bytes32"}],"name":"approveContractCallWithMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"authModule","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"params","type":"bytes"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"burnToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"destinationChain","type":"string"},{"internalType":"string","name":"destinationContractAddress","type":"string"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"callContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"destinationChain","type":"string"},{"internalType":"string","name":"destinationContractAddress","type":"string"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"callContractWithToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"params","type":"bytes"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"deployToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"input","type":"bytes"}],"name":"execute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getBool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getBytes","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getInt","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getString","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getUint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commandId","type":"bytes32"}],"name":"isCommandExecuted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commandId","type":"bytes32"},{"internalType":"string","name":"sourceChain","type":"string"},{"internalType":"string","name":"sourceAddress","type":"string"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bytes32","name":"payloadHash","type":"bytes32"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"isContractCallAndMintApproved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commandId","type":"bytes32"},{"internalType":"string","name":"sourceChain","type":"string"},{"internalType":"string","name":"sourceAddress","type":"string"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bytes32","name":"payloadHash","type":"bytes32"}],"name":"isContractCallApproved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintLimiter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"params","type":"bytes"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"mintToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"destinationChain","type":"string"},{"internalType":"string","name":"destinationAddress","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sendToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string[]","name":"symbols","type":"string[]"},{"internalType":"uint256[]","name":"limits","type":"uint256[]"}],"name":"setTokenMintLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"params","type":"bytes"}],"name":"setup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"symbol","type":"string"}],"name":"tokenAddresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenDeployer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"tokenFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"string","name":"symbol","type":"string"}],"name":"tokenMintAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"symbol","type":"string"}],"name":"tokenMintLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newGovernance","type":"address"}],"name":"transferGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newMintLimiter","type":"address"}],"name":"transferMintLimiter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"newOperatorsData","type":"bytes"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"transferOperatorship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes32","name":"newImplementationCodeHash","type":"bytes32"},{"internalType":"bytes","name":"setupParams","type":"bytes"}],"name":"upgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commandId","type":"bytes32"},{"internalType":"string","name":"sourceChain","type":"string"},{"internalType":"string","name":"sourceAddress","type":"string"},{"internalType":"bytes32","name":"payloadHash","type":"bytes32"}],"name":"validateContractCall","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commandId","type":"bytes32"},{"internalType":"string","name":"sourceChain","type":"string"},{"internalType":"string","name":"sourceAddress","type":"string"},{"internalType":"bytes32","name":"payloadHash","type":"bytes32"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"validateContractCallAndMint","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60e06040523480156200001157600080fd5b506040516200474b3803806200474b8339810160408190526200003491620000bf565b306080526001600160a01b0382163b620000615760405163735326ab60e01b815260040160405180910390fd5b6001600160a01b0381163b6200008a57604051630c84dabf60e31b815260040160405180910390fd5b6001600160a01b0391821660a0521660c052620000f7565b80516001600160a01b0381168114620000ba57600080fd5b919050565b60008060408385031215620000d357600080fd5b620000de83620000a2565b9150620000ee60208401620000a2565b90509250929050565b60805160a05160c0516146086200014360003960008181610359015261186701526000818161047e015281816106f201528181611aad0152611cbc01526000611bbf01526146086000f3fe608060405234801561001057600080fd5b50600436106102775760003560e01c80638291286c11610160578063bc00c216116100d8578063d26ff2101161008c578063dc97d96211610071578063dc97d96214610681578063f6a5f9f5146106a1578063fbe0a31b146106b457600080fd5b8063d26ff2101461065b578063d38bfff41461066e57600080fd5b8063c031a180116100bd578063c031a180146105dc578063c82fe87a146105ef578063cec7b3591461064857600080fd5b8063bc00c216146105a9578063bd02d0f5146105bc57600080fd5b8063986e791a1161012f578063a3499c7311610114578063a3499c731461057c578063aa1e1f0a1461058f578063b54170841461059657600080fd5b8063986e791a146105495780639ded06df1461056957600080fd5b80638291286c146104ea578063886a625d14610510578063935b13f61461052357806397b87ba61461053657600080fd5b80634656ae2e116101f35780635f6970c3116101c257806367ace8eb116101a757806367ace8eb146104a05780637ae1cfca146104b35780637b1b769e146104d657600080fd5b80635f6970c31461046657806364940c561461047957600080fd5b80634656ae2e1461038e578063585a9fd4146103a15780635aa6e675146103b45780635c60da1b1461040d57600080fd5b806321f8a7211161024a57806326ef699d1161022f57806326ef699d146103415780632a2dae0a1461035457806341d8f26b1461037b57600080fd5b806321f8a721146102df578063269eb65e1461032057600080fd5b806309c5eabe1461027c578063146e2d78146102915780631876eed9146102a45780631c92115f146102cc575b600080fd5b61028f61028a366004612f28565b6106c7565b005b61028f61029f366004612f6a565b610be1565b6102b76102b2366004612fb6565b610c2a565b60405190151581526020015b60405180910390f35b61028f6102da36600461306b565b610d85565b6103086102ed366004613105565b6000908152600260205260409020546001600160a01b031690565b6040516001600160a01b0390911681526020016102c3565b61033361032e3660046131e3565b610df0565b6040519081526020016102c3565b61028f61034f366004613220565b610e04565b6103087f000000000000000000000000000000000000000000000000000000000000000081565b61028f6103893660046132d8565b610e9c565b61028f61039c366004612f6a565b610fbc565b61028f6103af366004612f6a565b611403565b7fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b0316610308565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60005260026020527f11141f466c69fd409e1990e063b49cd6d61ed2ecff27a2e402e259ca6b9a01a3546001600160a01b0316610308565b6102b76104743660046132f5565b6114b1565b6103087f000000000000000000000000000000000000000000000000000000000000000081565b61028f6104ae3660046133bc565b611591565b6102b76104c1366004613105565b60009081526004602052604090205460ff1690565b6102b76104e43660046131e3565b50600090565b7fad2ae48b4d93c587cd1f0f8f269b84f57dbe98bbe5c61c4b6d324e6a667b3625610333565b61028f61051e366004612f6a565b61177f565b6103086105313660046131e3565b611a2f565b61028f610544366004612f6a565b611a3d565b61055c610557366004613105565b611b1b565b6040516102c39190613480565b61028f610577366004612f28565b611bbd565b61028f61058a366004613493565b611d26565b60006102b7565b61028f6105a43660046134e3565b61203c565b6102b76105b73660046135af565b6120f2565b6103336105ca366004613105565b60009081526020819052604090205490565b61055c6105ea366004613105565b6121c5565b7f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d9260005260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b546001600160a01b0316610308565b6103336106563660046131e3565b6121e2565b6102b7610669366004613105565b6121fc565b61028f61067c3660046132d8565b61220a565b61033361068f366004613105565b60009081526005602052604090205490565b6102b76106af36600461367d565b6122c5565b61028f6106c2366004612f6a565b61234e565b6000806106d683850185613714565b9150915060006106ec83805190602001206123ee565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166373e3d66a83856040518363ffffffff1660e01b815260040161073e929190613778565b602060405180830381600087803b15801561075857600080fd5b505af115801561076c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079091906137a6565b905060006060806060878060200190518101906107ad919061394a565b929650909450925090504684146107f0576040517f7a47c9a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8251825181141580610803575081518114155b1561083a576040517fca9a28f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610bd357600085828151811061085957610859613a34565b6020026020010151905061086c816121fc565b156108775750610bc3565b60008086848151811061088c5761088c613a34565b60200260200101516040516020016108a49190613a4a565b6040516020818303038152906040528051906020012090507f5763814b98a3aa86f212797af3273868b5dd6e2a532d764a79b98ca859e7bbad81141561090c577f886a625d000000000000000000000000000000000000000000000000000000009150610ab5565b7fec78d9c22c08bb9f0ecd5d95571ae83e3f22219c5a9278c3270691d50abfd91b81141561095c577f146e2d78000000000000000000000000000000000000000000000000000000009150610ab5565b7f37ac16aabc4d87540e53151b2b716265cfd6b195db96a9daf8e893c829bbd2338114156109ac577ffbe0a31b000000000000000000000000000000000000000000000000000000009150610ab5565b7ff41504255b911b3042ee4f8786fdf7cf4bcf24ace033fa16af3c8574e025e4368114156109fc577f585a9fd4000000000000000000000000000000000000000000000000000000009150610ab5565b7fda199c0e76f665e0450020791c7f8eacc75f3cdbace313272c28f93e5390b62c811415610a4c577f4656ae2e000000000000000000000000000000000000000000000000000000009150610ab5565b7fb460dcb6fd5797fc0e7ea0f13406c80d30702ba7f73a42bd91394775dcbca718811415610aad5789610a8157505050610bc3565b600099507f97b87ba6000000000000000000000000000000000000000000000000000000009150610ab5565b505050610bc3565b610ac0836001612442565b6000306001600160a01b031683888781518110610adf57610adf613a34565b602002602001015186604051602401610af9929190613a66565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051610b379190613a4a565b6000604051808303816000865af19150503d8060008114610b74576040519150601f19603f3d011682016040523d82523d6000602084013e610b79565b606091505b505090508015610bb35760405184907fa74c8847d513feba22a0f0cb38d53081abf97562cdb293926ba243689e7c41ca90600090a2610bbe565b610bbe846000612442565b505050505b610bcc81613a9e565b905061083d565b505050505050505050505050565b333014610c01576040516314e1dbf760e11b815260040160405180910390fd5b60008080610c1185870187613ac4565b925092509250610c2283838361246e565b505050505050565b600080610cdb8b8b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8f018190048102820181019092528d815292508d91508c908190840183828082843760009201919091525050604080516020601f8d018190048102820181019092528b81523393508d9250908c908c90819084018382808284376000920191909152508c925061257d915050565b60008181526004602052604090205460ff16925090508115610d7757600081815260046020526040808220805460ff19169055518c917f91057b069763121972ce22b18b2f319b1520dd4c72f1f94a6395e81ceaf63f4191a2610d7785858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525033925087915061246e9050565b509998505050505050505050565b8181604051610d95929190613b1e565b6040518091039020336001600160a01b03167f30ae6cc78c27e651745bf2ad08a11de83910ac1e347a52f7ac898c0fbef94dae888888888888604051610de096959493929190613b57565b60405180910390a3505050505050565b6000610dfe6105ca836125e1565b92915050565b610e463384848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869250612616915050565b336001600160a01b03167f651d93f66c4329630e8d0f62488eff599e3be484da587335e8dc0fcf4606272688888888888888604051610e8b9796959493929190613ba0565b60405180910390a250505050505050565b7f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d9260005260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b546001600160a01b03163314801590610f5257507fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b03163314155b15610f705760405163223aa83d60e11b815260040160405180910390fd5b6001600160a01b038116610fb0576040517fd79d772c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fb981612821565b50565b333014610fdc576040516314e1dbf760e11b815260040160405180910390fd5b600080610feb84860186613bf1565b915091506000610ffa83611a2f565b90506001600160a01b03811661102e578260405163395d09bf60e11b81526004016110259190613480565b60405180910390fd5b600261103984612916565b600281111561104a5761104a613c36565b14156113a0576000611107836040518060200161106690612ed2565b601f1982820381018352601f9091011660408190526110889190602001613a4a565b60408051601f1981840301815282825280516020918201207fff00000000000000000000000000000000000000000000000000000000000000848301526bffffffffffffffffffffffff193060601b16602185015260358401949094526055808401949094528151808403909401845260759092019052815191012090565b905061111b816001600160a01b0316612935565b156111295750505050505050565b60008360405161113890612ed2565b8190604051809103906000f5905080158015611158573d6000803e3d6000fd5b506040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b038083166004830181905292935060009283929091631cff79cd91889163a9059cbb60e01b9130918416906370a082319060240160206040518083038186803b1580156111d257600080fd5b505afa1580156111e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120a9190613c4c565b6040516001600160a01b039092166024830152604482015260640160408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199485161790525160e085901b909216825261126b9291600401613c65565b600060405180830381600087803b15801561128557600080fd5b505af1158015611299573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112c19190810190613c87565b915091508115806112ee57508051158015906112ee5750808060200190518101906112ec91906137a6565b155b1561132757866040517fe217b0ad0000000000000000000000000000000000000000000000000000000081526004016110259190613480565b6040517ef55d9d0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0384169062f55d9d90602401600060405180830381600087803b15801561137f57600080fd5b505af1158015611393573d6000803e3d6000fd5b5050505050505050610c22565b6040516308a1eee160e01b8152600481018390526001600160a01b038216906308a1eee190602401600060405180830381600087803b1580156113e257600080fd5b505af11580156113f6573d6000803e3d6000fd5b505050505050505b505050565b333014611423576040516314e1dbf760e11b815260040160405180910390fd5b6000808080808080806114388a8c018c613ccb565b9750975097509750975097509750975061145789898989898989612978565b84866001600160a01b03168a7f9991faa1f435675159ffae64b66d7ecfdb55c29755869a18db8497b4392347e08b8b8989898960405161149c96959493929190613d89565b60405180910390a45050505050505050505050565b60008061152c8888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8c018190048102820181019092528a815292508a91508990819084018382808284376000920191909152503392508991506129a59050565b60008181526004602052604090205460ff1692509050811561158657600081815260046020526040808220805460ff191690555189917f91057b069763121972ce22b18b2f319b1520dd4c72f1f94a6395e81ceaf63f4191a25b509695505050505050565b7f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d9260005260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b546001600160a01b0316331480159061164757507fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b03163314155b156116655760405163223aa83d60e11b815260040160405180910390fd5b8281811461169f576040517f14a2275f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610c225760008686838181106116be576116be613a34565b90506020028101906116d09190613de1565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525093945088925087915085905081811061171b5761171b613a34565b90506020020135905060006001600160a01b031661173883611a2f565b6001600160a01b03161415611762578160405163395d09bf60e11b81526004016110259190613480565b61176c8282612a03565b50508061177890613a9e565b90506116a2565b33301461179f576040516314e1dbf760e11b815260040160405180910390fd5b600080808080806117b2888a018a613e28565b95509550955095509550955060006001600160a01b03166117d286611a2f565b6001600160a01b03161461181457846040517faa7e8b320000000000000000000000000000000000000000000000000000000081526004016110259190613480565b61181e8582612a03565b6001600160a01b03821661198a5760008560405160200161183f9190613a4a565b604051602081830303815290604052805190602001209050611862866001612a5b565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636fc95b3460e01b8a8a8a8a886040516024016118b0959493929190613ecb565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516118ee9190613a4a565b600060405180830381855af49150503d8060008114611929576040519150601f19603f3d011682016040523d82523d6000602084013e61192e565b606091505b50915091508161196c57876040517f86d527430000000000000000000000000000000000000000000000000000000081526004016110259190613480565b808060200190518101906119809190613f11565b94505050506119e1565b6001600160a01b0382163b6119d6576040517fc5ccddde0000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401611025565b6119e1856002612a5b565b7fbf90b5a1ec9763e8bf4b9245cef0c28db92bab309fc2c5177f17814f382469388583604051611a12929190613f2e565b60405180910390a1611a248583612a8b565b505050505050505050565b6000610dfe6102ed83612acd565b333014611a5d576040516314e1dbf760e11b815260040160405180910390fd5b7f192e759e55f359cd9832b5c0c6e38e4b6df5c5ca33f3bd5c90738e865a5218728383604051611a8e929190613f59565b60405180910390a160405163d289d1cb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d289d1cb90611ae49086908690600401613f59565b600060405180830381600087803b158015611afe57600080fd5b505af1158015611b12573d6000803e3d6000fd5b50505050505050565b6000818152600160205260409020805460609190611b3890613f6d565b80601f0160208091040260200160405190810160405280929190818152602001828054611b6490613f6d565b8015611bb15780601f10611b8657610100808354040283529160200191611bb1565b820191906000526020600020905b815481529060010190602001808311611b9457829003601f168201915b50505050509050919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316301415611c20576040517fbf10dd3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008080611c3084860186613fa8565b919450925090506001600160a01b03831615611c4f57611c4f83612b02565b6001600160a01b03821615611c6757611c6782612821565b805115611d1f577f192e759e55f359cd9832b5c0c6e38e4b6df5c5ca33f3bd5c90738e865a52187281604051611c9d9190613480565b60405180910390a160405163d289d1cb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d289d1cb90611cf1908490600401613480565b600060405180830381600087803b158015611d0b57600080fd5b505af1158015611a24573d6000803e3d6000fd5b5050505050565b7fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b03163314611d9957604051632d5be4cb60e21b815260040160405180910390fd5b836001600160a01b03163f8314611ddc576040517f8f84fb2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b836001600160a01b0316638291286c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e1557600080fd5b505afa158015611e29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e4d9190613c4c565b7fad2ae48b4d93c587cd1f0f8f269b84f57dbe98bbe5c61c4b6d324e6a667b362514611ea5576040517f68155f9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038516907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2611f50847f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60005260026020527f11141f466c69fd409e1990e063b49cd6d61ed2ecff27a2e402e259ca6b9a01a3805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03831617905550565b8015612036576000846001600160a01b0316639ded06df60e01b8484604051602401611f7d929190613f59565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051611fbb9190613a4a565b600060405180830381855af49150503d8060008114611ff6576040519150601f19603f3d011682016040523d82523d6000602084013e611ffb565b606091505b5050905080611d1f576040517f97905dfb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b61207e3384848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869250612616915050565b848460405161208e929190613b1e565b6040518091039020336001600160a01b03167f7e50569d26be643bda7757722291ec66b1be66d8283474ae3fab5a98f878a7a28b8b8b8b8b8b8b8b8b6040516120df9998979695949392919061400a565b60405180910390a3505050505050505050565b60006121b66104c18c8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8d018190048102820181019092528b81528e93508d9250908c908c90819084018382808284376000920191909152508c925061257d915050565b9b9a5050505050505050505050565b6000818152600360205260409020805460609190611b3890613f6d565b6000610dfe6105ca836121f761546042614072565b612bf7565b6000610dfe6104c183612c4c565b7fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b0316331461227d57604051632d5be4cb60e21b815260040160405180910390fd5b6001600160a01b0381166122bc576040517e63186c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fb981612b02565b60006123426104c18989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8d018190048102820181019092528b815292508b91508a90819084018382808284376000920191909152508a92508991506129a59050565b98975050505050505050565b33301461236e576040516314e1dbf760e11b815260040160405180910390fd5b60008080808080612381888a018a614094565b95509550955095509550955061239a8787878787612c87565b82846001600160a01b0316887f44e4f8f6bd682c5a3aeba93601ab07cb4d1f21b2aab1ae4880d9577919309aa4898987876040516123db9493929190614126565b60405180910390a4505050505050505050565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c015b604051602081830303815290604052805190602001209050919050565b61246a61244e83612c4c565b6000908152600460205260409020805460ff1916831515179055565b5050565b600061247984611a2f565b90506001600160a01b0381166124a4578360405163395d09bf60e11b81526004016110259190613480565b6124c184836124b2876121e2565b6124bc919061415f565b612c97565b60026124cc85612916565b60028111156124dd576124dd613c36565b14156124fc576124f76001600160a01b0382168484612d12565b612036565b6040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152602482018490528216906340c10f1990604401600060405180830381600087803b15801561255f57600080fd5b505af1158015612573573d6000803e3d6000fd5b5050505050505050565b60007fb7ad972b71475860613db3ba1fe699b886c878f9002a09250dc25e769eb19a10888888888888886040516020016125be989796959493929190614177565b604051602081830303815290604052805190602001209050979650505050505050565b60007feee9348b4aaba3647b1612b2724f18e93b9299da26fb321c7b3fda135d7dea87826040516020016124259291906141ea565b600061262183611a2f565b90506001600160a01b03811661264c578260405163395d09bf60e11b81526004016110259190613480565b81612683576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061268e84612916565b905060028160028111156126a4576126a4613c36565b14156126c4576126bf6001600160a01b038316863086612d75565b611d1f565b60018160028111156126d8576126d8613c36565b141561274b57604080516001600160a01b03878116602483015260448083018790528351808403909101815260649092019092526020810180516001600160e01b03167f79cc6790000000000000000000000000000000000000000000000000000000001790526126bf91841690612dc6565b6040517f31eecaf4000000000000000000000000000000000000000000000000000000008152600060048201526127f49086906001600160a01b038516906331eecaf49060240160206040518083038186803b1580156127aa57600080fd5b505afa1580156127be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e29190613f11565b6001600160a01b038516919086612d75565b6040516308a1eee160e01b8152600060048201526001600160a01b038316906308a1eee190602401611cf1565b7f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d92600090815260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b546040516001600160a01b03848116939216917fa9303c860c5de3c0c866c354d281785c89778ac5ca2dffdf12841c45cd4e1e6e91a37f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d9260005260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03831617905550565b60006129246105ca83612e9d565b6002811115610dfe57610dfe613c36565b60006001600160a01b0382163f801580159061297157507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708114155b9392505050565b611b1261298a8888888888888861257d565b6000908152600460205260409020805460ff19166001179055565b60007f07b0d4304f82012bd3b70b1d531c160e326067c90829e2a3d386722ad10b89c386868686866040516020016129e296959493929190614210565b60405160208183030381529060405280519060200120905095945050505050565b7fd99446c1d76385bb5519ccfb5274abcfd5896dfc22405e40010fde217f018a188282604051612a34929190613a66565b60405180910390a161246a612a48836125e1565b8260009182526020829052604090912055565b61246a612a6783612e9d565b826002811115612a7957612a79613c36565b60009182526020829052604090912055565b61246a612a9783612acd565b6000908152600260205260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038416179055565b60007fc4e632779a6a7838736dd7e5e6a0eadf171dd37dfb6230720e265576dfcf42bb826040516020016124259291906141ea565b7fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f909600090815260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546040516001600160a01b03848116939216917f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce8091a37fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03831617905550565b60007f2f8851fe0d6d537e552a4f25b7a3167d48eb1292622c71d84630a2a44757bced8383604051602001612c2e93929190614260565b60405160208183030381529060405280519060200120905092915050565b604080517f957705a374326b30f4a1069c936d736cc9993ed6c820b4e0e2fd94a8beca0d1d6020820152908101829052600090606001612425565b611d1f61298a86868686866129a5565b6000612ca283610df0565b9050600081118015612cb357508082115b15612cec57826040517f037f60e50000000000000000000000000000000000000000000000000000000081526004016110259190613480565b6113fe612cff846121f761546042614072565b8360009182526020829052604090912055565b6040516001600160a01b0383166024820152604481018290526113fe90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612dc6565b6040516001600160a01b03808516602483015283166044820152606481018290526120369085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401612d3e565b600080836001600160a01b031683604051612de19190613a4a565b6000604051808303816000865af19150503d8060008114612e1e576040519150601f19603f3d011682016040523d82523d6000602084013e612e23565b606091505b50915091506000828015612e4f575081511580612e4f575081806020019051810190612e4f91906137a6565b9050801580612e6657506001600160a01b0385163b155b15611d1f576040517f045c4b0200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fa80d2259af55890618ec2eeb3ac72de4bdba22529bb14845d8a3d712d1c3f621826040516020016124259291906141ea565b6103498061428a83390190565b60008083601f840112612ef157600080fd5b50813567ffffffffffffffff811115612f0957600080fd5b602083019150836020828501011115612f2157600080fd5b9250929050565b60008060208385031215612f3b57600080fd5b823567ffffffffffffffff811115612f5257600080fd5b612f5e85828601612edf565b90969095509350505050565b600080600060408486031215612f7f57600080fd5b833567ffffffffffffffff811115612f9657600080fd5b612fa286828701612edf565b909790965060209590950135949350505050565b600080600080600080600080600060c08a8c031215612fd457600080fd5b8935985060208a013567ffffffffffffffff80821115612ff357600080fd5b612fff8d838e01612edf565b909a50985060408c013591508082111561301857600080fd5b6130248d838e01612edf565b909850965060608c0135955060808c013591508082111561304457600080fd5b506130518c828d01612edf565b9a9d999c50979a9699959894979660a00135949350505050565b6000806000806000806060878903121561308457600080fd5b863567ffffffffffffffff8082111561309c57600080fd5b6130a88a838b01612edf565b909850965060208901359150808211156130c157600080fd5b6130cd8a838b01612edf565b909650945060408901359150808211156130e657600080fd5b506130f389828a01612edf565b979a9699509497509295939492505050565b60006020828403121561311757600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561315d5761315d61311e565b604052919050565b600067ffffffffffffffff82111561317f5761317f61311e565b50601f01601f191660200190565b600082601f83011261319e57600080fd5b81356131b16131ac82613165565b613134565b8181528460208386010111156131c657600080fd5b816020850160208301376000918101602001919091529392505050565b6000602082840312156131f557600080fd5b813567ffffffffffffffff81111561320c57600080fd5b6132188482850161318d565b949350505050565b60008060008060008060006080888a03121561323b57600080fd5b873567ffffffffffffffff8082111561325357600080fd5b61325f8b838c01612edf565b909950975060208a013591508082111561327857600080fd5b6132848b838c01612edf565b909750955060408a013591508082111561329d57600080fd5b506132aa8a828b01612edf565b989b979a50959894979596606090950135949350505050565b6001600160a01b0381168114610fb957600080fd5b6000602082840312156132ea57600080fd5b8135612971816132c3565b6000806000806000806080878903121561330e57600080fd5b86359550602087013567ffffffffffffffff8082111561332d57600080fd5b6133398a838b01612edf565b9097509550604089013591508082111561335257600080fd5b5061335f89828a01612edf565b979a9699509497949695606090950135949350505050565b60008083601f84011261338957600080fd5b50813567ffffffffffffffff8111156133a157600080fd5b6020830191508360208260051b8501011115612f2157600080fd5b600080600080604085870312156133d257600080fd5b843567ffffffffffffffff808211156133ea57600080fd5b6133f688838901613377565b9096509450602087013591508082111561340f57600080fd5b5061341c87828801613377565b95989497509550505050565b60005b8381101561344357818101518382015260200161342b565b838111156120365750506000910152565b6000815180845261346c816020860160208601613428565b601f01601f19169290920160200192915050565b6020815260006129716020830184613454565b600080600080606085870312156134a957600080fd5b84356134b4816132c3565b935060208501359250604085013567ffffffffffffffff8111156134d757600080fd5b61341c87828801612edf565b600080600080600080600080600060a08a8c03121561350157600080fd5b893567ffffffffffffffff8082111561351957600080fd5b6135258d838e01612edf565b909b50995060208c013591508082111561353e57600080fd5b61354a8d838e01612edf565b909950975060408c013591508082111561356357600080fd5b61356f8d838e01612edf565b909750955060608c013591508082111561358857600080fd5b506135958c828d01612edf565b9a9d999c50979a9699959894979660800135949350505050565b60008060008060008060008060008060e08b8d0312156135ce57600080fd5b8a35995060208b013567ffffffffffffffff808211156135ed57600080fd5b6135f98e838f01612edf565b909b50995060408d013591508082111561361257600080fd5b61361e8e838f01612edf565b909950975060608d01359150613633826132c3565b90955060808c0135945060a08c0135908082111561365057600080fd5b5061365d8d828e01612edf565b9150809450508092505060c08b013590509295989b9194979a5092959850565b600080600080600080600060a0888a03121561369857600080fd5b87359650602088013567ffffffffffffffff808211156136b757600080fd5b6136c38b838c01612edf565b909850965060408a01359150808211156136dc57600080fd5b506136e98a828b01612edf565b90955093505060608801356136fd816132c3565b809250506080880135905092959891949750929550565b6000806040838503121561372757600080fd5b823567ffffffffffffffff8082111561373f57600080fd5b61374b8683870161318d565b9350602085013591508082111561376157600080fd5b5061376e8582860161318d565b9150509250929050565b8281526040602082015260006132186040830184613454565b805180151581146137a157600080fd5b919050565b6000602082840312156137b857600080fd5b61297182613791565b600067ffffffffffffffff8211156137db576137db61311e565b5060051b60200190565b60006137f36131ac84613165565b905082815283838301111561380757600080fd5b612971836020830184613428565b600082601f83011261382657600080fd5b815160206138366131ac836137c1565b82815260059290921b8401810191818101908684111561385557600080fd5b8286015b8481101561158657805167ffffffffffffffff8111156138795760008081fd5b8701603f8101891361388b5760008081fd5b61389c8986830151604084016137e5565b845250918301918301613859565b600082601f8301126138bb57600080fd5b612971838351602085016137e5565b600082601f8301126138db57600080fd5b815160206138eb6131ac836137c1565b82815260059290921b8401810191818101908684111561390a57600080fd5b8286015b8481101561158657805167ffffffffffffffff81111561392e5760008081fd5b61393c8986838b01016138aa565b84525091830191830161390e565b6000806000806080858703121561396057600080fd5b8451935060208086015167ffffffffffffffff8082111561398057600080fd5b818801915088601f83011261399457600080fd5b81516139a26131ac826137c1565b81815260059190911b8301840190848101908b8311156139c157600080fd5b938501935b828510156139df578451825293850193908501906139c6565b60408b015190985094505050808311156139f857600080fd5b613a0489848a01613815565b94506060880151925080831115613a1a57600080fd5b5050613a28878288016138ca565b91505092959194509250565b634e487b7160e01b600052603260045260246000fd5b60008251613a5c818460208701613428565b9190910192915050565b604081526000613a796040830185613454565b90508260208301529392505050565b634e487b7160e01b600052601160045260246000fd5b6000600019821415613ab257613ab2613a88565b5060010190565b80356137a1816132c3565b600080600060608486031215613ad957600080fd5b833567ffffffffffffffff811115613af057600080fd5b613afc8682870161318d565b9350506020840135613b0d816132c3565b929592945050506040919091013590565b8183823760009101908152919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b606081526000613b6b60608301888a613b2e565b8281036020840152613b7e818789613b2e565b90508281036040840152613b93818587613b2e565b9998505050505050505050565b608081526000613bb460808301898b613b2e565b8281036020840152613bc781888a613b2e565b90508281036040840152613bdc818688613b2e565b91505082606083015298975050505050505050565b60008060408385031215613c0457600080fd5b823567ffffffffffffffff811115613c1b57600080fd5b613c278582860161318d565b95602094909401359450505050565b634e487b7160e01b600052602160045260246000fd5b600060208284031215613c5e57600080fd5b5051919050565b6001600160a01b03831681526040602082015260006132186040830184613454565b60008060408385031215613c9a57600080fd5b613ca383613791565b9150602083015167ffffffffffffffff811115613cbf57600080fd5b61376e858286016138aa565b600080600080600080600080610100898b031215613ce857600080fd5b883567ffffffffffffffff80821115613d0057600080fd5b613d0c8c838d0161318d565b995060208b0135915080821115613d2257600080fd5b613d2e8c838d0161318d565b9850613d3c60408c01613ab9565b975060608b0135965060808b0135915080821115613d5957600080fd5b50613d668b828c0161318d565b989b979a50959894979660a0860135965060c08601359560e00135945092505050565b60c081526000613d9c60c0830189613454565b8281036020840152613dae8189613454565b90508281036040840152613dc28188613454565b60608401969096525050608081019290925260a0909101529392505050565b6000808335601e19843603018112613df857600080fd5b83018035915067ffffffffffffffff821115613e1357600080fd5b602001915036819003821315612f2157600080fd5b60008060008060008060c08789031215613e4157600080fd5b863567ffffffffffffffff80821115613e5957600080fd5b613e658a838b0161318d565b97506020890135915080821115613e7b57600080fd5b50613e8889828a0161318d565b955050604087013560ff81168114613e9f57600080fd5b9350606087013592506080870135613eb6816132c3565b8092505060a087013590509295509295509295565b60a081526000613ede60a0830188613454565b8281036020840152613ef08188613454565b60ff9690961660408401525050606081019290925260809091015292915050565b600060208284031215613f2357600080fd5b8151612971816132c3565b604081526000613f416040830185613454565b90506001600160a01b03831660208301529392505050565b602081526000613218602083018486613b2e565b600181811c90821680613f8157607f821691505b60208210811415613fa257634e487b7160e01b600052602260045260246000fd5b50919050565b600080600060608486031215613fbd57600080fd5b8335613fc8816132c3565b92506020840135613fd8816132c3565b9150604084013567ffffffffffffffff811115613ff457600080fd5b6140008682870161318d565b9150509250925092565b60a08152600061401e60a083018b8d613b2e565b8281036020840152614031818a8c613b2e565b9050828103604084015261404681888a613b2e565b9050828103606084015261405b818688613b2e565b9150508260808301529a9950505050505050505050565b60008261408f57634e487b7160e01b600052601260045260246000fd5b500490565b60008060008060008060c087890312156140ad57600080fd5b863567ffffffffffffffff808211156140c557600080fd5b6140d18a838b0161318d565b975060208901359150808211156140e757600080fd5b506140f489828a0161318d565b9550506040870135614105816132c3565b959894975094956060810135955060808101359460a0909101359350915050565b6080815260006141396080830187613454565b828103602084015261414b8187613454565b604084019590955250506060015292915050565b6000821982111561417257614172613a88565b500190565b60006101008a83528960208401528060408401526141978184018a613454565b905082810360608401526141ab8189613454565b90506001600160a01b03871660808401528560a084015282810360c08401526141d48186613454565b9150508260e08301529998505050505050505050565b82815260008251614202816020850160208701613428565b919091016020019392505050565b86815285602082015260c06040820152600061422f60c0830187613454565b82810360608401526142418187613454565b6001600160a01b03959095166080840152505060a00152949350505050565b8381526060602082015260006142796060830185613454565b905082604083015294935050505056fe6080604052600160005534801561001557600080fd5b50610324806100256000396000f3fe608060405234801561001057600080fd5b50600436106100355760003560e01c8062f55d9d1461003a5780631cff79cd1461004f575b600080fd5b61004d6100483660046101da565b610079565b005b61006261005d3660046101fc565b6100bb565b60405161007092919061027f565b60405180910390f35b6002600054141561009d5760405163caa30f5560e01b815260040160405180910390fd5b600260005573ffffffffffffffffffffffffffffffffffffffff8116ff5b60006060600260005414156100e35760405163caa30f5560e01b815260040160405180910390fd5b600260005573ffffffffffffffffffffffffffffffffffffffff85163b610136576040517f6f7c43f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff16848460405161015d9291906102de565b6000604051808303816000865af19150503d806000811461019a576040519150601f19603f3d011682016040523d82523d6000602084013e61019f565b606091505b50600160005590969095509350505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146101d557600080fd5b919050565b6000602082840312156101ec57600080fd5b6101f5826101b1565b9392505050565b60008060006040848603121561021157600080fd5b61021a846101b1565b9250602084013567ffffffffffffffff8082111561023757600080fd5b818601915086601f83011261024b57600080fd5b81358181111561025a57600080fd5b87602082850101111561026c57600080fd5b6020830194508093505050509250925092565b821515815260006020604081840152835180604085015260005b818110156102b557858101830151858201606001528201610299565b818111156102c7576000606083870101525b50601f01601f191692909201606001949350505050565b818382376000910190815291905056fea264697066735822122032cb5e746816b7fac95205c068b30da37bd40119a57265be331c162cae74712464736f6c63430008090033a26469706673582212207a2dbc57a1c98fee8c2369d9cf383e7218fef232e89a2c6ccc8240252688875764736f6c63430008090033000000000000000000000000e3b83f79fbf01b25659f8a814945ab82186a8ad0000000000000000000000000b28478319b64f8d47e19a120209a211d902f8b8f
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102775760003560e01c80638291286c11610160578063bc00c216116100d8578063d26ff2101161008c578063dc97d96211610071578063dc97d96214610681578063f6a5f9f5146106a1578063fbe0a31b146106b457600080fd5b8063d26ff2101461065b578063d38bfff41461066e57600080fd5b8063c031a180116100bd578063c031a180146105dc578063c82fe87a146105ef578063cec7b3591461064857600080fd5b8063bc00c216146105a9578063bd02d0f5146105bc57600080fd5b8063986e791a1161012f578063a3499c7311610114578063a3499c731461057c578063aa1e1f0a1461058f578063b54170841461059657600080fd5b8063986e791a146105495780639ded06df1461056957600080fd5b80638291286c146104ea578063886a625d14610510578063935b13f61461052357806397b87ba61461053657600080fd5b80634656ae2e116101f35780635f6970c3116101c257806367ace8eb116101a757806367ace8eb146104a05780637ae1cfca146104b35780637b1b769e146104d657600080fd5b80635f6970c31461046657806364940c561461047957600080fd5b80634656ae2e1461038e578063585a9fd4146103a15780635aa6e675146103b45780635c60da1b1461040d57600080fd5b806321f8a7211161024a57806326ef699d1161022f57806326ef699d146103415780632a2dae0a1461035457806341d8f26b1461037b57600080fd5b806321f8a721146102df578063269eb65e1461032057600080fd5b806309c5eabe1461027c578063146e2d78146102915780631876eed9146102a45780631c92115f146102cc575b600080fd5b61028f61028a366004612f28565b6106c7565b005b61028f61029f366004612f6a565b610be1565b6102b76102b2366004612fb6565b610c2a565b60405190151581526020015b60405180910390f35b61028f6102da36600461306b565b610d85565b6103086102ed366004613105565b6000908152600260205260409020546001600160a01b031690565b6040516001600160a01b0390911681526020016102c3565b61033361032e3660046131e3565b610df0565b6040519081526020016102c3565b61028f61034f366004613220565b610e04565b6103087f000000000000000000000000b28478319b64f8d47e19a120209a211d902f8b8f81565b61028f6103893660046132d8565b610e9c565b61028f61039c366004612f6a565b610fbc565b61028f6103af366004612f6a565b611403565b7fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b0316610308565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60005260026020527f11141f466c69fd409e1990e063b49cd6d61ed2ecff27a2e402e259ca6b9a01a3546001600160a01b0316610308565b6102b76104743660046132f5565b6114b1565b6103087f000000000000000000000000e3b83f79fbf01b25659f8a814945ab82186a8ad081565b61028f6104ae3660046133bc565b611591565b6102b76104c1366004613105565b60009081526004602052604090205460ff1690565b6102b76104e43660046131e3565b50600090565b7fad2ae48b4d93c587cd1f0f8f269b84f57dbe98bbe5c61c4b6d324e6a667b3625610333565b61028f61051e366004612f6a565b61177f565b6103086105313660046131e3565b611a2f565b61028f610544366004612f6a565b611a3d565b61055c610557366004613105565b611b1b565b6040516102c39190613480565b61028f610577366004612f28565b611bbd565b61028f61058a366004613493565b611d26565b60006102b7565b61028f6105a43660046134e3565b61203c565b6102b76105b73660046135af565b6120f2565b6103336105ca366004613105565b60009081526020819052604090205490565b61055c6105ea366004613105565b6121c5565b7f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d9260005260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b546001600160a01b0316610308565b6103336106563660046131e3565b6121e2565b6102b7610669366004613105565b6121fc565b61028f61067c3660046132d8565b61220a565b61033361068f366004613105565b60009081526005602052604090205490565b6102b76106af36600461367d565b6122c5565b61028f6106c2366004612f6a565b61234e565b6000806106d683850185613714565b9150915060006106ec83805190602001206123ee565b905060007f000000000000000000000000e3b83f79fbf01b25659f8a814945ab82186a8ad06001600160a01b03166373e3d66a83856040518363ffffffff1660e01b815260040161073e929190613778565b602060405180830381600087803b15801561075857600080fd5b505af115801561076c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079091906137a6565b905060006060806060878060200190518101906107ad919061394a565b929650909450925090504684146107f0576040517f7a47c9a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8251825181141580610803575081518114155b1561083a576040517fca9a28f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610bd357600085828151811061085957610859613a34565b6020026020010151905061086c816121fc565b156108775750610bc3565b60008086848151811061088c5761088c613a34565b60200260200101516040516020016108a49190613a4a565b6040516020818303038152906040528051906020012090507f5763814b98a3aa86f212797af3273868b5dd6e2a532d764a79b98ca859e7bbad81141561090c577f886a625d000000000000000000000000000000000000000000000000000000009150610ab5565b7fec78d9c22c08bb9f0ecd5d95571ae83e3f22219c5a9278c3270691d50abfd91b81141561095c577f146e2d78000000000000000000000000000000000000000000000000000000009150610ab5565b7f37ac16aabc4d87540e53151b2b716265cfd6b195db96a9daf8e893c829bbd2338114156109ac577ffbe0a31b000000000000000000000000000000000000000000000000000000009150610ab5565b7ff41504255b911b3042ee4f8786fdf7cf4bcf24ace033fa16af3c8574e025e4368114156109fc577f585a9fd4000000000000000000000000000000000000000000000000000000009150610ab5565b7fda199c0e76f665e0450020791c7f8eacc75f3cdbace313272c28f93e5390b62c811415610a4c577f4656ae2e000000000000000000000000000000000000000000000000000000009150610ab5565b7fb460dcb6fd5797fc0e7ea0f13406c80d30702ba7f73a42bd91394775dcbca718811415610aad5789610a8157505050610bc3565b600099507f97b87ba6000000000000000000000000000000000000000000000000000000009150610ab5565b505050610bc3565b610ac0836001612442565b6000306001600160a01b031683888781518110610adf57610adf613a34565b602002602001015186604051602401610af9929190613a66565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051610b379190613a4a565b6000604051808303816000865af19150503d8060008114610b74576040519150601f19603f3d011682016040523d82523d6000602084013e610b79565b606091505b505090508015610bb35760405184907fa74c8847d513feba22a0f0cb38d53081abf97562cdb293926ba243689e7c41ca90600090a2610bbe565b610bbe846000612442565b505050505b610bcc81613a9e565b905061083d565b505050505050505050505050565b333014610c01576040516314e1dbf760e11b815260040160405180910390fd5b60008080610c1185870187613ac4565b925092509250610c2283838361246e565b505050505050565b600080610cdb8b8b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8f018190048102820181019092528d815292508d91508c908190840183828082843760009201919091525050604080516020601f8d018190048102820181019092528b81523393508d9250908c908c90819084018382808284376000920191909152508c925061257d915050565b60008181526004602052604090205460ff16925090508115610d7757600081815260046020526040808220805460ff19169055518c917f91057b069763121972ce22b18b2f319b1520dd4c72f1f94a6395e81ceaf63f4191a2610d7785858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525033925087915061246e9050565b509998505050505050505050565b8181604051610d95929190613b1e565b6040518091039020336001600160a01b03167f30ae6cc78c27e651745bf2ad08a11de83910ac1e347a52f7ac898c0fbef94dae888888888888604051610de096959493929190613b57565b60405180910390a3505050505050565b6000610dfe6105ca836125e1565b92915050565b610e463384848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869250612616915050565b336001600160a01b03167f651d93f66c4329630e8d0f62488eff599e3be484da587335e8dc0fcf4606272688888888888888604051610e8b9796959493929190613ba0565b60405180910390a250505050505050565b7f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d9260005260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b546001600160a01b03163314801590610f5257507fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b03163314155b15610f705760405163223aa83d60e11b815260040160405180910390fd5b6001600160a01b038116610fb0576040517fd79d772c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fb981612821565b50565b333014610fdc576040516314e1dbf760e11b815260040160405180910390fd5b600080610feb84860186613bf1565b915091506000610ffa83611a2f565b90506001600160a01b03811661102e578260405163395d09bf60e11b81526004016110259190613480565b60405180910390fd5b600261103984612916565b600281111561104a5761104a613c36565b14156113a0576000611107836040518060200161106690612ed2565b601f1982820381018352601f9091011660408190526110889190602001613a4a565b60408051601f1981840301815282825280516020918201207fff00000000000000000000000000000000000000000000000000000000000000848301526bffffffffffffffffffffffff193060601b16602185015260358401949094526055808401949094528151808403909401845260759092019052815191012090565b905061111b816001600160a01b0316612935565b156111295750505050505050565b60008360405161113890612ed2565b8190604051809103906000f5905080158015611158573d6000803e3d6000fd5b506040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b038083166004830181905292935060009283929091631cff79cd91889163a9059cbb60e01b9130918416906370a082319060240160206040518083038186803b1580156111d257600080fd5b505afa1580156111e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120a9190613c4c565b6040516001600160a01b039092166024830152604482015260640160408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199485161790525160e085901b909216825261126b9291600401613c65565b600060405180830381600087803b15801561128557600080fd5b505af1158015611299573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112c19190810190613c87565b915091508115806112ee57508051158015906112ee5750808060200190518101906112ec91906137a6565b155b1561132757866040517fe217b0ad0000000000000000000000000000000000000000000000000000000081526004016110259190613480565b6040517ef55d9d0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0384169062f55d9d90602401600060405180830381600087803b15801561137f57600080fd5b505af1158015611393573d6000803e3d6000fd5b5050505050505050610c22565b6040516308a1eee160e01b8152600481018390526001600160a01b038216906308a1eee190602401600060405180830381600087803b1580156113e257600080fd5b505af11580156113f6573d6000803e3d6000fd5b505050505050505b505050565b333014611423576040516314e1dbf760e11b815260040160405180910390fd5b6000808080808080806114388a8c018c613ccb565b9750975097509750975097509750975061145789898989898989612978565b84866001600160a01b03168a7f9991faa1f435675159ffae64b66d7ecfdb55c29755869a18db8497b4392347e08b8b8989898960405161149c96959493929190613d89565b60405180910390a45050505050505050505050565b60008061152c8888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8c018190048102820181019092528a815292508a91508990819084018382808284376000920191909152503392508991506129a59050565b60008181526004602052604090205460ff1692509050811561158657600081815260046020526040808220805460ff191690555189917f91057b069763121972ce22b18b2f319b1520dd4c72f1f94a6395e81ceaf63f4191a25b509695505050505050565b7f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d9260005260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b546001600160a01b0316331480159061164757507fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b03163314155b156116655760405163223aa83d60e11b815260040160405180910390fd5b8281811461169f576040517f14a2275f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610c225760008686838181106116be576116be613a34565b90506020028101906116d09190613de1565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525093945088925087915085905081811061171b5761171b613a34565b90506020020135905060006001600160a01b031661173883611a2f565b6001600160a01b03161415611762578160405163395d09bf60e11b81526004016110259190613480565b61176c8282612a03565b50508061177890613a9e565b90506116a2565b33301461179f576040516314e1dbf760e11b815260040160405180910390fd5b600080808080806117b2888a018a613e28565b95509550955095509550955060006001600160a01b03166117d286611a2f565b6001600160a01b03161461181457846040517faa7e8b320000000000000000000000000000000000000000000000000000000081526004016110259190613480565b61181e8582612a03565b6001600160a01b03821661198a5760008560405160200161183f9190613a4a565b604051602081830303815290604052805190602001209050611862866001612a5b565b6000807f000000000000000000000000b28478319b64f8d47e19a120209a211d902f8b8f6001600160a01b0316636fc95b3460e01b8a8a8a8a886040516024016118b0959493929190613ecb565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516118ee9190613a4a565b600060405180830381855af49150503d8060008114611929576040519150601f19603f3d011682016040523d82523d6000602084013e61192e565b606091505b50915091508161196c57876040517f86d527430000000000000000000000000000000000000000000000000000000081526004016110259190613480565b808060200190518101906119809190613f11565b94505050506119e1565b6001600160a01b0382163b6119d6576040517fc5ccddde0000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401611025565b6119e1856002612a5b565b7fbf90b5a1ec9763e8bf4b9245cef0c28db92bab309fc2c5177f17814f382469388583604051611a12929190613f2e565b60405180910390a1611a248583612a8b565b505050505050505050565b6000610dfe6102ed83612acd565b333014611a5d576040516314e1dbf760e11b815260040160405180910390fd5b7f192e759e55f359cd9832b5c0c6e38e4b6df5c5ca33f3bd5c90738e865a5218728383604051611a8e929190613f59565b60405180910390a160405163d289d1cb60e01b81526001600160a01b037f000000000000000000000000e3b83f79fbf01b25659f8a814945ab82186a8ad0169063d289d1cb90611ae49086908690600401613f59565b600060405180830381600087803b158015611afe57600080fd5b505af1158015611b12573d6000803e3d6000fd5b50505050505050565b6000818152600160205260409020805460609190611b3890613f6d565b80601f0160208091040260200160405190810160405280929190818152602001828054611b6490613f6d565b8015611bb15780601f10611b8657610100808354040283529160200191611bb1565b820191906000526020600020905b815481529060010190602001808311611b9457829003601f168201915b50505050509050919050565b7f00000000000000000000000099b5fa03a5ea4315725c43346e55a6a6fbd940986001600160a01b0316301415611c20576040517fbf10dd3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008080611c3084860186613fa8565b919450925090506001600160a01b03831615611c4f57611c4f83612b02565b6001600160a01b03821615611c6757611c6782612821565b805115611d1f577f192e759e55f359cd9832b5c0c6e38e4b6df5c5ca33f3bd5c90738e865a52187281604051611c9d9190613480565b60405180910390a160405163d289d1cb60e01b81526001600160a01b037f000000000000000000000000e3b83f79fbf01b25659f8a814945ab82186a8ad0169063d289d1cb90611cf1908490600401613480565b600060405180830381600087803b158015611d0b57600080fd5b505af1158015611a24573d6000803e3d6000fd5b5050505050565b7fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b03163314611d9957604051632d5be4cb60e21b815260040160405180910390fd5b836001600160a01b03163f8314611ddc576040517f8f84fb2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b836001600160a01b0316638291286c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e1557600080fd5b505afa158015611e29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e4d9190613c4c565b7fad2ae48b4d93c587cd1f0f8f269b84f57dbe98bbe5c61c4b6d324e6a667b362514611ea5576040517f68155f9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038516907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2611f50847f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60005260026020527f11141f466c69fd409e1990e063b49cd6d61ed2ecff27a2e402e259ca6b9a01a3805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03831617905550565b8015612036576000846001600160a01b0316639ded06df60e01b8484604051602401611f7d929190613f59565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051611fbb9190613a4a565b600060405180830381855af49150503d8060008114611ff6576040519150601f19603f3d011682016040523d82523d6000602084013e611ffb565b606091505b5050905080611d1f576040517f97905dfb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b61207e3384848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869250612616915050565b848460405161208e929190613b1e565b6040518091039020336001600160a01b03167f7e50569d26be643bda7757722291ec66b1be66d8283474ae3fab5a98f878a7a28b8b8b8b8b8b8b8b8b6040516120df9998979695949392919061400a565b60405180910390a3505050505050505050565b60006121b66104c18c8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8d018190048102820181019092528b81528e93508d9250908c908c90819084018382808284376000920191909152508c925061257d915050565b9b9a5050505050505050505050565b6000818152600360205260409020805460609190611b3890613f6d565b6000610dfe6105ca836121f761546042614072565b612bf7565b6000610dfe6104c183612c4c565b7fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b0316331461227d57604051632d5be4cb60e21b815260040160405180910390fd5b6001600160a01b0381166122bc576040517e63186c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fb981612b02565b60006123426104c18989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8d018190048102820181019092528b815292508b91508a90819084018382808284376000920191909152508a92508991506129a59050565b98975050505050505050565b33301461236e576040516314e1dbf760e11b815260040160405180910390fd5b60008080808080612381888a018a614094565b95509550955095509550955061239a8787878787612c87565b82846001600160a01b0316887f44e4f8f6bd682c5a3aeba93601ab07cb4d1f21b2aab1ae4880d9577919309aa4898987876040516123db9493929190614126565b60405180910390a4505050505050505050565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c015b604051602081830303815290604052805190602001209050919050565b61246a61244e83612c4c565b6000908152600460205260409020805460ff1916831515179055565b5050565b600061247984611a2f565b90506001600160a01b0381166124a4578360405163395d09bf60e11b81526004016110259190613480565b6124c184836124b2876121e2565b6124bc919061415f565b612c97565b60026124cc85612916565b60028111156124dd576124dd613c36565b14156124fc576124f76001600160a01b0382168484612d12565b612036565b6040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152602482018490528216906340c10f1990604401600060405180830381600087803b15801561255f57600080fd5b505af1158015612573573d6000803e3d6000fd5b5050505050505050565b60007fb7ad972b71475860613db3ba1fe699b886c878f9002a09250dc25e769eb19a10888888888888886040516020016125be989796959493929190614177565b604051602081830303815290604052805190602001209050979650505050505050565b60007feee9348b4aaba3647b1612b2724f18e93b9299da26fb321c7b3fda135d7dea87826040516020016124259291906141ea565b600061262183611a2f565b90506001600160a01b03811661264c578260405163395d09bf60e11b81526004016110259190613480565b81612683576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061268e84612916565b905060028160028111156126a4576126a4613c36565b14156126c4576126bf6001600160a01b038316863086612d75565b611d1f565b60018160028111156126d8576126d8613c36565b141561274b57604080516001600160a01b03878116602483015260448083018790528351808403909101815260649092019092526020810180516001600160e01b03167f79cc6790000000000000000000000000000000000000000000000000000000001790526126bf91841690612dc6565b6040517f31eecaf4000000000000000000000000000000000000000000000000000000008152600060048201526127f49086906001600160a01b038516906331eecaf49060240160206040518083038186803b1580156127aa57600080fd5b505afa1580156127be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e29190613f11565b6001600160a01b038516919086612d75565b6040516308a1eee160e01b8152600060048201526001600160a01b038316906308a1eee190602401611cf1565b7f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d92600090815260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b546040516001600160a01b03848116939216917fa9303c860c5de3c0c866c354d281785c89778ac5ca2dffdf12841c45cd4e1e6e91a37f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d9260005260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03831617905550565b60006129246105ca83612e9d565b6002811115610dfe57610dfe613c36565b60006001600160a01b0382163f801580159061297157507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708114155b9392505050565b611b1261298a8888888888888861257d565b6000908152600460205260409020805460ff19166001179055565b60007f07b0d4304f82012bd3b70b1d531c160e326067c90829e2a3d386722ad10b89c386868686866040516020016129e296959493929190614210565b60405160208183030381529060405280519060200120905095945050505050565b7fd99446c1d76385bb5519ccfb5274abcfd5896dfc22405e40010fde217f018a188282604051612a34929190613a66565b60405180910390a161246a612a48836125e1565b8260009182526020829052604090912055565b61246a612a6783612e9d565b826002811115612a7957612a79613c36565b60009182526020829052604090912055565b61246a612a9783612acd565b6000908152600260205260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038416179055565b60007fc4e632779a6a7838736dd7e5e6a0eadf171dd37dfb6230720e265576dfcf42bb826040516020016124259291906141ea565b7fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f909600090815260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546040516001600160a01b03848116939216917f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce8091a37fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03831617905550565b60007f2f8851fe0d6d537e552a4f25b7a3167d48eb1292622c71d84630a2a44757bced8383604051602001612c2e93929190614260565b60405160208183030381529060405280519060200120905092915050565b604080517f957705a374326b30f4a1069c936d736cc9993ed6c820b4e0e2fd94a8beca0d1d6020820152908101829052600090606001612425565b611d1f61298a86868686866129a5565b6000612ca283610df0565b9050600081118015612cb357508082115b15612cec57826040517f037f60e50000000000000000000000000000000000000000000000000000000081526004016110259190613480565b6113fe612cff846121f761546042614072565b8360009182526020829052604090912055565b6040516001600160a01b0383166024820152604481018290526113fe90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612dc6565b6040516001600160a01b03808516602483015283166044820152606481018290526120369085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401612d3e565b600080836001600160a01b031683604051612de19190613a4a565b6000604051808303816000865af19150503d8060008114612e1e576040519150601f19603f3d011682016040523d82523d6000602084013e612e23565b606091505b50915091506000828015612e4f575081511580612e4f575081806020019051810190612e4f91906137a6565b9050801580612e6657506001600160a01b0385163b155b15611d1f576040517f045c4b0200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fa80d2259af55890618ec2eeb3ac72de4bdba22529bb14845d8a3d712d1c3f621826040516020016124259291906141ea565b6103498061428a83390190565b60008083601f840112612ef157600080fd5b50813567ffffffffffffffff811115612f0957600080fd5b602083019150836020828501011115612f2157600080fd5b9250929050565b60008060208385031215612f3b57600080fd5b823567ffffffffffffffff811115612f5257600080fd5b612f5e85828601612edf565b90969095509350505050565b600080600060408486031215612f7f57600080fd5b833567ffffffffffffffff811115612f9657600080fd5b612fa286828701612edf565b909790965060209590950135949350505050565b600080600080600080600080600060c08a8c031215612fd457600080fd5b8935985060208a013567ffffffffffffffff80821115612ff357600080fd5b612fff8d838e01612edf565b909a50985060408c013591508082111561301857600080fd5b6130248d838e01612edf565b909850965060608c0135955060808c013591508082111561304457600080fd5b506130518c828d01612edf565b9a9d999c50979a9699959894979660a00135949350505050565b6000806000806000806060878903121561308457600080fd5b863567ffffffffffffffff8082111561309c57600080fd5b6130a88a838b01612edf565b909850965060208901359150808211156130c157600080fd5b6130cd8a838b01612edf565b909650945060408901359150808211156130e657600080fd5b506130f389828a01612edf565b979a9699509497509295939492505050565b60006020828403121561311757600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561315d5761315d61311e565b604052919050565b600067ffffffffffffffff82111561317f5761317f61311e565b50601f01601f191660200190565b600082601f83011261319e57600080fd5b81356131b16131ac82613165565b613134565b8181528460208386010111156131c657600080fd5b816020850160208301376000918101602001919091529392505050565b6000602082840312156131f557600080fd5b813567ffffffffffffffff81111561320c57600080fd5b6132188482850161318d565b949350505050565b60008060008060008060006080888a03121561323b57600080fd5b873567ffffffffffffffff8082111561325357600080fd5b61325f8b838c01612edf565b909950975060208a013591508082111561327857600080fd5b6132848b838c01612edf565b909750955060408a013591508082111561329d57600080fd5b506132aa8a828b01612edf565b989b979a50959894979596606090950135949350505050565b6001600160a01b0381168114610fb957600080fd5b6000602082840312156132ea57600080fd5b8135612971816132c3565b6000806000806000806080878903121561330e57600080fd5b86359550602087013567ffffffffffffffff8082111561332d57600080fd5b6133398a838b01612edf565b9097509550604089013591508082111561335257600080fd5b5061335f89828a01612edf565b979a9699509497949695606090950135949350505050565b60008083601f84011261338957600080fd5b50813567ffffffffffffffff8111156133a157600080fd5b6020830191508360208260051b8501011115612f2157600080fd5b600080600080604085870312156133d257600080fd5b843567ffffffffffffffff808211156133ea57600080fd5b6133f688838901613377565b9096509450602087013591508082111561340f57600080fd5b5061341c87828801613377565b95989497509550505050565b60005b8381101561344357818101518382015260200161342b565b838111156120365750506000910152565b6000815180845261346c816020860160208601613428565b601f01601f19169290920160200192915050565b6020815260006129716020830184613454565b600080600080606085870312156134a957600080fd5b84356134b4816132c3565b935060208501359250604085013567ffffffffffffffff8111156134d757600080fd5b61341c87828801612edf565b600080600080600080600080600060a08a8c03121561350157600080fd5b893567ffffffffffffffff8082111561351957600080fd5b6135258d838e01612edf565b909b50995060208c013591508082111561353e57600080fd5b61354a8d838e01612edf565b909950975060408c013591508082111561356357600080fd5b61356f8d838e01612edf565b909750955060608c013591508082111561358857600080fd5b506135958c828d01612edf565b9a9d999c50979a9699959894979660800135949350505050565b60008060008060008060008060008060e08b8d0312156135ce57600080fd5b8a35995060208b013567ffffffffffffffff808211156135ed57600080fd5b6135f98e838f01612edf565b909b50995060408d013591508082111561361257600080fd5b61361e8e838f01612edf565b909950975060608d01359150613633826132c3565b90955060808c0135945060a08c0135908082111561365057600080fd5b5061365d8d828e01612edf565b9150809450508092505060c08b013590509295989b9194979a5092959850565b600080600080600080600060a0888a03121561369857600080fd5b87359650602088013567ffffffffffffffff808211156136b757600080fd5b6136c38b838c01612edf565b909850965060408a01359150808211156136dc57600080fd5b506136e98a828b01612edf565b90955093505060608801356136fd816132c3565b809250506080880135905092959891949750929550565b6000806040838503121561372757600080fd5b823567ffffffffffffffff8082111561373f57600080fd5b61374b8683870161318d565b9350602085013591508082111561376157600080fd5b5061376e8582860161318d565b9150509250929050565b8281526040602082015260006132186040830184613454565b805180151581146137a157600080fd5b919050565b6000602082840312156137b857600080fd5b61297182613791565b600067ffffffffffffffff8211156137db576137db61311e565b5060051b60200190565b60006137f36131ac84613165565b905082815283838301111561380757600080fd5b612971836020830184613428565b600082601f83011261382657600080fd5b815160206138366131ac836137c1565b82815260059290921b8401810191818101908684111561385557600080fd5b8286015b8481101561158657805167ffffffffffffffff8111156138795760008081fd5b8701603f8101891361388b5760008081fd5b61389c8986830151604084016137e5565b845250918301918301613859565b600082601f8301126138bb57600080fd5b612971838351602085016137e5565b600082601f8301126138db57600080fd5b815160206138eb6131ac836137c1565b82815260059290921b8401810191818101908684111561390a57600080fd5b8286015b8481101561158657805167ffffffffffffffff81111561392e5760008081fd5b61393c8986838b01016138aa565b84525091830191830161390e565b6000806000806080858703121561396057600080fd5b8451935060208086015167ffffffffffffffff8082111561398057600080fd5b818801915088601f83011261399457600080fd5b81516139a26131ac826137c1565b81815260059190911b8301840190848101908b8311156139c157600080fd5b938501935b828510156139df578451825293850193908501906139c6565b60408b015190985094505050808311156139f857600080fd5b613a0489848a01613815565b94506060880151925080831115613a1a57600080fd5b5050613a28878288016138ca565b91505092959194509250565b634e487b7160e01b600052603260045260246000fd5b60008251613a5c818460208701613428565b9190910192915050565b604081526000613a796040830185613454565b90508260208301529392505050565b634e487b7160e01b600052601160045260246000fd5b6000600019821415613ab257613ab2613a88565b5060010190565b80356137a1816132c3565b600080600060608486031215613ad957600080fd5b833567ffffffffffffffff811115613af057600080fd5b613afc8682870161318d565b9350506020840135613b0d816132c3565b929592945050506040919091013590565b8183823760009101908152919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b606081526000613b6b60608301888a613b2e565b8281036020840152613b7e818789613b2e565b90508281036040840152613b93818587613b2e565b9998505050505050505050565b608081526000613bb460808301898b613b2e565b8281036020840152613bc781888a613b2e565b90508281036040840152613bdc818688613b2e565b91505082606083015298975050505050505050565b60008060408385031215613c0457600080fd5b823567ffffffffffffffff811115613c1b57600080fd5b613c278582860161318d565b95602094909401359450505050565b634e487b7160e01b600052602160045260246000fd5b600060208284031215613c5e57600080fd5b5051919050565b6001600160a01b03831681526040602082015260006132186040830184613454565b60008060408385031215613c9a57600080fd5b613ca383613791565b9150602083015167ffffffffffffffff811115613cbf57600080fd5b61376e858286016138aa565b600080600080600080600080610100898b031215613ce857600080fd5b883567ffffffffffffffff80821115613d0057600080fd5b613d0c8c838d0161318d565b995060208b0135915080821115613d2257600080fd5b613d2e8c838d0161318d565b9850613d3c60408c01613ab9565b975060608b0135965060808b0135915080821115613d5957600080fd5b50613d668b828c0161318d565b989b979a50959894979660a0860135965060c08601359560e00135945092505050565b60c081526000613d9c60c0830189613454565b8281036020840152613dae8189613454565b90508281036040840152613dc28188613454565b60608401969096525050608081019290925260a0909101529392505050565b6000808335601e19843603018112613df857600080fd5b83018035915067ffffffffffffffff821115613e1357600080fd5b602001915036819003821315612f2157600080fd5b60008060008060008060c08789031215613e4157600080fd5b863567ffffffffffffffff80821115613e5957600080fd5b613e658a838b0161318d565b97506020890135915080821115613e7b57600080fd5b50613e8889828a0161318d565b955050604087013560ff81168114613e9f57600080fd5b9350606087013592506080870135613eb6816132c3565b8092505060a087013590509295509295509295565b60a081526000613ede60a0830188613454565b8281036020840152613ef08188613454565b60ff9690961660408401525050606081019290925260809091015292915050565b600060208284031215613f2357600080fd5b8151612971816132c3565b604081526000613f416040830185613454565b90506001600160a01b03831660208301529392505050565b602081526000613218602083018486613b2e565b600181811c90821680613f8157607f821691505b60208210811415613fa257634e487b7160e01b600052602260045260246000fd5b50919050565b600080600060608486031215613fbd57600080fd5b8335613fc8816132c3565b92506020840135613fd8816132c3565b9150604084013567ffffffffffffffff811115613ff457600080fd5b6140008682870161318d565b9150509250925092565b60a08152600061401e60a083018b8d613b2e565b8281036020840152614031818a8c613b2e565b9050828103604084015261404681888a613b2e565b9050828103606084015261405b818688613b2e565b9150508260808301529a9950505050505050505050565b60008261408f57634e487b7160e01b600052601260045260246000fd5b500490565b60008060008060008060c087890312156140ad57600080fd5b863567ffffffffffffffff808211156140c557600080fd5b6140d18a838b0161318d565b975060208901359150808211156140e757600080fd5b506140f489828a0161318d565b9550506040870135614105816132c3565b959894975094956060810135955060808101359460a0909101359350915050565b6080815260006141396080830187613454565b828103602084015261414b8187613454565b604084019590955250506060015292915050565b6000821982111561417257614172613a88565b500190565b60006101008a83528960208401528060408401526141978184018a613454565b905082810360608401526141ab8189613454565b90506001600160a01b03871660808401528560a084015282810360c08401526141d48186613454565b9150508260e08301529998505050505050505050565b82815260008251614202816020850160208701613428565b919091016020019392505050565b86815285602082015260c06040820152600061422f60c0830187613454565b82810360608401526142418187613454565b6001600160a01b03959095166080840152505060a00152949350505050565b8381526060602082015260006142796060830185613454565b905082604083015294935050505056fe6080604052600160005534801561001557600080fd5b50610324806100256000396000f3fe608060405234801561001057600080fd5b50600436106100355760003560e01c8062f55d9d1461003a5780631cff79cd1461004f575b600080fd5b61004d6100483660046101da565b610079565b005b61006261005d3660046101fc565b6100bb565b60405161007092919061027f565b60405180910390f35b6002600054141561009d5760405163caa30f5560e01b815260040160405180910390fd5b600260005573ffffffffffffffffffffffffffffffffffffffff8116ff5b60006060600260005414156100e35760405163caa30f5560e01b815260040160405180910390fd5b600260005573ffffffffffffffffffffffffffffffffffffffff85163b610136576040517f6f7c43f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff16848460405161015d9291906102de565b6000604051808303816000865af19150503d806000811461019a576040519150601f19603f3d011682016040523d82523d6000602084013e61019f565b606091505b50600160005590969095509350505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146101d557600080fd5b919050565b6000602082840312156101ec57600080fd5b6101f5826101b1565b9392505050565b60008060006040848603121561021157600080fd5b61021a846101b1565b9250602084013567ffffffffffffffff8082111561023757600080fd5b818601915086601f83011261024b57600080fd5b81358181111561025a57600080fd5b87602082850101111561026c57600080fd5b6020830194508093505050509250925092565b821515815260006020604081840152835180604085015260005b818110156102b557858101830151858201606001528201610299565b818111156102c7576000606083870101525b50601f01601f191692909201606001949350505050565b818382376000910190815291905056fea264697066735822122032cb5e746816b7fac95205c068b30da37bd40119a57265be331c162cae74712464736f6c63430008090033a26469706673582212207a2dbc57a1c98fee8c2369d9cf383e7218fef232e89a2c6ccc8240252688875764736f6c63430008090033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000e3b83f79fbf01b25659f8a814945ab82186a8ad0000000000000000000000000b28478319b64f8d47e19a120209a211d902f8b8f
-----Decoded View---------------
Arg [0] : authModule_ (address): 0xE3B83f79Fbf01B25659f8A814945aB82186A8AD0
Arg [1] : tokenDeployer_ (address): 0xb28478319B64f8D47e19A120209A211D902F8b8f
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000e3b83f79fbf01b25659f8a814945ab82186a8ad0
Arg [1] : 000000000000000000000000b28478319b64f8d47e19a120209a211d902f8b8f
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.