Source Code
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 16685087 | 337 days ago | Contract Creation | 0 FRAX |
Cross-Chain Transactions
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:
InterchainTokenService
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
Yes with 100 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 { IAxelarGasService } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol';
import { IAxelarGateway } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol';
import { ExpressExecutorTracker } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/express/ExpressExecutorTracker.sol';
import { Upgradable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradable/Upgradable.sol';
import { AddressBytes } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/AddressBytes.sol';
import { Multicall } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/Multicall.sol';
import { Pausable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/Pausable.sol';
import { InterchainAddressTracker } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/InterchainAddressTracker.sol';
import { IInterchainTokenService } from './interfaces/IInterchainTokenService.sol';
import { ITokenHandler } from './interfaces/ITokenHandler.sol';
import { ITokenManagerDeployer } from './interfaces/ITokenManagerDeployer.sol';
import { IInterchainTokenDeployer } from './interfaces/IInterchainTokenDeployer.sol';
import { IInterchainTokenExecutable } from './interfaces/IInterchainTokenExecutable.sol';
import { IInterchainTokenExpressExecutable } from './interfaces/IInterchainTokenExpressExecutable.sol';
import { ITokenManager } from './interfaces/ITokenManager.sol';
import { IERC20Named } from './interfaces/IERC20Named.sol';
import { IGatewayCaller } from './interfaces/IGatewayCaller.sol';
import { IMinter } from './interfaces/IMinter.sol';
import { Create3AddressFixed } from './utils/Create3AddressFixed.sol';
import { Operator } from './utils/Operator.sol';
/**
* @title The Interchain Token Service
* @notice This contract is responsible for facilitating interchain token transfers.
* It (mostly) does not handle tokens, but is responsible for the messaging that needs to occur for interchain transfers to happen.
* @dev The only storage used in this contract is for Express calls.
* Furthermore, no ether is intended to or should be sent to this contract except as part of deploy/interchainTransfer payable methods for gas payment.
*/
contract InterchainTokenService is
Upgradable,
Operator,
Pausable,
Multicall,
Create3AddressFixed,
ExpressExecutorTracker,
InterchainAddressTracker,
IInterchainTokenService
{
using AddressBytes for bytes;
using AddressBytes for address;
/**
* @dev There are two types of Axelar Gateways for cross-chain messaging:
* 1. Cross-chain messaging (GMP): The Axelar Gateway allows sending cross-chain messages.
* This is compatible across both Amplifier and consensus chains. IAxelarGateway interface exposes this functionality.
* 2. Cross-chain messaging with Gateway Token: The AxelarGateway on legacy consensus EVM connections supports this (via callContractWithToken)
* but not Amplifier chains. The gateway is cast to IAxelarGatewayWithToken when gateway tokens need to be handled.
* ITS deployments on Amplifier chains will revert when this functionality is used.
*/
IAxelarGateway public immutable gateway;
IAxelarGasService public immutable gasService;
address public immutable interchainTokenFactory;
bytes32 public immutable chainNameHash;
address public immutable interchainTokenDeployer;
address public immutable tokenManagerDeployer;
/**
* @dev Token manager implementation addresses
*/
address public immutable tokenManager;
address public immutable tokenHandler;
address public immutable gatewayCaller;
bytes32 internal constant PREFIX_INTERCHAIN_TOKEN_ID = keccak256('its-interchain-token-id');
bytes32 internal constant PREFIX_INTERCHAIN_TOKEN_SALT = keccak256('its-interchain-token-salt');
bytes32 private constant CONTRACT_ID = keccak256('interchain-token-service');
bytes32 private constant EXECUTE_SUCCESS = keccak256('its-execute-success');
bytes32 private constant EXPRESS_EXECUTE_SUCCESS = keccak256('its-express-execute-success');
/**
* @dev The message types that are sent between InterchainTokenService on different chains.
*/
uint256 private constant MESSAGE_TYPE_INTERCHAIN_TRANSFER = 0;
uint256 private constant MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN = 1;
// uint256 private constant MESSAGE_TYPE_DEPLOY_TOKEN_MANAGER = 2;
uint256 private constant MESSAGE_TYPE_SEND_TO_HUB = 3;
uint256 private constant MESSAGE_TYPE_RECEIVE_FROM_HUB = 4;
uint256 private constant MESSAGE_TYPE_LINK_TOKEN = 5;
uint256 private constant MESSAGE_TYPE_REGISTER_TOKEN_METADATA = 6;
/**
* @dev Tokens and token managers deployed via the Token Factory contract use a special deployer address.
* This removes the dependency on the address the token factory was deployed too to be able to derive the same tokenId.
*/
address internal constant TOKEN_FACTORY_DEPLOYER = address(0);
/**
* @dev Latest version of metadata that's supported.
*/
uint32 internal constant LATEST_METADATA_VERSION = 1;
/**
* @dev Chain name where ITS Hub exists. This is used for routing ITS calls via ITS hub.
* This is set as a constant, since the ITS Hub will exist on Axelar.
*/
string internal constant ITS_HUB_CHAIN_NAME = 'axelar';
bytes32 internal constant ITS_HUB_CHAIN_NAME_HASH = keccak256(abi.encodePacked(ITS_HUB_CHAIN_NAME));
/**
* @dev Special identifier that the trusted address for a chain should be set to, which indicates if the ITS call
* for that chain should be routed via the ITS hub.
*/
string internal constant ITS_HUB_ROUTING_IDENTIFIER = 'hub';
bytes32 internal constant ITS_HUB_ROUTING_IDENTIFIER_HASH = keccak256(abi.encodePacked(ITS_HUB_ROUTING_IDENTIFIER));
/**
* @notice Constructor for the Interchain Token Service.
* @dev All of the variables passed here are stored as immutable variables.
* @param tokenManagerDeployer_ The address of the TokenManagerDeployer.
* @param interchainTokenDeployer_ The address of the InterchainTokenDeployer.
* @param gateway_ The address of the AxelarGateway.
* @param gasService_ The address of the AxelarGasService.
* @param interchainTokenFactory_ The address of the InterchainTokenFactory.
* @param chainName_ The name of the chain that this contract is deployed on.
* @param tokenManagerImplementation_ The tokenManager implementation.
* @param tokenHandler_ The tokenHandler implementation.
* @param gatewayCaller_ The gatewayCaller implementation.
*/
constructor(
address tokenManagerDeployer_,
address interchainTokenDeployer_,
address gateway_,
address gasService_,
address interchainTokenFactory_,
string memory chainName_,
address tokenManagerImplementation_,
address tokenHandler_,
address gatewayCaller_
) {
if (
gasService_ == address(0) ||
tokenManagerDeployer_ == address(0) ||
interchainTokenDeployer_ == address(0) ||
gateway_ == address(0) ||
interchainTokenFactory_ == address(0) ||
tokenManagerImplementation_ == address(0) ||
tokenHandler_ == address(0) ||
gatewayCaller_ == address(0)
) revert ZeroAddress();
gateway = IAxelarGateway(gateway_);
gasService = IAxelarGasService(gasService_);
tokenManagerDeployer = tokenManagerDeployer_;
interchainTokenDeployer = interchainTokenDeployer_;
interchainTokenFactory = interchainTokenFactory_;
if (bytes(chainName_).length == 0) revert InvalidChainName();
chainNameHash = keccak256(bytes(chainName_));
tokenManager = tokenManagerImplementation_;
tokenHandler = tokenHandler_;
gatewayCaller = gatewayCaller_;
}
/*******\
MODIFIERS
\*******/
/**
* @notice This modifier is used to ensure that only a remote InterchainTokenService can invoke the execute function.
* @param sourceChain The source chain of the contract call.
* @param sourceAddress The source address that the call came from.
*/
modifier onlyRemoteService(string calldata sourceChain, string calldata sourceAddress) {
if (!isTrustedAddress(sourceChain, sourceAddress)) revert NotRemoteService();
_;
}
/**
* @notice This modifier is used to ensure that only a the token factory can call a function.
*/
modifier onlyTokenFactory() {
if (msg.sender != interchainTokenFactory) revert NotInterchainTokenFactory(msg.sender);
_;
}
/*****\
GETTERS
\*****/
/**
* @notice Getter for the contract id.
* @return bytes32 The contract id of this contract.
*/
function contractId() external pure returns (bytes32) {
return CONTRACT_ID;
}
/**
* @notice Calculates the address of a TokenManager from a specific tokenId.
* @dev The TokenManager does not need to exist already.
* @param tokenId The tokenId.
* @return tokenManagerAddress_ The deployment address of the TokenManager.
*/
function tokenManagerAddress(bytes32 tokenId) public view returns (address tokenManagerAddress_) {
tokenManagerAddress_ = _create3Address(tokenId);
}
/**
* @notice Returns the instance of ITokenManager from a specific tokenId.
* @dev This function checks if a token manager contract exists at the address for the specified tokenId.
* If no token manager is deployed for the tokenId, the function will revert with `TokenManagerDoesNotExist`.
* @param tokenId The tokenId of the deployed token manager.
* @return tokenManager_ The instance of ITokenManager associated with the specified tokenId.
*/
function deployedTokenManager(bytes32 tokenId) public view returns (ITokenManager tokenManager_) {
address tokenManagerAddress_ = tokenManagerAddress(tokenId);
if (tokenManagerAddress_.code.length == 0) revert TokenManagerDoesNotExist(tokenId);
tokenManager_ = ITokenManager(tokenManagerAddress_);
}
/**
* @notice Returns the address of the token that an existing tokenManager points to.
* @dev This function requires that a token manager is already deployed for the specified tokenId.
* It will call `deployedTokenManager` to get the token manager and return the address of the associated token.
* @param tokenId The tokenId of the registered token.
* @return tokenAddress The address of the token.
*/
function registeredTokenAddress(bytes32 tokenId) public view returns (address tokenAddress) {
tokenAddress = ITokenManager(deployedTokenManager(tokenId)).tokenAddress();
}
/**
* @notice Returns the address of the interchain token associated with the given tokenId.
* @dev The token does not need to exist.
* @param tokenId The tokenId of the interchain token.
* @return tokenAddress The address of the interchain token.
*/
function interchainTokenAddress(bytes32 tokenId) public view returns (address tokenAddress) {
tokenId = _getInterchainTokenSalt(tokenId);
tokenAddress = _create3Address(tokenId);
}
/**
* @notice Calculates the tokenId that would correspond to a link for a given deployer with a specified salt.
* @param sender The address of the TokenManager deployer.
* @param salt The salt that the deployer uses for the deployment.
* @return tokenId The tokenId that the custom TokenManager would get (or has gotten).
*/
function interchainTokenId(address sender, bytes32 salt) public pure returns (bytes32 tokenId) {
tokenId = keccak256(abi.encode(PREFIX_INTERCHAIN_TOKEN_ID, sender, salt));
}
/**
* @notice Getter function for TokenManager implementation. This will mainly be called by TokenManager proxies
* to figure out their implementations.
* @return tokenManagerAddress The address of the TokenManager implementation.
*/
function tokenManagerImplementation(uint256 /*tokenManagerType*/) external view returns (address) {
return tokenManager;
}
/************\
USER FUNCTIONS
\************/
/**
* @notice Registers metadata for a token on the ITS Hub. This metadata is used for scaling linked tokens.
* The token metadata must be registered before linkToken can be called for the corresponding token.
* @param tokenAddress The address of the token.
* @param gasValue The cross-chain gas value for sending the registration message to ITS Hub.
*/
function registerTokenMetadata(address tokenAddress, uint256 gasValue) external payable {
if (tokenAddress == address(0)) revert EmptyTokenAddress();
uint8 decimals = IERC20Named(tokenAddress).decimals();
bytes memory payload = abi.encode(MESSAGE_TYPE_REGISTER_TOKEN_METADATA, tokenAddress.toBytes(), decimals);
emit TokenMetadataRegistered(tokenAddress, decimals);
_callContract(
ITS_HUB_CHAIN_NAME,
trustedAddress(ITS_HUB_CHAIN_NAME),
payload,
IGatewayCaller.MetadataVersion.CONTRACT_CALL,
gasValue
);
}
/**
* @notice Only to be used by the InterchainTokenFactory to register custom tokens to this chain. Then link token can be used to register those tokens to other chains.
* @param salt A unique salt to derive tokenId from.
* @param tokenManagerType The type of the token manager to use for the token registration.
* @param linkParams The operator for the token.
*/
function registerCustomToken(
bytes32 salt,
address tokenAddress,
TokenManagerType tokenManagerType,
bytes calldata linkParams
) external payable whenNotPaused onlyTokenFactory returns (bytes32 tokenId) {
// Custom token managers can't be deployed with native interchain token type, which is reserved for interchain tokens
if (tokenManagerType == TokenManagerType.NATIVE_INTERCHAIN_TOKEN) revert CannotDeploy(tokenManagerType);
address deployer = TOKEN_FACTORY_DEPLOYER;
tokenId = interchainTokenId(deployer, salt);
emit InterchainTokenIdClaimed(tokenId, deployer, salt);
_deployTokenManager(tokenId, tokenManagerType, tokenAddress, linkParams);
}
/**
* @notice If `destinationChain` is an empty string, this function will register the token address on the current chain.
* Otherwise, it will link the token address on the destination chain with the token corresponding to the tokenId on the current chain.
* A token manager is deployed on EVM chains that's responsible for managing the linked token.
* @dev This function replaces the prior `deployTokenManager` function.
* @param salt A unique identifier to allow for multiple tokens registered per deployer.
* @param destinationChain The chain to link the token to. Pass an empty string for this chain.
* @param destinationTokenAddress The token address to link, as bytes.
* @param tokenManagerType The type of the token manager to use to send and receive tokens.
* @param linkParams Additional parameteres to use to link the token. Fow not it is just the address of the operator.
* @param gasValue Pass a non-zero value only for remote linking, which should be the gas to use to pay for the contract call.
* @return tokenId The tokenId associated with the token manager.
*/
function linkToken(
bytes32 salt,
string calldata destinationChain,
bytes calldata destinationTokenAddress,
TokenManagerType tokenManagerType,
bytes calldata linkParams,
uint256 gasValue
) public payable whenNotPaused returns (bytes32 tokenId) {
if (destinationTokenAddress.length == 0) revert EmptyTokenAddress();
// Custom token managers can't be deployed with native interchain token type, which is reserved for interchain tokens
if (tokenManagerType == TokenManagerType.NATIVE_INTERCHAIN_TOKEN) revert CannotDeploy(tokenManagerType);
// Cannot deploy to this chain using linkToken anymore
if (bytes(destinationChain).length == 0) {
revert NotSupported();
}
// Cannot deploy to this chain using linkToken anymore
if (chainNameHash == keccak256(bytes(destinationChain))) revert CannotDeployRemotelyToSelf();
address deployer = msg.sender;
if (deployer == interchainTokenFactory) {
deployer = TOKEN_FACTORY_DEPLOYER;
}
tokenId = interchainTokenId(deployer, salt);
emit InterchainTokenIdClaimed(tokenId, deployer, salt);
bytes memory sourceTokenAddress = registeredTokenAddress(tokenId).toBytes();
emit LinkTokenStarted(tokenId, destinationChain, sourceTokenAddress, destinationTokenAddress, tokenManagerType, linkParams);
bytes memory payload = abi.encode(
MESSAGE_TYPE_LINK_TOKEN,
tokenId,
tokenManagerType,
sourceTokenAddress,
destinationTokenAddress,
linkParams
);
_routeMessage(destinationChain, payload, IGatewayCaller.MetadataVersion.CONTRACT_CALL, gasValue);
}
/**
* @notice Used to deploy an interchain token alongside a TokenManager in another chain.
* @dev At least the `gasValue` amount of native token must be passed to the function call. `gasValue` exists because this function can be
* part of a multicall involving multiple functions that could make remote contract calls.
* If minter is empty bytes, no additional minter is set on the token, only ITS is allowed to mint.
* If the token is being deployed on the current chain, minter should correspond to an EVM address (as bytes).
* Otherwise, an encoding appropriate to the destination chain should be used.
* @param salt The salt to be used during deployment.
* @param destinationChain The name of the destination chain to deploy to.
* @param name The name of the token to be deployed.
* @param symbol The symbol of the token to be deployed.
* @param decimals The decimals of the token to be deployed.
* @param minter The address that will be able to mint and burn the deployed token.
* @param gasValue The amount of native tokens to be used to pay for gas for the remote deployment.
* @return tokenId The tokenId corresponding to the deployed InterchainToken.
*/
function deployInterchainToken(
bytes32 salt,
string calldata destinationChain,
string memory name,
string memory symbol,
uint8 decimals,
bytes memory minter,
uint256 gasValue
) external payable whenNotPaused onlyTokenFactory returns (bytes32 tokenId) {
address deployer = TOKEN_FACTORY_DEPLOYER;
tokenId = interchainTokenId(deployer, salt);
emit InterchainTokenIdClaimed(tokenId, deployer, salt);
if (bytes(destinationChain).length == 0) {
address tokenAddress = _deployInterchainToken(tokenId, minter, name, symbol, decimals);
_deployTokenManager(tokenId, TokenManagerType.NATIVE_INTERCHAIN_TOKEN, tokenAddress, minter);
} else {
if (chainNameHash == keccak256(bytes(destinationChain))) revert CannotDeployRemotelyToSelf();
_deployRemoteInterchainToken(tokenId, name, symbol, decimals, minter, destinationChain, gasValue);
}
}
/**
* @notice Returns the amount of token that this call is worth.
* @dev If `tokenAddress` is `0`, then value is in terms of the native token, otherwise it's in terms of the token address.
* @param sourceChain The source chain.
* @param sourceAddress The source address on the source chain.
* @param payload The payload sent with the call.
* @return address The token address.
* @return uint256 The value the call is worth.
*/
function contractCallValue(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload
) public view virtual onlyRemoteService(sourceChain, sourceAddress) whenNotPaused returns (address, uint256) {
return _contractCallValue(payload);
}
/**
* @notice Executes the cross-chain ITS message.
* @param commandId The unique message id.
* @param sourceChain The chain where the transaction originates from.
* @param sourceAddress The address of the remote ITS where the transaction originates from.
* @param payload The encoded data payload for the transaction.
*/
function execute(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload
) external onlyRemoteService(sourceChain, sourceAddress) whenNotPaused {
bytes32 payloadHash = keccak256(payload);
if (!gateway.validateContractCall(commandId, sourceChain, sourceAddress, payloadHash)) revert NotApprovedByGateway();
_execute(commandId, sourceChain, sourceAddress, payload, payloadHash);
}
/**
* @notice Express executes operations based on the payload and selector.
* @dev This function is `payable` because non-payable functions cannot be called in a multicall that calls other `payable` functions.
* @param commandId The unique message id.
* @param sourceChain The chain where the transaction originates from.
* @param sourceAddress The address of the remote ITS where the transaction originates from.
* @param payload The encoded data payload for the transaction.
*/
function expressExecute(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload
) public payable whenNotPaused {
uint256 messageType = abi.decode(payload, (uint256));
if (messageType != MESSAGE_TYPE_INTERCHAIN_TRANSFER) {
revert InvalidExpressMessageType(messageType);
}
if (gateway.isCommandExecuted(commandId)) revert AlreadyExecuted();
address expressExecutor = msg.sender;
bytes32 payloadHash = keccak256(payload);
emit ExpressExecuted(commandId, sourceChain, sourceAddress, payloadHash, expressExecutor);
_setExpressExecutor(commandId, sourceChain, sourceAddress, payloadHash, expressExecutor);
_expressExecute(commandId, sourceChain, payload);
}
/**
* @notice Returns the express executor for a given command.
* @param commandId The commandId for the contractCall.
* @param sourceChain The source chain.
* @param sourceAddress The source address.
* @param payloadHash The hash of the payload.
* @return expressExecutor The address of the express executor.
*/
function getExpressExecutor(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash
) external view returns (address expressExecutor) {
expressExecutor = _getExpressExecutor(commandId, sourceChain, sourceAddress, payloadHash);
}
/**
* @notice Uses the caller's tokens to fullfill a sendCall ahead of time. Use this only if you have detected an outgoing
* interchainTransfer that matches the parameters passed here.
* @param commandId The unique message id of the transfer being expressed.
* @param sourceChain the name of the chain where the interchainTransfer originated from.
* @param payload the payload of the receive token
*/
function _expressExecute(bytes32 commandId, string calldata sourceChain, bytes calldata payload) internal {
(, bytes32 tokenId, bytes memory sourceAddress, bytes memory destinationAddressBytes, uint256 amount, bytes memory data) = abi
.decode(payload, (uint256, bytes32, bytes, bytes, uint256, bytes));
address destinationAddress = destinationAddressBytes.toAddress();
IERC20 token;
{
(bool success, bytes memory returnData) = tokenHandler.delegatecall(
abi.encodeWithSelector(ITokenHandler.transferTokenFrom.selector, tokenId, msg.sender, destinationAddress, amount)
);
if (!success) revert TokenHandlerFailed(returnData);
(amount, token) = abi.decode(returnData, (uint256, IERC20));
}
// slither-disable-next-line reentrancy-events
emit InterchainTransferReceived(
commandId,
tokenId,
sourceChain,
sourceAddress,
destinationAddress,
amount,
data.length == 0 ? bytes32(0) : keccak256(data)
);
if (data.length != 0) {
bytes32 result = IInterchainTokenExpressExecutable(destinationAddress).expressExecuteWithInterchainToken(
commandId,
sourceChain,
sourceAddress,
data,
tokenId,
address(token),
amount
);
if (result != EXPRESS_EXECUTE_SUCCESS) revert ExpressExecuteWithInterchainTokenFailed(destinationAddress);
}
}
/**
* @notice Initiates an interchain transfer of a specified token to a destination chain.
* @dev The function retrieves the TokenManager associated with the tokenId.
* @param tokenId The unique identifier of the token to be transferred.
* @param destinationChain The destination chain to send the tokens to.
* @param destinationAddress The address on the destination chain to send the tokens to.
* @param amount The amount of tokens to be transferred.
* @param metadata Optional metadata for the transfer. The first 4 bytes is the metadata version. To call the `destinationAddress` as a contract with a payload, provide `bytes.concat(bytes4(0), payload)` as the metadata. The token will be transferred to the destination app contract before it is executed.
*/
function interchainTransfer(
bytes32 tokenId,
string calldata destinationChain,
bytes calldata destinationAddress,
uint256 amount,
bytes calldata metadata,
uint256 gasValue
) external payable whenNotPaused {
amount = _takeToken(tokenId, msg.sender, amount, false);
(IGatewayCaller.MetadataVersion metadataVersion, bytes memory data) = _decodeMetadata(metadata);
_transmitInterchainTransfer(tokenId, msg.sender, destinationChain, destinationAddress, amount, metadataVersion, data, gasValue);
}
/******************\
TOKEN ONLY FUNCTIONS
\******************/
/**
* @notice Transmit an interchain transfer for the given tokenId.
* @dev Only callable by a token registered under a tokenId.
* @param tokenId The tokenId of the token (which must be the msg.sender).
* @param sourceAddress The address where the token is coming from.
* @param destinationChain The name of the chain to send tokens to.
* @param destinationAddress The destinationAddress for the interchainTransfer.
* @param amount The amount of token to give.
* @param metadata Optional metadata for the call for additional effects (such as calling a destination contract).
*/
function transmitInterchainTransfer(
bytes32 tokenId,
address sourceAddress,
string calldata destinationChain,
bytes memory destinationAddress,
uint256 amount,
bytes calldata metadata
) external payable whenNotPaused {
amount = _takeToken(tokenId, sourceAddress, amount, true);
(IGatewayCaller.MetadataVersion metadataVersion, bytes memory data) = _decodeMetadata(metadata);
_transmitInterchainTransfer(tokenId, sourceAddress, destinationChain, destinationAddress, amount, metadataVersion, data, msg.value);
}
/*************\
OWNER FUNCTIONS
\*************/
/**
* @notice Used to set a flow limit for a token manager that has the service as its operator.
* @param tokenIds An array of the tokenIds of the tokenManagers to set the flow limits of.
* @param flowLimits The flowLimits to set.
*/
function setFlowLimits(bytes32[] calldata tokenIds, uint256[] calldata flowLimits) external onlyRole(uint8(Roles.OPERATOR)) {
uint256 length = tokenIds.length;
if (length != flowLimits.length) revert LengthMismatch();
for (uint256 i; i < length; ++i) {
// slither-disable-next-line calls-loop
deployedTokenManager(tokenIds[i]).setFlowLimit(flowLimits[i]);
}
}
/**
* @notice Used to set a trusted address for a chain.
* @param chain The chain to set the trusted address of.
* @param address_ The address to set as trusted.
*/
function setTrustedAddress(string memory chain, string memory address_) external onlyOwner {
_setTrustedAddress(chain, address_);
}
/**
* @notice Used to remove a trusted address for a chain.
* @param chain The chain to set the trusted address of.
*/
function removeTrustedAddress(string memory chain) external onlyOwner {
_removeTrustedAddress(chain);
}
/**
* @notice Allows the owner to pause/unpause the token service.
* @param paused Boolean value representing whether to pause or unpause.
*/
function setPauseStatus(bool paused) external onlyOwner {
if (paused) {
_pause();
} else {
_unpause();
}
}
/**
* @notice Allows the owner to migrate minter of native interchain tokens from ITS to the corresponding token manager.
* @param tokenId the tokenId of the registered token.
*/
function migrateInterchainToken(bytes32 tokenId) external onlyOwner {
ITokenManager tokenManager_ = deployedTokenManager(tokenId);
address tokenAddress = tokenManager_.tokenAddress();
IMinter(tokenAddress).transferMintership(address(tokenManager_));
}
/****************\
INTERNAL FUNCTIONS
\****************/
function _setup(bytes calldata params) internal override {
(address operator, string memory chainName_, string[] memory trustedChainNames, string[] memory trustedAddresses) = abi.decode(
params,
(address, string, string[], string[])
);
uint256 length = trustedChainNames.length;
if (operator == address(0)) revert ZeroAddress();
if (bytes(chainName_).length == 0 || keccak256(bytes(chainName_)) != chainNameHash) revert InvalidChainName();
if (length != trustedAddresses.length) revert LengthMismatch();
_addOperator(operator);
_setChainName(chainName_);
for (uint256 i; i < length; ++i) {
_setTrustedAddress(trustedChainNames[i], trustedAddresses[i]);
}
}
/**
* @notice Processes the payload data for a send token call.
* @param commandId The unique message id.
* @param expressExecutor The address of the express executor. Equals `address(0)` if it wasn't expressed.
* @param sourceChain The chain where the transaction originates from.
* @param payload The encoded data payload to be processed.
*/
function _processInterchainTransferPayload(
bytes32 commandId,
address expressExecutor,
string memory sourceChain,
bytes memory payload
) internal {
bytes32 tokenId;
bytes memory sourceAddress;
address destinationAddress;
uint256 amount;
bytes memory data;
{
bytes memory destinationAddressBytes;
(, tokenId, sourceAddress, destinationAddressBytes, amount, data) = abi.decode(
payload,
(uint256, bytes32, bytes, bytes, uint256, bytes)
);
destinationAddress = destinationAddressBytes.toAddress();
}
// Return token to the express executor
if (expressExecutor != address(0)) {
_giveToken(tokenId, expressExecutor, amount);
return;
}
address tokenAddress;
(amount, tokenAddress) = _giveToken(tokenId, destinationAddress, amount);
// slither-disable-next-line reentrancy-events
emit InterchainTransferReceived(
commandId,
tokenId,
sourceChain,
sourceAddress,
destinationAddress,
amount,
data.length == 0 ? bytes32(0) : keccak256(data)
);
if (data.length != 0) {
bytes32 result = IInterchainTokenExecutable(destinationAddress).executeWithInterchainToken(
commandId,
sourceChain,
sourceAddress,
data,
tokenId,
tokenAddress,
amount
);
if (result != EXECUTE_SUCCESS) revert ExecuteWithInterchainTokenFailed(destinationAddress);
}
}
/**
* @notice Processes a deploy token manager payload.
*/
function _processLinkTokenPayload(bytes memory payload) internal {
(, bytes32 tokenId, TokenManagerType tokenManagerType, , bytes memory destinationTokenAddress, bytes memory linkParams) = abi
.decode(payload, (uint256, bytes32, TokenManagerType, bytes, bytes, bytes));
if (tokenManagerType == TokenManagerType.NATIVE_INTERCHAIN_TOKEN) revert CannotDeploy(tokenManagerType);
_deployTokenManager(tokenId, tokenManagerType, destinationTokenAddress.toAddress(), linkParams);
}
/**
* @notice Processes a deploy interchain token manager payload.
* @param payload The encoded data payload to be processed.
*/
function _processDeployInterchainTokenPayload(bytes memory payload) internal {
(, bytes32 tokenId, string memory name, string memory symbol, uint8 decimals, bytes memory minterBytes) = abi.decode(
payload,
(uint256, bytes32, string, string, uint8, bytes)
);
address tokenAddress;
tokenAddress = _deployInterchainToken(tokenId, minterBytes, name, symbol, decimals);
_deployTokenManager(tokenId, TokenManagerType.NATIVE_INTERCHAIN_TOKEN, tokenAddress, minterBytes);
}
/**
* @notice Route the ITS message to the destination chain with the given payload
* @dev This method also determines whether the ITS call should be routed via the ITS Hub.
* If the `trustedAddress(destinationChain) == 'hub'`, then the call is wrapped and routed to the ITS Hub destination.
* @param destinationChain The target chain where the contract will be called.
* @param payload The data payload for the transaction.
* @param gasValue The amount of gas to be paid for the transaction.
*/
function _routeMessage(
string memory destinationChain,
bytes memory payload,
IGatewayCaller.MetadataVersion metadataVersion,
uint256 gasValue
) internal {
string memory destinationAddress;
(destinationChain, destinationAddress, payload) = _getCallParams(destinationChain, payload);
_callContract(destinationChain, destinationAddress, payload, metadataVersion, gasValue);
}
/**
* @notice Calls a contract on a destination chain via the gateway caller.
* @param destinationChain The chain where the contract will be called.
* @param destinationAddress The address of the contract to call.
* @param payload The data payload for the transaction.
* @param metadataVersion The version of the metadata.
* @param gasValue The amount of gas to be paid for the transaction.
*/
function _callContract(
string memory destinationChain,
string memory destinationAddress,
bytes memory payload,
IGatewayCaller.MetadataVersion metadataVersion,
uint256 gasValue
) internal {
// Check whether no trusted address was set for the destination chain
if (bytes(destinationAddress).length == 0) revert UntrustedChain();
(bool success, bytes memory returnData) = gatewayCaller.delegatecall(
abi.encodeWithSelector(
IGatewayCaller.callContract.selector,
destinationChain,
destinationAddress,
payload,
metadataVersion,
gasValue
)
);
if (!success) revert GatewayCallFailed(returnData);
}
/**
* @dev Get the params for the cross-chain message, taking routing via ITS Hub into account.
*/
function _getCallParams(
string memory destinationChain,
bytes memory payload
) internal view returns (string memory, string memory, bytes memory) {
string memory destinationAddress = trustedAddress(destinationChain);
// Prevent sending directly to the ITS Hub chain. This is not supported yet, so fail early to prevent the user from having their funds stuck.
if (keccak256(abi.encodePacked(destinationChain)) == ITS_HUB_CHAIN_NAME_HASH) revert UntrustedChain();
// Check whether the ITS call should be routed via ITS hub for this destination chain
if (keccak256(abi.encodePacked(destinationAddress)) == ITS_HUB_ROUTING_IDENTIFIER_HASH) {
// Wrap ITS message in an ITS Hub message
payload = abi.encode(MESSAGE_TYPE_SEND_TO_HUB, destinationChain, payload);
destinationChain = ITS_HUB_CHAIN_NAME;
destinationAddress = trustedAddress(ITS_HUB_CHAIN_NAME);
}
return (destinationChain, destinationAddress, payload);
}
function _execute(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes memory payload,
bytes32 payloadHash
) internal {
uint256 messageType;
string memory originalSourceChain;
(messageType, originalSourceChain, payload) = _getExecuteParams(sourceChain, payload);
if (messageType == MESSAGE_TYPE_INTERCHAIN_TRANSFER) {
address expressExecutor = _getExpressExecutorAndEmitEvent(commandId, sourceChain, sourceAddress, payloadHash);
_processInterchainTransferPayload(commandId, expressExecutor, originalSourceChain, payload);
} else if (messageType == MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) {
_processDeployInterchainTokenPayload(payload);
} else if (messageType == MESSAGE_TYPE_LINK_TOKEN) {
_processLinkTokenPayload(payload);
} else {
revert InvalidMessageType(messageType);
}
}
function _getMessageType(bytes memory payload) internal pure returns (uint256 messageType) {
if (payload.length < 32) revert InvalidPayload();
/// @solidity memory-safe-assembly
assembly {
messageType := mload(add(payload, 32))
}
}
/**
* @dev Return the parameters for the execute call, taking routing via ITS Hub into account.
*/
function _getExecuteParams(
string calldata sourceChain,
bytes memory payload
) internal view returns (uint256, string memory, bytes memory) {
// Read the first 32 bytes of the payload to determine the message type
uint256 messageType = _getMessageType(payload);
// True source chain, this is overridden if the ITS call is coming via the ITS hub
string memory originalSourceChain = sourceChain;
// Unwrap ITS message if coming from ITS hub
if (messageType == MESSAGE_TYPE_RECEIVE_FROM_HUB) {
if (keccak256(abi.encodePacked(sourceChain)) != ITS_HUB_CHAIN_NAME_HASH) revert UntrustedChain();
(, originalSourceChain, payload) = abi.decode(payload, (uint256, string, bytes));
// Check whether the original source chain is expected to be routed via the ITS Hub
if (trustedAddressHash(originalSourceChain) != ITS_HUB_ROUTING_IDENTIFIER_HASH) revert UntrustedChain();
// Get message type of the inner ITS message
messageType = _getMessageType(payload);
} else {
// Prevent receiving a direct message from the ITS Hub. This is not supported yet.
if (keccak256(abi.encodePacked(sourceChain)) == ITS_HUB_CHAIN_NAME_HASH) revert UntrustedChain();
}
return (messageType, originalSourceChain, payload);
}
/**
* @notice Deploys an interchain token on a destination chain.
* @param tokenId The ID of the token.
* @param name The name of the token.
* @param symbol The symbol of the token.
* @param decimals The number of decimals of the token.
* @param minter The minter address for the token.
* @param destinationChain The destination chain where the token will be deployed.
* @param gasValue The amount of gas to be paid for the transaction.
*/
function _deployRemoteInterchainToken(
bytes32 tokenId,
string memory name,
string memory symbol,
uint8 decimals,
bytes memory minter,
string calldata destinationChain,
uint256 gasValue
) internal {
if (bytes(name).length == 0) revert EmptyTokenName();
if (bytes(symbol).length == 0) revert EmptyTokenSymbol();
// slither-disable-next-line unused-return
deployedTokenManager(tokenId);
// slither-disable-next-line reentrancy-events
emit InterchainTokenDeploymentStarted(tokenId, name, symbol, decimals, minter, destinationChain);
bytes memory payload = abi.encode(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN, tokenId, name, symbol, decimals, minter);
_routeMessage(destinationChain, payload, IGatewayCaller.MetadataVersion.CONTRACT_CALL, gasValue);
}
/**
* @notice Deploys a token manager.
* @param tokenId The ID of the token.
* @param tokenManagerType The type of the token manager to be deployed.
* @param tokenAddress The address of the token to be managed.
* @param operator The operator of the token manager.
*/
function _deployTokenManager(bytes32 tokenId, TokenManagerType tokenManagerType, address tokenAddress, bytes memory operator) internal {
// TokenManagerProxy params
bytes memory params = abi.encode(operator, tokenAddress);
(bool success, bytes memory returnData) = tokenManagerDeployer.delegatecall(
abi.encodeWithSelector(ITokenManagerDeployer.deployTokenManager.selector, tokenId, tokenManagerType, params)
);
if (!success) revert TokenManagerDeploymentFailed(returnData);
address tokenManager_;
assembly {
tokenManager_ := mload(add(returnData, 0x20))
}
(success, returnData) = tokenHandler.delegatecall(
abi.encodeWithSelector(ITokenHandler.postTokenManagerDeploy.selector, tokenManagerType, tokenManager_)
);
if (!success) revert PostDeployFailed(returnData);
// slither-disable-next-line reentrancy-events
emit TokenManagerDeployed(tokenId, tokenManager_, tokenManagerType, params);
}
/**
* @notice Computes the salt for an interchain token deployment.
* @param tokenId The ID of the token.
* @return salt The computed salt for the token deployment.
*/
function _getInterchainTokenSalt(bytes32 tokenId) internal pure returns (bytes32 salt) {
salt = keccak256(abi.encode(PREFIX_INTERCHAIN_TOKEN_SALT, tokenId));
}
/**
* @notice Deploys an interchain token.
* @param tokenId The ID of the token.
* @param minterBytes The minter address for the token.
* @param name The name of the token.
* @param symbol The symbol of the token.
* @param decimals The number of decimals of the token.
*/
function _deployInterchainToken(
bytes32 tokenId,
bytes memory minterBytes,
string memory name,
string memory symbol,
uint8 decimals
) internal returns (address tokenAddress) {
if (bytes(name).length == 0) revert EmptyTokenName();
if (bytes(symbol).length == 0) revert EmptyTokenSymbol();
bytes32 salt = _getInterchainTokenSalt(tokenId);
address minter;
if (bytes(minterBytes).length != 0) minter = minterBytes.toAddress();
(bool success, bytes memory returnData) = interchainTokenDeployer.delegatecall(
abi.encodeWithSelector(IInterchainTokenDeployer.deployInterchainToken.selector, salt, tokenId, minter, name, symbol, decimals)
);
if (!success) {
revert InterchainTokenDeploymentFailed(returnData);
}
assembly {
tokenAddress := mload(add(returnData, 0x20))
}
// slither-disable-next-line reentrancy-events
emit InterchainTokenDeployed(tokenId, tokenAddress, minter, name, symbol, decimals);
}
/**
* @notice Decodes the metadata into a version number and data bytes.
* @dev The function expects the metadata to have the version in the first 4 bytes, followed by the actual data.
* @param metadata The bytes containing the metadata to decode.
* @return version The version number extracted from the metadata.
* @return data The data bytes extracted from the metadata.
*/
function _decodeMetadata(bytes calldata metadata) internal pure returns (IGatewayCaller.MetadataVersion version, bytes memory data) {
if (metadata.length < 4) return (IGatewayCaller.MetadataVersion.CONTRACT_CALL, data);
uint32 versionUint = uint32(bytes4(metadata[:4]));
if (versionUint > LATEST_METADATA_VERSION) revert InvalidMetadataVersion(versionUint);
version = IGatewayCaller.MetadataVersion(versionUint);
if (metadata.length == 4) return (version, data);
data = metadata[4:];
}
/**
* @notice Transmit a callContractWithInterchainToken for the given tokenId.
* @param tokenId The tokenId of the TokenManager (which must be the msg.sender).
* @param sourceAddress The address where the token is coming from, which will also be used for gas reimbursement.
* @param destinationChain The name of the chain to send tokens to.
* @param destinationAddress The destinationAddress for the interchainTransfer.
* @param amount The amount of tokens to send.
* @param metadataVersion The version of the metadata.
* @param data The data to be passed with the token transfer.
* @param gasValue The amount of gas to be paid for the transaction.
*/
function _transmitInterchainTransfer(
bytes32 tokenId,
address sourceAddress,
string calldata destinationChain,
bytes memory destinationAddress,
uint256 amount,
IGatewayCaller.MetadataVersion metadataVersion,
bytes memory data,
uint256 gasValue
) internal {
if (destinationAddress.length == 0) revert EmptyDestinationAddress();
if (amount == 0) revert ZeroAmount();
// slither-disable-next-line reentrancy-events
emit InterchainTransfer(
tokenId,
sourceAddress,
destinationChain,
destinationAddress,
amount,
data.length == 0 ? bytes32(0) : keccak256(data)
);
bytes memory payload = abi.encode(
MESSAGE_TYPE_INTERCHAIN_TRANSFER,
tokenId,
sourceAddress.toBytes(),
destinationAddress,
amount,
data
);
_routeMessage(destinationChain, payload, metadataVersion, gasValue);
}
/**
* @dev Takes token from a sender via the token service. `tokenOnly` indicates if the caller should be restricted to the token only.
*/
function _takeToken(bytes32 tokenId, address from, uint256 amount, bool tokenOnly) internal returns (uint256) {
(bool success, bytes memory data) = tokenHandler.delegatecall(
abi.encodeWithSelector(ITokenHandler.takeToken.selector, tokenId, tokenOnly, from, amount)
);
if (!success) revert TakeTokenFailed(data);
amount = abi.decode(data, (uint256));
return amount;
}
/**
* @dev Gives token to recipient via the token service.
*/
function _giveToken(bytes32 tokenId, address to, uint256 amount) internal returns (uint256, address tokenAddress) {
(bool success, bytes memory data) = tokenHandler.delegatecall(
abi.encodeWithSelector(ITokenHandler.giveToken.selector, tokenId, to, amount)
);
if (!success) revert GiveTokenFailed(data);
(amount, tokenAddress) = abi.decode(data, (uint256, address));
return (amount, tokenAddress);
}
/**
* @notice Returns the amount of token that this call is worth.
* @dev If `tokenAddress` is `0`, then value is in terms of the native token, otherwise it's in terms of the token address.
* @param payload The payload sent with the call.
* @return address The token address.
* @return uint256 The value the call is worth.
*/
function _contractCallValue(bytes calldata payload) internal view returns (address, uint256) {
(uint256 messageType, bytes32 tokenId, , , uint256 amount) = abi.decode(payload, (uint256, bytes32, bytes, bytes, uint256));
if (messageType != MESSAGE_TYPE_INTERCHAIN_TRANSFER) {
revert InvalidExpressMessageType(messageType);
}
return (registeredTokenAddress(tokenId), amount);
}
function _getExpressExecutorAndEmitEvent(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash
) internal returns (address expressExecutor) {
expressExecutor = _popExpressExecutor(commandId, sourceChain, sourceAddress, payloadHash);
if (expressExecutor != address(0)) {
emit ExpressExecutionFulfilled(commandId, sourceChain, sourceAddress, payloadHash, expressExecutor);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
abstract contract ExpressExecutorTracker {
error ExpressExecutorAlreadySet();
bytes32 internal constant PREFIX_EXPRESS_EXECUTE = keccak256('express-execute');
bytes32 internal constant PREFIX_EXPRESS_EXECUTE_WITH_TOKEN = keccak256('express-execute-with-token');
function _expressExecuteSlot(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash
) internal pure returns (bytes32 slot) {
slot = keccak256(abi.encode(PREFIX_EXPRESS_EXECUTE, commandId, sourceChain, sourceAddress, payloadHash));
}
function _expressExecuteWithTokenSlot(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash,
string calldata symbol,
uint256 amount
) internal pure returns (bytes32 slot) {
slot = keccak256(
abi.encode(
PREFIX_EXPRESS_EXECUTE_WITH_TOKEN,
commandId,
sourceChain,
sourceAddress,
payloadHash,
symbol,
amount
)
);
}
function _getExpressExecutor(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash
) internal view returns (address expressExecutor) {
bytes32 slot = _expressExecuteSlot(commandId, sourceChain, sourceAddress, payloadHash);
assembly {
expressExecutor := sload(slot)
}
}
function _getExpressExecutorWithToken(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash,
string calldata symbol,
uint256 amount
) internal view returns (address expressExecutor) {
bytes32 slot = _expressExecuteWithTokenSlot(commandId, sourceChain, sourceAddress, payloadHash, symbol, amount);
assembly {
expressExecutor := sload(slot)
}
}
function _setExpressExecutor(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash,
address expressExecutor
) internal {
bytes32 slot = _expressExecuteSlot(commandId, sourceChain, sourceAddress, payloadHash);
address currentExecutor;
assembly {
currentExecutor := sload(slot)
}
if (currentExecutor != address(0)) revert ExpressExecutorAlreadySet();
assembly {
sstore(slot, expressExecutor)
}
}
function _setExpressExecutorWithToken(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash,
string calldata symbol,
uint256 amount,
address expressExecutor
) internal {
bytes32 slot = _expressExecuteWithTokenSlot(commandId, sourceChain, sourceAddress, payloadHash, symbol, amount);
address currentExecutor;
assembly {
currentExecutor := sload(slot)
}
if (currentExecutor != address(0)) revert ExpressExecutorAlreadySet();
assembly {
sstore(slot, expressExecutor)
}
}
function _popExpressExecutor(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash
) internal returns (address expressExecutor) {
bytes32 slot = _expressExecuteSlot(commandId, sourceChain, sourceAddress, payloadHash);
assembly {
expressExecutor := sload(slot)
if expressExecutor {
sstore(slot, 0)
}
}
}
function _popExpressExecutorWithToken(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash,
string calldata symbol,
uint256 amount
) internal returns (address expressExecutor) {
bytes32 slot = _expressExecuteWithTokenSlot(commandId, sourceChain, sourceAddress, payloadHash, symbol, amount);
assembly {
expressExecutor := sload(slot)
if expressExecutor {
sstore(slot, 0)
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IAxelarGateway } from './IAxelarGateway.sol';
/**
* @title IAxelarExecutable
* @dev Interface for a contract that is executable by Axelar Gateway's cross-chain message passing.
* It defines a standard interface to execute commands sent from another chain.
*/
interface IAxelarExecutable {
/**
* @dev Thrown when a function is called with an invalid address.
*/
error InvalidAddress();
/**
* @dev Thrown when the call is not approved by the Axelar Gateway.
*/
error NotApprovedByGateway();
/**
* @notice Returns the address of the AxelarGateway contract.
* @return The Axelar Gateway contract associated with this executable contract.
*/
function gateway() external view returns (IAxelarGateway);
/**
* @notice Executes the specified command sent from another chain.
* @dev This function is called by the Axelar Gateway to carry out cross-chain commands.
* Reverts if the call is not approved by the gateway or other checks fail.
* @param commandId The identifier of the command to execute.
* @param sourceChain The name of the source chain from where the command originated.
* @param sourceAddress The address on the source chain that sent the command.
* @param payload The payload of the command to be executed. This typically includes the function selector and encoded arguments.
*/
function execute(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IAxelarExecutable } from './IAxelarExecutable.sol';
/**
* @title IAxelarExpressExecutable
* @notice Interface for the Axelar Express Executable contract.
*/
interface IAxelarExpressExecutable is IAxelarExecutable {
// Custom errors
error AlreadyExecuted();
error InsufficientValue();
/**
* @notice Emitted when an express execution is successfully performed.
* @param commandId The unique identifier for the command.
* @param sourceChain The source chain.
* @param sourceAddress The source address.
* @param payloadHash The hash of the payload.
* @param expressExecutor The address of the express executor.
*/
event ExpressExecuted(
bytes32 indexed commandId,
string sourceChain,
string sourceAddress,
bytes32 payloadHash,
address indexed expressExecutor
);
/**
* @notice Emitted when an express execution is fulfilled.
* @param commandId The commandId for the contractCall.
* @param sourceChain The source chain.
* @param sourceAddress The source address.
* @param payloadHash The hash of the payload.
* @param expressExecutor The address of the express executor.
*/
event ExpressExecutionFulfilled(
bytes32 indexed commandId,
string sourceChain,
string sourceAddress,
bytes32 payloadHash,
address indexed expressExecutor
);
/**
* @notice Returns the express executor for a given command.
* @param commandId The commandId for the contractCall.
* @param sourceChain The source chain.
* @param sourceAddress The source address.
* @param payloadHash The hash of the payload.
* @return expressExecutor The address of the express executor.
*/
function getExpressExecutor(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash
) external view returns (address expressExecutor);
/**
* @notice Express executes a contract call.
* @param commandId The commandId for the contractCall.
* @param sourceChain The source chain.
* @param sourceAddress The source address.
* @param payload The payload data.
*/
function expressExecute(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload
) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { GasInfo } from '../types/GasEstimationTypes.sol';
import { IInterchainGasEstimation } from './IInterchainGasEstimation.sol';
import { IUpgradable } from './IUpgradable.sol';
/**
* @title IAxelarGasService Interface
* @notice This is an interface for the AxelarGasService contract which manages gas payments
* and refunds for cross-chain communication on the Axelar network.
* @dev This interface inherits IUpgradable
*/
interface IAxelarGasService is IInterchainGasEstimation, IUpgradable {
error InvalidAddress();
error NotCollector();
error InvalidAmounts();
error InvalidGasUpdates();
error InvalidParams();
error InsufficientGasPayment(uint256 required, uint256 provided);
event GasPaidForContractCall(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
);
event GasPaidForContractCallWithToken(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
string symbol,
uint256 amount,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
);
event NativeGasPaidForContractCall(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
uint256 gasFeeAmount,
address refundAddress
);
event NativeGasPaidForContractCallWithToken(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
string symbol,
uint256 amount,
uint256 gasFeeAmount,
address refundAddress
);
event GasPaidForExpressCall(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
);
event GasPaidForExpressCallWithToken(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
string symbol,
uint256 amount,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
);
event NativeGasPaidForExpressCall(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
uint256 gasFeeAmount,
address refundAddress
);
event NativeGasPaidForExpressCallWithToken(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
string symbol,
uint256 amount,
uint256 gasFeeAmount,
address refundAddress
);
event GasAdded(
bytes32 indexed txHash,
uint256 indexed logIndex,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
);
event NativeGasAdded(bytes32 indexed txHash, uint256 indexed logIndex, uint256 gasFeeAmount, address refundAddress);
event ExpressGasAdded(
bytes32 indexed txHash,
uint256 indexed logIndex,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
);
event NativeExpressGasAdded(
bytes32 indexed txHash,
uint256 indexed logIndex,
uint256 gasFeeAmount,
address refundAddress
);
event Refunded(
bytes32 indexed txHash,
uint256 indexed logIndex,
address payable receiver,
address token,
uint256 amount
);
/**
* @notice Pay for gas for any type of contract execution on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @dev If estimateOnChain is true, the function will estimate the gas cost and revert if the payment is insufficient.
* @param sender The address making the payment
* @param destinationChain The target chain where the contract call will be made
* @param destinationAddress The target address on the destination chain
* @param payload Data payload for the contract call
* @param executionGasLimit The gas limit for the contract call
* @param estimateOnChain Flag to enable on-chain gas estimation
* @param refundAddress The address where refunds, if any, should be sent
* @param params Additional parameters for gas payment. This can be left empty for normal contract call payments.
*/
function payGas(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
uint256 executionGasLimit,
bool estimateOnChain,
address refundAddress,
bytes calldata params
) external payable;
/**
* @notice Pay for gas using ERC20 tokens for a contract call on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @param sender The address making the payment
* @param destinationChain The target chain where the contract call will be made
* @param destinationAddress The target address on the destination chain
* @param payload Data payload for the contract call
* @param gasToken The address of the ERC20 token used to pay for gas
* @param gasFeeAmount The amount of tokens to pay for gas
* @param refundAddress The address where refunds, if any, should be sent
*/
function payGasForContractCall(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
/**
* @notice Pay for gas using ERC20 tokens for a contract call with tokens on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @param sender The address making the payment
* @param destinationChain The target chain where the contract call with tokens will be made
* @param destinationAddress The target address on the destination chain
* @param payload Data payload for the contract call with tokens
* @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
* @param gasToken The address of the ERC20 token used to pay for gas
* @param gasFeeAmount The amount of tokens to pay for gas
* @param refundAddress The address where refunds, if any, should be sent
*/
function payGasForContractCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
/**
* @notice Pay for gas using native currency for a contract call on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @param sender The address making the payment
* @param destinationChain The target chain where the contract call will be made
* @param destinationAddress The target address on the destination chain
* @param payload Data payload for the contract call
* @param refundAddress The address where refunds, if any, should be sent
*/
function payNativeGasForContractCall(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
address refundAddress
) external payable;
/**
* @notice Pay for gas using native currency for a contract call with tokens on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @param sender The address making the payment
* @param destinationChain The target chain where the contract call with tokens will be made
* @param destinationAddress The target address on the destination chain
* @param payload Data payload for the contract call with tokens
* @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
* @param refundAddress The address where refunds, if any, should be sent
*/
function payNativeGasForContractCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
address refundAddress
) external payable;
/**
* @notice Pay for gas using ERC20 tokens for an express contract call on a destination chain.
* @dev This function is called on the source chain before calling the gateway to express execute a remote contract.
* @param sender The address making the payment
* @param destinationChain The target chain where the contract call will be made
* @param destinationAddress The target address on the destination chain
* @param payload Data payload for the contract call
* @param gasToken The address of the ERC20 token used to pay for gas
* @param gasFeeAmount The amount of tokens to pay for gas
* @param refundAddress The address where refunds, if any, should be sent
*/
function payGasForExpressCall(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
/**
* @notice Pay for gas using ERC20 tokens for an express contract call with tokens on a destination chain.
* @dev This function is called on the source chain before calling the gateway to express execute a remote contract.
* @param sender The address making the payment
* @param destinationChain The target chain where the contract call with tokens will be made
* @param destinationAddress The target address on the destination chain
* @param payload Data payload for the contract call with tokens
* @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
* @param gasToken The address of the ERC20 token used to pay for gas
* @param gasFeeAmount The amount of tokens to pay for gas
* @param refundAddress The address where refunds, if any, should be sent
*/
function payGasForExpressCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
/**
* @notice Pay for gas using native currency for an express contract call on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @param sender The address making the payment
* @param destinationChain The target chain where the contract call will be made
* @param destinationAddress The target address on the destination chain
* @param payload Data payload for the contract call
* @param refundAddress The address where refunds, if any, should be sent
*/
function payNativeGasForExpressCall(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
address refundAddress
) external payable;
/**
* @notice Pay for gas using native currency for an express contract call with tokens on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @param sender The address making the payment
* @param destinationChain The target chain where the contract call with tokens will be made
* @param destinationAddress The target address on the destination chain
* @param payload Data payload for the contract call with tokens
* @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
* @param refundAddress The address where refunds, if any, should be sent
*/
function payNativeGasForExpressCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
address refundAddress
) external payable;
/**
* @notice Add additional gas payment using ERC20 tokens after initiating a cross-chain call.
* @dev This function can be called on the source chain after calling the gateway to execute a remote contract.
* @param txHash The transaction hash of the cross-chain call
* @param logIndex The log index for the cross-chain call
* @param gasToken The ERC20 token address used to add gas
* @param gasFeeAmount The amount of tokens to add as gas
* @param refundAddress The address where refunds, if any, should be sent
*/
function addGas(
bytes32 txHash,
uint256 logIndex,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
/**
* @notice Add additional gas payment using native currency after initiating a cross-chain call.
* @dev This function can be called on the source chain after calling the gateway to execute a remote contract.
* @param txHash The transaction hash of the cross-chain call
* @param logIndex The log index for the cross-chain call
* @param refundAddress The address where refunds, if any, should be sent
*/
function addNativeGas(
bytes32 txHash,
uint256 logIndex,
address refundAddress
) external payable;
/**
* @notice Add additional gas payment using ERC20 tokens after initiating an express cross-chain call.
* @dev This function can be called on the source chain after calling the gateway to express execute a remote contract.
* @param txHash The transaction hash of the cross-chain call
* @param logIndex The log index for the cross-chain call
* @param gasToken The ERC20 token address used to add gas
* @param gasFeeAmount The amount of tokens to add as gas
* @param refundAddress The address where refunds, if any, should be sent
*/
function addExpressGas(
bytes32 txHash,
uint256 logIndex,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
/**
* @notice Add additional gas payment using native currency after initiating an express cross-chain call.
* @dev This function can be called on the source chain after calling the gateway to express execute a remote contract.
* @param txHash The transaction hash of the cross-chain call
* @param logIndex The log index for the cross-chain call
* @param refundAddress The address where refunds, if any, should be sent
*/
function addNativeExpressGas(
bytes32 txHash,
uint256 logIndex,
address refundAddress
) external payable;
/**
* @notice Updates the gas price for a specific chain.
* @dev This function is called by the gas oracle to update the gas prices for a specific chains.
* @param chains Array of chain names
* @param gasUpdates Array of gas updates
*/
function updateGasInfo(string[] calldata chains, GasInfo[] calldata gasUpdates) external;
/**
* @notice Allows the gasCollector to collect accumulated fees from the contract.
* @dev Use address(0) as the token address for native currency.
* @param receiver The address to receive the collected fees
* @param tokens Array of token addresses to be collected
* @param amounts Array of amounts to be collected for each respective token address
*/
function collectFees(
address payable receiver,
address[] calldata tokens,
uint256[] calldata amounts
) external;
/**
* @notice Refunds gas payment to the receiver in relation to a specific cross-chain transaction.
* @dev Only callable by the gasCollector.
* @dev Use address(0) as the token address to refund native currency.
* @param txHash The transaction hash of the cross-chain call
* @param logIndex The log index for the cross-chain call
* @param receiver The address to receive the refund
* @param token The token address to be refunded
* @param amount The amount to refund
*/
function refund(
bytes32 txHash,
uint256 logIndex,
address payable receiver,
address token,
uint256 amount
) external;
/**
* @notice Returns the address of the designated gas collector.
* @return address of the gas collector
*/
function gasCollector() external returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IAxelarGateway
* @dev Interface for the Axelar Gateway that supports general message passing and contract call execution.
*/
interface IAxelarGateway {
/**
* @notice Emitted when a contract call is made through the gateway.
* @dev Logs the attempt to call a contract on another chain.
* @param sender The address of the sender who initiated the contract call.
* @param destinationChain The name of the destination chain.
* @param destinationContractAddress The address of the contract on the destination chain.
* @param payloadHash The keccak256 hash of the sent payload data.
* @param payload The payload data used for the contract call.
*/
event ContractCall(
address indexed sender,
string destinationChain,
string destinationContractAddress,
bytes32 indexed payloadHash,
bytes payload
);
/**
* @notice Sends a contract call to another chain.
* @dev Initiates a cross-chain contract call through the gateway to the specified destination chain and contract.
* @param destinationChain The name of the destination chain.
* @param contractAddress The address of the contract on the destination chain.
* @param payload The payload data to be used in the contract call.
*/
function callContract(
string calldata destinationChain,
string calldata contractAddress,
bytes calldata payload
) external;
/**
* @notice Checks if a contract call is approved.
* @dev Determines whether a given contract call, identified by the commandId and payloadHash, is approved.
* @param commandId The identifier of the command to check.
* @param sourceChain The name of the source chain.
* @param sourceAddress The address of the sender on the source chain.
* @param contractAddress The address of the contract where the call will be executed.
* @param payloadHash The keccak256 hash of the payload data.
* @return True if the contract call is approved, false otherwise.
*/
function isContractCallApproved(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
address contractAddress,
bytes32 payloadHash
) external view returns (bool);
/**
* @notice Validates and approves a contract call.
* @dev Validates the given contract call information and marks it as approved if valid.
* @param commandId The identifier of the command to validate.
* @param sourceChain The name of the source chain.
* @param sourceAddress The address of the sender on the source chain.
* @param payloadHash The keccak256 hash of the payload data.
* @return True if the contract call is validated and approved, false otherwise.
*/
function validateContractCall(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash
) external returns (bool);
/**
* @notice Checks if a command has been executed.
* @dev Determines whether a command, identified by the commandId, has been executed.
* @param commandId The identifier of the command to check.
* @return True if the command has been executed, false otherwise.
*/
function isCommandExecuted(bytes32 commandId) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IAxelarExpressExecutable } from './IAxelarExpressExecutable.sol';
/**
* @title IAxelarValuedExpressExecutable
* @dev Interface for the Axelar Valued Express Executable contract.
*/
interface IAxelarValuedExpressExecutable is IAxelarExpressExecutable {
/**
* @dev Returns the value (token address and amount) associated with a contract call
* @param sourceChain The source chain.
* @param sourceAddress The source address.
* @param payload The payload data.
* @return tokenAddress The address of the token used.
* @return value The value associated with the contract call.
*/
function contractCallValue(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload
) external view returns (address tokenAddress, uint256 value);
}// 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;
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 IInterchainAddressTracker
* @dev Manages trusted addresses by chain, keeps track of addresses supported by the Axelar gateway contract
*/
interface IInterchainAddressTracker {
error ZeroAddress();
error LengthMismatch();
error ZeroStringLength();
error UntrustedChain();
event TrustedAddressSet(string chain, string address_);
event TrustedAddressRemoved(string chain);
/**
* @dev Gets the name of the chain this is deployed at
*/
function chainName() external view returns (string memory);
/**
* @dev Gets the trusted address at a remote chain
* @param chain Chain name of the remote chain
* @return trustedAddress_ The trusted address for the chain. Returns '' if the chain is untrusted
*/
function trustedAddress(string memory chain) external view returns (string memory trustedAddress_);
/**
* @dev Gets the trusted address hash for a chain
* @param chain Chain name
* @return trustedAddressHash_ the hash of the trusted address for that chain
*/
function trustedAddressHash(string memory chain) external view returns (bytes32 trustedAddressHash_);
/**
* @dev Checks whether the interchain sender is a trusted address
* @param chain Chain name of the sender
* @param address_ Address of the sender
* @return bool true if the sender chain/address are trusted, false otherwise
*/
function isTrustedAddress(string calldata chain, string calldata address_) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { GasEstimationType, GasInfo } from '../types/GasEstimationTypes.sol';
/**
* @title IInterchainGasEstimation Interface
* @notice This is an interface for the InterchainGasEstimation contract
* which allows for estimating gas fees for cross-chain communication on the Axelar network.
*/
interface IInterchainGasEstimation {
error UnsupportedEstimationType(GasEstimationType gasEstimationType);
/**
* @notice Event emitted when the gas price for a specific chain is updated.
* @param chain The name of the chain
* @param info The gas info for the chain
*/
event GasInfoUpdated(string chain, GasInfo info);
/**
* @notice Returns the gas price for a specific chain.
* @param chain The name of the chain
* @return gasInfo The gas info for the chain
*/
function getGasInfo(string calldata chain) external view returns (GasInfo memory);
/**
* @notice Estimates the gas fee for a cross-chain contract call.
* @param destinationChain Axelar registered name of the destination chain
* @param destinationAddress Destination contract address being called
* @param executionGasLimit The gas limit to be used for the destination contract execution,
* e.g. pass in 200k if your app consumes needs upto 200k for this contract call
* @param params Additional parameters for the gas estimation
* @return gasEstimate The cross-chain gas estimate, in terms of source chain's native gas token that should be forwarded to the gas service.
*/
function estimateGasFee(
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
uint256 executionGasLimit,
bytes calldata params
) external view returns (uint256 gasEstimate);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IMulticall
* @notice This contract is a multi-functional smart contract which allows for multiple
* contract calls in a single transaction.
*/
interface IMulticall {
error MulticallFailed();
/**
* @notice Performs multiple delegate calls and returns the results of all calls as an array
* @dev This function requires that the contract has sufficient balance for the delegate calls.
* If any of the calls fail, the function will revert with the failure message.
* @param data An array of encoded function calls
* @return results An bytes array with the return data of each function call
*/
function multicall(bytes[] calldata data) external payable returns (bytes[] memory results);
}// 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;
/**
* @title Pausable
* @notice This contract provides a mechanism to halt the execution of specific functions
* if a pause condition is activated.
*/
interface IPausable {
event Paused(address indexed account);
event Unpaused(address indexed account);
error Pause();
error NotPaused();
/**
* @notice Check if the contract is paused
* @return paused A boolean representing the pause status. True if paused, false otherwise.
*/
function paused() external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IRolesBase Interface
* @notice IRolesBase is an interface that abstracts the implementation of a
* contract with role control internal functions.
*/
interface IRolesBase {
error MissingRole(address account, uint8 role);
error MissingAllRoles(address account, uint256 accountRoles);
error MissingAnyOfRoles(address account, uint256 accountRoles);
error InvalidProposedRoles(address fromAccount, address toAccount, uint256 accountRoles);
event RolesProposed(address indexed fromAccount, address indexed toAccount, uint256 accountRoles);
event RolesAdded(address indexed account, uint256 accountRoles);
event RolesRemoved(address indexed account, uint256 accountRoles);
/**
* @notice Checks if an account has a role.
* @param account The address to check
* @param role The role to check
* @return True if the account has the role, false otherwise
*/
function hasRole(address account, uint8 role) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IOwnable } from './IOwnable.sol';
import { IImplementation } from './IImplementation.sol';
// General interface for upgradable contracts
interface IUpgradable is IOwnable, IImplementation {
error InvalidCodeHash();
error InvalidImplementation();
error SetupFailed();
event Upgraded(address indexed newImplementation);
function implementation() external view returns (address);
function upgrade(
address newImplementation,
bytes32 newImplementationCodeHash,
bytes calldata params
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title AddressBytesUtils
* @dev This library provides utility functions to convert between `address` and `bytes`.
*/
library AddressBytes {
error InvalidBytesLength(bytes bytesAddress);
/**
* @dev Converts a bytes address to an address type.
* @param bytesAddress The bytes representation of an address
* @return addr The converted address
*/
function toAddress(bytes memory bytesAddress) internal pure returns (address addr) {
if (bytesAddress.length != 20) revert InvalidBytesLength(bytesAddress);
assembly {
addr := mload(add(bytesAddress, 20))
}
}
/**
* @dev Converts an address to bytes.
* @param addr The address to be converted
* @return bytesAddress The bytes representation of the address
*/
function toBytes(address addr) internal pure returns (bytes memory bytesAddress) {
bytesAddress = new bytes(20);
// we can test if using a single 32 byte variable that is the address with the length together and using one mstore would be slightly cheaper.
assembly {
mstore(add(bytesAddress, 20), addr)
mstore(bytesAddress, 20)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library StringStorage {
struct Wrapper {
string value;
}
function set(bytes32 slot, string memory value) internal {
_getStorageStruct(slot).value = value;
}
function get(bytes32 slot) internal view returns (string memory value) {
value = _getStorageStruct(slot).value;
}
function clear(bytes32 slot) internal {
delete _getStorageStruct(slot).value;
}
function _getStorageStruct(bytes32 slot) internal pure returns (Wrapper storage wrapper) {
assembly {
wrapper.slot := slot
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title GasEstimationType
* @notice This enum represents the gas estimation types for different chains.
*/
enum GasEstimationType {
Default,
OptimismEcotone,
OptimismBedrock,
Arbitrum,
Scroll
}
/**
* @title GasInfo
* @notice This struct represents the gas pricing information for a specific chain.
* @dev Smaller uint types are used for efficient struct packing to save storage costs.
*/
struct GasInfo {
/// @dev Custom gas pricing rule, such as L1 data fee on L2s
uint64 gasEstimationType;
/// @dev Scalar value needed for specific gas estimation types, expected to be less than 1e10
uint64 l1FeeScalar;
/// @dev Axelar base fee for cross-chain message approval on destination, in terms of source native gas token
uint128 axelarBaseFee;
/// @dev Gas price of destination chain, in terms of the source chain token, i.e dest_gas_price * dest_token_market_price / src_token_market_price
uint128 relativeGasPrice;
/// @dev Needed for specific gas estimation types. Blob base fee of destination chain, in terms of the source chain token, i.e dest_blob_base_fee * dest_token_market_price / src_token_market_price
uint128 relativeBlobBaseFee;
/// @dev Axelar express fee for express execution, in terms of source chain token
uint128 expressFee;
}// 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.0;
import { IImplementation } from '../interfaces/IImplementation.sol';
import { IUpgradable } from '../interfaces/IUpgradable.sol';
import { Ownable } from '../utils/Ownable.sol';
import { Implementation } from './Implementation.sol';
/**
* @title Upgradable Contract
* @notice This contract provides an interface for upgradable smart contracts and includes the functionality to perform upgrades.
*/
abstract contract Upgradable is Ownable, Implementation, IUpgradable {
// bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @notice Constructor sets the implementation address to the address of the contract itself
* @dev This is used in the onlyProxy modifier to prevent certain functions from being called directly
* on the implementation contract itself.
* @dev The owner is initially set as address(1) because the actual owner is set within the proxy. It is not
* set as the zero address because Ownable is designed to throw an error for ownership transfers to the zero address.
*/
constructor() Ownable(address(1)) {}
/**
* @notice Returns the address of the current implementation
* @return implementation_ Address of the current implementation
*/
function implementation() public view returns (address implementation_) {
assembly {
implementation_ := sload(_IMPLEMENTATION_SLOT)
}
}
/**
* @notice Upgrades the contract to a new implementation
* @param newImplementation The address of the new implementation contract
* @param newImplementationCodeHash The codehash of the new implementation contract
* @param params Optional setup parameters for the new implementation contract
* @dev This function is only callable by the owner.
*/
function upgrade(
address newImplementation,
bytes32 newImplementationCodeHash,
bytes calldata params
) external override onlyOwner {
if (IUpgradable(newImplementation).contractId() != IUpgradable(implementation()).contractId())
revert InvalidImplementation();
if (newImplementationCodeHash != newImplementation.codehash) revert InvalidCodeHash();
assembly {
sstore(_IMPLEMENTATION_SLOT, newImplementation)
}
emit Upgraded(newImplementation);
if (params.length > 0) {
// slither-disable-next-line controlled-delegatecall
(bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(this.setup.selector, params));
if (!success) revert SetupFailed();
}
}
/**
* @notice Sets up the contract with initial data
* @param data Initialization data for the contract
* @dev This function is only callable by the proxy contract.
*/
function setup(bytes calldata data) external override(IImplementation, Implementation) onlyProxy {
_setup(data);
}
/**
* @notice Internal function to set up the contract with initial data
* @param data Initialization data for the contract
* @dev This function should be implemented in derived contracts.
*/
function _setup(bytes calldata data) internal virtual;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IInterchainAddressTracker } from '../interfaces/IInterchainAddressTracker.sol';
import { StringStorage } from '../libs/StringStorage.sol';
/**
* @title InterchainAddressTracker
* @dev Manages and validates trusted interchain addresses of an application.
*/
contract InterchainAddressTracker is IInterchainAddressTracker {
bytes32 internal constant PREFIX_ADDRESS_MAPPING = keccak256('interchain-address-tracker-address-mapping');
bytes32 internal constant PREFIX_ADDRESS_HASH_MAPPING =
keccak256('interchain-address-tracker-address-hash-mapping');
// bytes32(uint256(keccak256('interchain-address-tracker-chain-name')) - 1)
bytes32 internal constant _CHAIN_NAME_SLOT = 0x0e2c162a1f4b5cff9fdbd6b34678a9bcb9898a0b9fbca695b112d61688d8b2ac;
function _setChainName(string memory chainName_) internal {
StringStorage.set(_CHAIN_NAME_SLOT, chainName_);
}
/**
* @dev Gets the name of the chain this is deployed at
*/
function chainName() public view returns (string memory chainName_) {
chainName_ = StringStorage.get(_CHAIN_NAME_SLOT);
}
/**
* @dev Gets the trusted address at a remote chain
* @param chain Chain name of the remote chain
* @return trustedAddress_ The trusted address for the chain. Returns '' if the chain is untrusted
*/
function trustedAddress(string memory chain) public view returns (string memory trustedAddress_) {
trustedAddress_ = StringStorage.get(_getTrustedAddressSlot(chain));
}
/**
* @dev Gets the trusted address hash for a chain
* @param chain Chain name
* @return trustedAddressHash_ the hash of the trusted address for that chain
*/
function trustedAddressHash(string memory chain) public view returns (bytes32 trustedAddressHash_) {
bytes32 slot = _getTrustedAddressHashSlot(chain);
assembly {
trustedAddressHash_ := sload(slot)
}
}
/**
* @dev Checks whether the interchain sender is a trusted address
* @param chain Chain name of the sender
* @param address_ Address of the sender
* @return bool true if the sender chain/address are trusted, false otherwise
*/
function isTrustedAddress(string calldata chain, string calldata address_) public view returns (bool) {
bytes32 addressHash = keccak256(bytes(address_));
return addressHash == trustedAddressHash(chain);
}
/**
* @dev Gets the key for the trusted address at a remote chain
* @param chain Chain name of the remote chain
* @return slot the slot to store the trusted address in
*/
function _getTrustedAddressSlot(string memory chain) internal pure returns (bytes32 slot) {
slot = keccak256(abi.encode(PREFIX_ADDRESS_MAPPING, chain));
}
/**
* @dev Gets the key for the trusted address at a remote chain
* @param chain Chain name of the remote chain
* @return slot the slot to store the trusted address hash in
*/
function _getTrustedAddressHashSlot(string memory chain) internal pure returns (bytes32 slot) {
slot = keccak256(abi.encode(PREFIX_ADDRESS_HASH_MAPPING, chain));
}
/**
* @dev Sets the trusted address and its hash for a remote chain
* @param chain Chain name of the remote chain
* @param address_ the string representation of the trusted address
*/
function _setTrustedAddress(string memory chain, string memory address_) internal {
if (bytes(chain).length == 0) revert ZeroStringLength();
if (bytes(address_).length == 0) revert ZeroStringLength();
StringStorage.set(_getTrustedAddressSlot(chain), address_);
bytes32 slot = _getTrustedAddressHashSlot(chain);
bytes32 addressHash = keccak256(bytes(address_));
assembly {
sstore(slot, addressHash)
}
emit TrustedAddressSet(chain, address_);
}
/**
* @dev Remove the trusted address of the chain.
* @param chain Chain name that should be made untrusted
*/
function _removeTrustedAddress(string memory chain) internal {
if (bytes(chain).length == 0) revert ZeroStringLength();
StringStorage.clear(_getTrustedAddressSlot(chain));
bytes32 slot = _getTrustedAddressHashSlot(chain);
assembly {
sstore(slot, 0)
}
emit TrustedAddressRemoved(chain);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IMulticall } from '../interfaces/IMulticall.sol';
/**
* @title Multicall
* @notice This contract is a multi-functional smart contract which allows for multiple
* contract calls in a single transaction.
*/
contract Multicall is IMulticall {
/**
* @notice Performs multiple delegate calls and returns the results of all calls as an array
* @dev This function requires that the contract has sufficient balance for the delegate calls.
* If any of the calls fail, the function will revert with the failure message.
* @param data An array of encoded function calls
* @return results An bytes array with the return data of each function call
*/
function multicall(bytes[] calldata data) public payable returns (bytes[] memory results) {
results = new bytes[](data.length);
bool success;
bytes memory result;
for (uint256 i = 0; i < data.length; ++i) {
// slither-disable-next-line calls-loop,delegatecall-loop
(success, result) = address(this).delegatecall(data[i]);
if (!success) {
if (result.length == 0) revert MulticallFailed();
assembly {
revert(add(32, result), mload(result))
}
}
results[i] = result;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IOwnable } from '../interfaces/IOwnable.sol';
/**
* @title Ownable
* @notice A contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The owner account is set through ownership transfer. This module makes
* it possible to transfer the ownership of the contract to a new account in one
* step, as well as to an interim pending owner. In the second flow the ownership does not
* change until the pending owner accepts the ownership transfer.
*/
abstract contract Ownable is IOwnable {
// keccak256('owner')
bytes32 internal constant _OWNER_SLOT = 0x02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0;
// keccak256('ownership-transfer')
bytes32 internal constant _OWNERSHIP_TRANSFER_SLOT =
0x9855384122b55936fbfb8ca5120e63c6537a1ac40caf6ae33502b3c5da8c87d1;
/**
* @notice Initializes the contract by transferring ownership to the owner parameter.
* @param _owner Address to set as the initial owner of the contract
*/
constructor(address _owner) {
_transferOwnership(_owner);
}
/**
* @notice Modifier that throws an error if called by any account other than the owner.
*/
modifier onlyOwner() {
if (owner() != msg.sender) revert NotOwner();
_;
}
/**
* @notice Returns the current owner of the contract.
* @return owner_ The current owner of the contract
*/
function owner() public view returns (address owner_) {
assembly {
owner_ := sload(_OWNER_SLOT)
}
}
/**
* @notice Returns the pending owner of the contract.
* @return owner_ The pending owner of the contract
*/
function pendingOwner() public view returns (address owner_) {
assembly {
owner_ := sload(_OWNERSHIP_TRANSFER_SLOT)
}
}
/**
* @notice Transfers ownership of the contract to a new account `newOwner`.
* @dev Can only be called by the current owner.
* @param newOwner The address to transfer ownership to
*/
function transferOwnership(address newOwner) external virtual onlyOwner {
_transferOwnership(newOwner);
}
/**
* @notice Propose to transfer ownership of the contract to a new account `newOwner`.
* @dev Can only be called by the current owner. The ownership does not change
* until the new owner accepts the ownership transfer.
* @param newOwner The address to transfer ownership to
*/
function proposeOwnership(address newOwner) external virtual onlyOwner {
if (newOwner == address(0)) revert InvalidOwnerAddress();
emit OwnershipTransferStarted(newOwner);
assembly {
sstore(_OWNERSHIP_TRANSFER_SLOT, newOwner)
}
}
/**
* @notice Accepts ownership of the contract.
* @dev Can only be called by the pending owner
*/
function acceptOwnership() external virtual {
address newOwner = pendingOwner();
if (newOwner != msg.sender) revert InvalidOwner();
_transferOwnership(newOwner);
}
/**
* @notice Internal function to transfer ownership of the contract to a new account `newOwner`.
* @dev Called in the constructor to set the initial owner.
* @param newOwner The address to transfer ownership to
*/
function _transferOwnership(address newOwner) internal virtual {
if (newOwner == address(0)) revert InvalidOwnerAddress();
emit OwnershipTransferred(newOwner);
assembly {
sstore(_OWNER_SLOT, newOwner)
sstore(_OWNERSHIP_TRANSFER_SLOT, 0)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IPausable } from '../interfaces/IPausable.sol';
/**
* @title Pausable
* @notice This contract provides a mechanism to halt the execution of specific functions
* if a pause condition is activated.
*/
contract Pausable is IPausable {
// uint256(keccak256('paused')) - 1
uint256 internal constant PAUSE_SLOT = 0xee35723ac350a69d2a92d3703f17439cbaadf2f093a21ba5bf5f1a53eb2a14d8;
/**
* @notice A modifier that throws a Paused custom error if the contract is paused
* @dev This modifier should be used with functions that can be paused
*/
modifier whenNotPaused() {
if (paused()) revert Pause();
_;
}
modifier whenPaused() {
if (!paused()) revert NotPaused();
_;
}
/**
* @notice Check if the contract is paused
* @return paused_ A boolean representing the pause status. True if paused, false otherwise.
*/
function paused() public view returns (bool paused_) {
assembly {
paused_ := sload(PAUSE_SLOT)
}
}
/**
* @notice Pauses the contract
* @dev This function should be callable by the owner/governance.
*/
function _pause() internal {
_setPaused(true);
emit Paused(msg.sender);
}
/**
* @notice Unpauses the contract
* @dev This function should be callable by the owner/governance.
*/
function _unpause() internal {
_setPaused(false);
emit Unpaused(msg.sender);
}
/**
* @notice Sets the pause status of the contract
* @dev This is an internal function, meaning it can only be called from within the contract itself
* or from derived contracts.
* @param paused_ The new pause status
*/
function _setPaused(bool paused_) internal {
assembly {
sstore(PAUSE_SLOT, paused_)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IRolesBase } from '../interfaces/IRolesBase.sol';
/**
* @title RolesBase
* @notice A contract module which provides a set if internal functions
* for implementing role control features.
*/
contract RolesBase is IRolesBase {
bytes32 internal constant ROLES_PREFIX = keccak256('roles');
bytes32 internal constant PROPOSE_ROLES_PREFIX = keccak256('propose-roles');
/**
* @notice Modifier that throws an error if called by any account missing the role.
*/
modifier onlyRole(uint8 role) {
if (!_hasRole(_getRoles(msg.sender), role)) revert MissingRole(msg.sender, role);
_;
}
/**
* @notice Modifier that throws an error if called by an account without all the roles.
*/
modifier withEveryRole(uint8[] memory roles) {
uint256 accountRoles = _toAccountRoles(roles);
if (!_hasAllTheRoles(_getRoles(msg.sender), accountRoles)) revert MissingAllRoles(msg.sender, accountRoles);
_;
}
/**
* @notice Modifier that throws an error if called by an account without any of the roles.
*/
modifier withAnyRole(uint8[] memory roles) {
uint256 accountRoles = _toAccountRoles(roles);
if (!_hasAnyOfRoles(_getRoles(msg.sender), accountRoles)) revert MissingAnyOfRoles(msg.sender, accountRoles);
_;
}
/**
* @notice Checks if an account has a role.
* @param account The address to check
* @param role The role to check
* @return True if the account has the role, false otherwise
*/
function hasRole(address account, uint8 role) public view returns (bool) {
return _hasRole(_getRoles(account), role);
}
/**
* @notice Internal function to convert an array of roles to a uint256.
* @param roles The roles to convert
* @return accountRoles The roles in uint256 format
*/
function _toAccountRoles(uint8[] memory roles) internal pure returns (uint256) {
uint256 length = roles.length;
uint256 accountRoles;
for (uint256 i = 0; i < length; ++i) {
accountRoles |= (1 << roles[i]);
}
return accountRoles;
}
/**
* @notice Internal function to get the key of the roles mapping.
* @param account The address to get the key for
* @return key The key of the roles mapping
*/
function _rolesKey(address account) internal view virtual returns (bytes32 key) {
return keccak256(abi.encodePacked(ROLES_PREFIX, account));
}
/**
* @notice Internal function to get the roles of an account.
* @param account The address to get the roles for
* @return accountRoles The roles of the account in uint256 format
*/
function _getRoles(address account) internal view returns (uint256 accountRoles) {
bytes32 key = _rolesKey(account);
assembly {
accountRoles := sload(key)
}
}
/**
* @notice Internal function to set the roles of an account.
* @param account The address to set the roles for
* @param accountRoles The roles to set
*/
function _setRoles(address account, uint256 accountRoles) private {
bytes32 key = _rolesKey(account);
assembly {
sstore(key, accountRoles)
}
}
/**
* @notice Internal function to get the key of the proposed roles mapping.
* @param fromAccount The address of the current role
* @param toAccount The address of the pending role
* @return key The key of the proposed roles mapping
*/
function _proposalKey(address fromAccount, address toAccount) internal view virtual returns (bytes32 key) {
return keccak256(abi.encodePacked(PROPOSE_ROLES_PREFIX, fromAccount, toAccount));
}
/**
* @notice Internal function to get the proposed roles of an account.
* @param fromAccount The address of the current role
* @param toAccount The address of the pending role
* @return proposedRoles_ The proposed roles of the account in uint256 format
*/
function _getProposedRoles(address fromAccount, address toAccount) internal view returns (uint256 proposedRoles_) {
bytes32 key = _proposalKey(fromAccount, toAccount);
assembly {
proposedRoles_ := sload(key)
}
}
/**
* @notice Internal function to set the proposed roles of an account.
* @param fromAccount The address of the current role
* @param toAccount The address of the pending role
* @param proposedRoles_ The proposed roles to set in uint256 format
*/
function _setProposedRoles(
address fromAccount,
address toAccount,
uint256 proposedRoles_
) private {
bytes32 key = _proposalKey(fromAccount, toAccount);
assembly {
sstore(key, proposedRoles_)
}
}
/**
* @notice Internal function to add a role to an account.
* @dev emits a RolesAdded event.
* @param account The address to add the role to
* @param role The role to add
*/
function _addRole(address account, uint8 role) internal {
_addAccountRoles(account, 1 << role);
}
/**
* @notice Internal function to add roles to an account.
* @dev emits a RolesAdded event.
* @dev Called in the constructor to set the initial roles.
* @param account The address to add roles to
* @param roles The roles to add
*/
function _addRoles(address account, uint8[] memory roles) internal {
_addAccountRoles(account, _toAccountRoles(roles));
}
/**
* @notice Internal function to add roles to an account.
* @dev emits a RolesAdded event.
* @dev Called in the constructor to set the initial roles.
* @param account The address to add roles to
* @param accountRoles The roles to add
*/
function _addAccountRoles(address account, uint256 accountRoles) internal {
uint256 newAccountRoles = _getRoles(account) | accountRoles;
_setRoles(account, newAccountRoles);
emit RolesAdded(account, accountRoles);
}
/**
* @notice Internal function to remove a role from an account.
* @dev emits a RolesRemoved event.
* @param account The address to remove the role from
* @param role The role to remove
*/
function _removeRole(address account, uint8 role) internal {
_removeAccountRoles(account, 1 << role);
}
/**
* @notice Internal function to remove roles from an account.
* @dev emits a RolesRemoved event.
* @param account The address to remove roles from
* @param roles The roles to remove
*/
function _removeRoles(address account, uint8[] memory roles) internal {
_removeAccountRoles(account, _toAccountRoles(roles));
}
/**
* @notice Internal function to remove roles from an account.
* @dev emits a RolesRemoved event.
* @param account The address to remove roles from
* @param accountRoles The roles to remove
*/
function _removeAccountRoles(address account, uint256 accountRoles) internal {
uint256 newAccountRoles = _getRoles(account) & ~accountRoles;
_setRoles(account, newAccountRoles);
emit RolesRemoved(account, accountRoles);
}
/**
* @notice Internal function to check if an account has a role.
* @param accountRoles The roles of the account in uint256 format
* @param role The role to check
* @return True if the account has the role, false otherwise
*/
function _hasRole(uint256 accountRoles, uint8 role) internal pure returns (bool) {
return accountRoles & (1 << role) != 0;
}
/**
* @notice Internal function to check if an account has all the roles.
* @param hasAccountRoles The roles of the account in uint256 format
* @param mustHaveAccountRoles The roles the account must have
* @return True if the account has all the roles, false otherwise
*/
function _hasAllTheRoles(uint256 hasAccountRoles, uint256 mustHaveAccountRoles) internal pure returns (bool) {
return (hasAccountRoles & mustHaveAccountRoles) == mustHaveAccountRoles;
}
/**
* @notice Internal function to check if an account has any of the roles.
* @param hasAccountRoles The roles of the account in uint256 format
* @param mustHaveAnyAccountRoles The roles to check in uint256 format
* @return True if the account has any of the roles, false otherwise
*/
function _hasAnyOfRoles(uint256 hasAccountRoles, uint256 mustHaveAnyAccountRoles) internal pure returns (bool) {
return (hasAccountRoles & mustHaveAnyAccountRoles) != 0;
}
/**
* @notice Internal function to propose to transfer roles of message sender to a new account.
* @dev Original account must have all the proposed roles.
* @dev Emits a RolesProposed event.
* @dev Roles are not transferred until the new role accepts the role transfer.
* @param fromAccount The address of the current roles
* @param toAccount The address to transfer roles to
* @param role The role to transfer
*/
function _proposeRole(
address fromAccount,
address toAccount,
uint8 role
) internal {
_proposeAccountRoles(fromAccount, toAccount, 1 << role);
}
/**
* @notice Internal function to propose to transfer roles of message sender to a new account.
* @dev Original account must have all the proposed roles.
* @dev Emits a RolesProposed event.
* @dev Roles are not transferred until the new role accepts the role transfer.
* @param fromAccount The address of the current roles
* @param toAccount The address to transfer roles to
* @param roles The roles to transfer
*/
function _proposeRoles(
address fromAccount,
address toAccount,
uint8[] memory roles
) internal {
_proposeAccountRoles(fromAccount, toAccount, _toAccountRoles(roles));
}
/**
* @notice Internal function to propose to transfer roles of message sender to a new account.
* @dev Original account must have all the proposed roles.
* @dev Emits a RolesProposed event.
* @dev Roles are not transferred until the new role accepts the role transfer.
* @param fromAccount The address of the current roles
* @param toAccount The address to transfer roles to
* @param accountRoles The account roles to transfer
*/
function _proposeAccountRoles(
address fromAccount,
address toAccount,
uint256 accountRoles
) internal {
if (!_hasAllTheRoles(_getRoles(fromAccount), accountRoles)) revert MissingAllRoles(fromAccount, accountRoles);
_setProposedRoles(fromAccount, toAccount, accountRoles);
emit RolesProposed(fromAccount, toAccount, accountRoles);
}
/**
* @notice Internal function to accept roles transferred from another account.
* @dev Pending account needs to pass all the proposed roles.
* @dev Emits RolesRemoved and RolesAdded events.
* @param fromAccount The address of the current role
* @param role The role to accept
*/
function _acceptRole(
address fromAccount,
address toAccount,
uint8 role
) internal virtual {
_acceptAccountRoles(fromAccount, toAccount, 1 << role);
}
/**
* @notice Internal function to accept roles transferred from another account.
* @dev Pending account needs to pass all the proposed roles.
* @dev Emits RolesRemoved and RolesAdded events.
* @param fromAccount The address of the current role
* @param roles The roles to accept
*/
function _acceptRoles(
address fromAccount,
address toAccount,
uint8[] memory roles
) internal virtual {
_acceptAccountRoles(fromAccount, toAccount, _toAccountRoles(roles));
}
/**
* @notice Internal function to accept roles transferred from another account.
* @dev Pending account needs to pass all the proposed roles.
* @dev Emits RolesRemoved and RolesAdded events.
* @param fromAccount The address of the current role
* @param accountRoles The account roles to accept
*/
function _acceptAccountRoles(
address fromAccount,
address toAccount,
uint256 accountRoles
) internal virtual {
if (_getProposedRoles(fromAccount, toAccount) != accountRoles) {
revert InvalidProposedRoles(fromAccount, toAccount, accountRoles);
}
_setProposedRoles(fromAccount, toAccount, 0);
_transferAccountRoles(fromAccount, toAccount, accountRoles);
}
/**
* @notice Internal function to transfer roles from one account to another.
* @dev Original account must have all the proposed roles.
* @param fromAccount The address of the current role
* @param toAccount The address to transfer role to
* @param role The role to transfer
*/
function _transferRole(
address fromAccount,
address toAccount,
uint8 role
) internal {
_transferAccountRoles(fromAccount, toAccount, 1 << role);
}
/**
* @notice Internal function to transfer roles from one account to another.
* @dev Original account must have all the proposed roles.
* @param fromAccount The address of the current role
* @param toAccount The address to transfer role to
* @param roles The roles to transfer
*/
function _transferRoles(
address fromAccount,
address toAccount,
uint8[] memory roles
) internal {
_transferAccountRoles(fromAccount, toAccount, _toAccountRoles(roles));
}
/**
* @notice Internal function to transfer roles from one account to another.
* @dev Original account must have all the proposed roles.
* @param fromAccount The address of the current role
* @param toAccount The address to transfer role to
* @param accountRoles The account roles to transfer
*/
function _transferAccountRoles(
address fromAccount,
address toAccount,
uint256 accountRoles
) internal {
if (!_hasAllTheRoles(_getRoles(fromAccount), accountRoles)) revert MissingAllRoles(fromAccount, accountRoles);
_removeAccountRoles(fromAccount, accountRoles);
_addAccountRoles(toAccount, accountRoles);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IInterchainAddressTracker } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IInterchainAddressTracker.sol';
/**
* @title IAddressTracker Interface
* @notice This interface allows setting and removing a trusted address for a specific chain.
* @dev Extends the IInterchainAddressTracker interface.
*/
interface IAddressTracker is IInterchainAddressTracker {
/**
* @notice Sets the trusted address for the specified chain.
* @param chain Chain name to be trusted.
* @param address_ Trusted address to be added for the chain.
*/
function setTrustedAddress(string memory chain, string memory address_) external;
/**
* @notice Remove the trusted address of the chain.
* @param chain Chain name to remove the trusted address for.
*/
function removeTrustedAddress(string calldata chain) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IBaseTokenManager
* @notice This contract is defines the base token manager interface implemented by all token managers.
*/
interface IBaseTokenManager {
/**
* @notice A function that returns the token id.
*/
function interchainTokenId() external view returns (bytes32);
/**
* @notice A function that should return the address of the token.
* Must be overridden in the inheriting contract.
* @return address address of the token.
*/
function tokenAddress() external view returns (address);
/**
* @notice A function that should return the token address from the init params.
*/
function getTokenAddressFromParams(bytes calldata params) external pure returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol';
/**
* @title IERC20Named Interface
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Named is IERC20 {
/**
* @notice Getter for the name of the token.
* @return string Name of the token.
*/
function name() external view returns (string memory);
/**
* @notice Getter for the symbol of the token.
* @return string The symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @notice Getter for the decimals of the token.
* @return uint8 The decimals of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title FlowLimit Interface
* @notice Interface for flow limit logic for interchain token transfers.
*/
interface IFlowLimit {
error FlowLimitExceeded(uint256 limit, uint256 flowAmount, address tokenManager);
error FlowAdditionOverflow(uint256 flowAmount, uint256 flowToAdd, address tokenManager);
error FlowLimitOverflow(uint256 flowLimit, uint256 flowToCompare, address tokenManager);
event FlowLimitSet(bytes32 indexed tokenId, address operator, uint256 flowLimit_);
/**
* @notice Returns the current flow limit.
* @return flowLimit_ The current flow limit value.
*/
function flowLimit() external view returns (uint256 flowLimit_);
/**
* @notice Returns the current flow out amount.
* @return flowOutAmount_ The current flow out amount.
*/
function flowOutAmount() external view returns (uint256 flowOutAmount_);
/**
* @notice Returns the current flow in amount.
* @return flowInAmount_ The current flow in amount.
*/
function flowInAmount() external view returns (uint256 flowInAmount_);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IGatewayCaller interface
* @dev Interface for the GatewayCaller contract
*/
interface IGatewayCaller {
/**
* @dev Enum representing different metadata versions
*/
enum MetadataVersion {
CONTRACT_CALL,
EXPRESS_CALL
}
/**
* @dev Error thrown when an invalid metadata version is provided
*/
error InvalidMetadataVersion(uint32 metadataVersion);
/**
* @notice Call the Axelar gateway to send a payload to a destination contract on a specific destination chain
* @param destinationChain The target chain where the contract will be called
* @param destinationAddress The address of the contract to be called on the destination chain
* @param payload The data payload for the transaction
* @param metadataVersion The version of metadata to be used
* @param gasValue The amount of gas to be paid for the cross-chain message. If this is 0, then gas payment is skipped. `msg.value` must be at least gasValue.
*/
function callContract(
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
MetadataVersion metadataVersion,
uint256 gasValue
) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IInterchainTokenDeployer
* @notice This interface is used to deploy new instances of the InterchainTokenProxy contract.
*/
interface IInterchainTokenDeployer {
error AddressZero();
error TokenDeploymentFailed();
/**
* @notice Returns the interchain token implementation address.
* @return address The interchain token implementation address.
*/
function implementationAddress() external view returns (address);
/**
* @notice Returns the interchain token deployment address.
* @param salt The deployment salt.
* @return tokenAddress The token address.
*/
function deployedAddress(bytes32 salt) external view returns (address tokenAddress);
/**
* @notice Deploys a new instance of the InterchainTokenProxy contract.
* @param salt The salt used by Create3Deployer.
* @param tokenId tokenId of the token.
* @param minter Address of the minter.
* @param name Name of the token.
* @param symbol Symbol of the token.
* @param decimals Decimals of the token.
* @return tokenAddress Address of the deployed token.
*/
function deployInterchainToken(
bytes32 salt,
bytes32 tokenId,
address minter,
string calldata name,
string calldata symbol,
uint8 decimals
) external returns (address tokenAddress);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IInterchainTokenExecutable
* @notice Contracts should implement this interface to accept calls from the InterchainTokenService.
*/
interface IInterchainTokenExecutable {
/**
* @notice This will be called after the tokens are sent to this contract.
* @dev Execution should revert unless the msg.sender is the InterchainTokenService
* @param commandId The unique message id for the call.
* @param sourceChain The name of the source chain.
* @param sourceAddress The address that sent the contract call.
* @param data The data to be processed.
* @param tokenId The tokenId of the token manager managing the token.
* @param token The address of the token.
* @param amount The amount of tokens that were sent.
* @return bytes32 Hash indicating success of the execution.
*/
function executeWithInterchainToken(
bytes32 commandId,
string calldata sourceChain,
bytes calldata sourceAddress,
bytes calldata data,
bytes32 tokenId,
address token,
uint256 amount
) external returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IInterchainTokenExecutable } from './IInterchainTokenExecutable.sol';
/**
* @title IInterchainTokenExpressExecutable
* @notice Contracts should implement this interface to accept express calls from the InterchainTokenService.
*/
interface IInterchainTokenExpressExecutable is IInterchainTokenExecutable {
/**
* @notice Executes express logic in the context of an interchain token transfer.
* @dev Only callable by the interchain token service.
* @param commandId The unique message id for the call.
* @param sourceChain The source chain of the token transfer.
* @param sourceAddress The source address of the token transfer.
* @param data The data associated with the token transfer.
* @param tokenId The token ID.
* @param token The token address.
* @param amount The amount of tokens to be transferred.
* @return bytes32 Hash indicating success of the express execution.
*/
function expressExecuteWithInterchainToken(
bytes32 commandId,
string calldata sourceChain,
bytes calldata sourceAddress,
bytes calldata data,
bytes32 tokenId,
address token,
uint256 amount
) external returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IAxelarValuedExpressExecutable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarValuedExpressExecutable.sol';
import { IMulticall } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IMulticall.sol';
import { IPausable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IPausable.sol';
import { IUpgradable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IUpgradable.sol';
import { ITransmitInterchainToken } from './ITransmitInterchainToken.sol';
import { ITokenManager } from './ITokenManager.sol';
import { ITokenManagerType } from './ITokenManagerType.sol';
import { ITokenManagerImplementation } from './ITokenManagerImplementation.sol';
import { IOperator } from './IOperator.sol';
import { IAddressTracker } from './IAddressTracker.sol';
/**
* @title IInterchainTokenService Interface
* @notice Interface for the Interchain Token Service
*/
interface IInterchainTokenService is
ITransmitInterchainToken,
ITokenManagerType,
ITokenManagerImplementation,
IAxelarValuedExpressExecutable,
IOperator,
IPausable,
IMulticall,
IAddressTracker,
IUpgradable
{
error InvalidChainName();
error NotRemoteService();
error TokenManagerDoesNotExist(bytes32 tokenId);
error ExecuteWithInterchainTokenFailed(address contractAddress);
error ExpressExecuteWithInterchainTokenFailed(address contractAddress);
error TokenManagerDeploymentFailed(bytes error);
error InterchainTokenDeploymentFailed(bytes error);
error InvalidMessageType(uint256 messageType);
error InvalidMetadataVersion(uint32 version);
error InvalidExpressMessageType(uint256 messageType);
error TakeTokenFailed(bytes data);
error GiveTokenFailed(bytes data);
error TokenHandlerFailed(bytes data);
error EmptyData();
error PostDeployFailed(bytes data);
error ZeroAmount();
error CannotDeploy(TokenManagerType);
error CannotDeployRemotelyToSelf();
error InvalidPayload();
error GatewayCallFailed(bytes data);
error EmptyTokenName();
error EmptyTokenSymbol();
error EmptyParams();
error EmptyDestinationAddress();
error EmptyTokenAddress();
error NotSupported();
error NotInterchainTokenFactory(address sender);
event InterchainTransfer(
bytes32 indexed tokenId,
address indexed sourceAddress,
string destinationChain,
bytes destinationAddress,
uint256 amount,
bytes32 indexed dataHash
);
event InterchainTransferReceived(
bytes32 indexed commandId,
bytes32 indexed tokenId,
string sourceChain,
bytes sourceAddress,
address indexed destinationAddress,
uint256 amount,
bytes32 dataHash
);
event TokenMetadataRegistered(address indexed tokenAddress, uint8 decimals);
event LinkTokenStarted(
bytes32 indexed tokenId,
string destinationChain,
bytes sourceTokenAddress,
bytes destinationTokenAddress,
TokenManagerType indexed tokenManagerType,
bytes params
);
event InterchainTokenDeploymentStarted(
bytes32 indexed tokenId,
string tokenName,
string tokenSymbol,
uint8 tokenDecimals,
bytes minter,
string destinationChain
);
event TokenManagerDeployed(bytes32 indexed tokenId, address tokenManager, TokenManagerType indexed tokenManagerType, bytes params);
event InterchainTokenDeployed(
bytes32 indexed tokenId,
address tokenAddress,
address indexed minter,
string name,
string symbol,
uint8 decimals
);
event InterchainTokenIdClaimed(bytes32 indexed tokenId, address indexed deployer, bytes32 indexed salt);
/**
* @notice Returns the address of the token manager deployer contract.
* @return tokenManagerDeployerAddress The address of the token manager deployer contract.
*/
function tokenManagerDeployer() external view returns (address tokenManagerDeployerAddress);
/**
* @notice Returns the address of the interchain token deployer contract.
* @return interchainTokenDeployerAddress The address of the interchain token deployer contract.
*/
function interchainTokenDeployer() external view returns (address interchainTokenDeployerAddress);
/**
* @notice Returns the address of TokenManager implementation.
* @return tokenManagerAddress_ The address of the token manager contract.
*/
function tokenManager() external view returns (address tokenManagerAddress_);
/**
* @notice Returns the address of TokenHandler implementation.
* @return tokenHandlerAddress The address of the token handler contract.
*/
function tokenHandler() external view returns (address tokenHandlerAddress);
/**
* @notice Returns the address of the interchain token factory.
* @return address The address of the interchain token factory.
*/
function interchainTokenFactory() external view returns (address);
/**
* @notice Returns the hash of the chain name.
* @return bytes32 The hash of the chain name.
*/
function chainNameHash() external view returns (bytes32);
/**
* @notice Returns the address of the token manager associated with the given tokenId.
* @param tokenId The tokenId of the token manager.
* @return tokenManagerAddress_ The address of the token manager.
*/
function tokenManagerAddress(bytes32 tokenId) external view returns (address tokenManagerAddress_);
/**
* @notice Returns the instance of ITokenManager from a specific tokenId.
* @param tokenId The tokenId of the deployed token manager.
* @return tokenManager_ The instance of ITokenManager associated with the specified tokenId.
*/
function deployedTokenManager(bytes32 tokenId) external view returns (ITokenManager tokenManager_);
/**
* @notice Returns the address of the token that an existing tokenManager points to.
* @param tokenId The tokenId of the registered token.
* @return tokenAddress The address of the token.
*/
function registeredTokenAddress(bytes32 tokenId) external view returns (address tokenAddress);
/**
* @notice Returns the address of the interchain token associated with the given tokenId.
* @param tokenId The tokenId of the interchain token.
* @return tokenAddress The address of the interchain token.
*/
function interchainTokenAddress(bytes32 tokenId) external view returns (address tokenAddress);
/**
* @notice Returns the custom tokenId associated with the given operator and salt.
* @param operator_ The operator address.
* @param salt The salt used for token id calculation.
* @return tokenId The custom tokenId associated with the operator and salt.
*/
function interchainTokenId(address operator_, bytes32 salt) external view returns (bytes32 tokenId);
/**
* @notice Registers metadata for a token on the ITS Hub. This metadata is used for scaling linked tokens.
* The token metadata must be registered before linkToken can be called for the corresponding token.
* @param tokenAddress The address of the token.
* @param gasValue The cross-chain gas value for sending the registration message to ITS Hub.
*/
function registerTokenMetadata(address tokenAddress, uint256 gasValue) external payable;
/**
* @notice Only to be used by the InterchainTokenFactory to register custom tokens to this chain. Then link token can be used to register those tokens to other chains.
* @param salt A unique salt to derive tokenId from.
* @param tokenManagerType The type of the token manager to use for the token registration.
* @param linkParams The operator for the token.
*/
function registerCustomToken(
bytes32 salt,
address tokenAddress,
TokenManagerType tokenManagerType,
bytes calldata linkParams
) external payable returns (bytes32 tokenId);
/**
* @notice If `destinationChain` is an empty string, this function will register the token address on the current chain.
* Otherwise, it will link the token address on the destination chain with the token corresponding to the tokenId on the current chain.
* A token manager is deployed on EVM chains that's responsible for managing the linked token.
* @dev This function replaces the prior `deployTokenManager` function.
* @param salt A unique identifier to allow for multiple tokens registered per deployer.
* @param destinationChain The chain to link the token to. Pass an empty string for this chain.
* @param destinationTokenAddress The token address to link, as bytes.
* @param tokenManagerType The type of the token manager to use to send and receive tokens.
* @param linkParams Additional parameteres to use to link the token. Fow not it is just the address of the operator.
* @param gasValue Pass a non-zero value only for remote linking, which should be the gas to use to pay for the contract call.
* @return tokenId The tokenId associated with the token manager.
*/
function linkToken(
bytes32 salt,
string calldata destinationChain,
bytes memory destinationTokenAddress,
TokenManagerType tokenManagerType,
bytes memory linkParams,
uint256 gasValue
) external payable returns (bytes32 tokenId);
/**
* @notice Deploys and registers an interchain token on a remote chain.
* @param salt The salt used for token deployment.
* @param destinationChain The name of the destination chain. Use '' for this chain.
* @param name The name of the interchain tokens.
* @param symbol The symbol of the interchain tokens.
* @param decimals The number of decimals for the interchain tokens.
* @param minter The minter data for mint/burn operations.
* @param gasValue The gas value for deployment.
* @return tokenId The tokenId corresponding to the deployed InterchainToken.
*/
function deployInterchainToken(
bytes32 salt,
string calldata destinationChain,
string memory name,
string memory symbol,
uint8 decimals,
bytes memory minter,
uint256 gasValue
) external payable returns (bytes32 tokenId);
/**
* @notice Initiates an interchain transfer of a specified token to a destination chain.
* @param tokenId The unique identifier of the token to be transferred.
* @param destinationChain The destination chain to send the tokens to.
* @param destinationAddress The address on the destination chain to send the tokens to.
* @param amount The amount of tokens to be transferred.
* @param metadata Optional metadata for the call for additional effects (such as calling a destination contract).
*/
function interchainTransfer(
bytes32 tokenId,
string calldata destinationChain,
bytes calldata destinationAddress,
uint256 amount,
bytes calldata metadata,
uint256 gasValue
) external payable;
/**
* @notice Sets the flow limits for multiple tokens.
* @param tokenIds An array of tokenIds.
* @param flowLimits An array of flow limits corresponding to the tokenIds.
*/
function setFlowLimits(bytes32[] calldata tokenIds, uint256[] calldata flowLimits) external;
/**
* @notice Allows the owner to pause/unpause the token service.
* @param paused whether to pause or unpause.
*/
function setPauseStatus(bool paused) external;
/**
* @notice Allows the owner to migrate legacy tokens that cannot be migrated automatically.
* @param tokenId the tokenId of the registered token.
*/
function migrateInterchainToken(bytes32 tokenId) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IRolesBase } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IRolesBase.sol';
/**
* @title IMinter Interface
* @notice An interface for a contract module which provides a basic access control mechanism, where
* there is an account (a minter) that can be granted exclusive access to specific functions.
*/
interface IMinter is IRolesBase {
/**
* @notice Change the minter of the contract.
* @dev Can only be called by the current minter.
* @param minter_ The address of the new minter.
*/
function transferMintership(address minter_) external;
/**
* @notice Proposed a change of the minter of the contract.
* @dev Can only be called by the current minter.
* @param minter_ The address of the new minter.
*/
function proposeMintership(address minter_) external;
/**
* @notice Accept a change of the minter of the contract.
* @dev Can only be called by the proposed minter.
* @param fromMinter The previous minter.
*/
function acceptMintership(address fromMinter) external;
/**
* @notice Query if an address is a minter
* @param addr the address to query for
* @return bool Boolean value representing whether or not the address is a minter.
*/
function isMinter(address addr) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IRolesBase } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IRolesBase.sol';
/**
* @title IOperator Interface
* @notice An interface for a contract module which provides a basic access control mechanism, where
* there is an account (a operator) that can be granted exclusive access to specific functions.
*/
interface IOperator is IRolesBase {
/**
* @notice Change the operator of the contract.
* @dev Can only be called by the current operator.
* @param operator_ The address of the new operator.
*/
function transferOperatorship(address operator_) external;
/**
* @notice Proposed a change of the operator of the contract.
* @dev Can only be called by the current operator.
* @param operator_ The address of the new operator.
*/
function proposeOperatorship(address operator_) external;
/**
* @notice Accept a proposed change of operatorship.
* @dev Can only be called by the proposed operator.
* @param fromOperator The previous operator of the contract.
*/
function acceptOperatorship(address fromOperator) external;
/**
* @notice Query if an address is a operator.
* @param addr The address to query for.
* @return bool Boolean value representing whether or not the address is an operator.
*/
function isOperator(address addr) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { ITokenManager } from './ITokenManager.sol';
/**
* @title ITokenHandler Interface
* @notice This interface is responsible for handling tokens before initiating an interchain token transfer, or after receiving one.
*/
interface ITokenHandler {
error UnsupportedTokenManagerType(uint256 tokenManagerType);
error NotToken(address caller, address token);
/**
* @notice This function gives token to a specified address from the token manager.
* @param tokenId The token id of the tokenManager.
* @param to The address to give tokens to.
* @param amount The amount of tokens to give.
* @return uint256 The amount of token actually given, which could be different for certain token type.
* @return address the address of the token.
*/
function giveToken(bytes32 tokenId, address to, uint256 amount) external returns (uint256, address);
/**
* @notice This function takes token from a specified address to the token manager.
* @param tokenId The tokenId for the token.
* @param tokenOnly can only be called from the token.
* @param from The address to take tokens from.
* @param amount The amount of token to take.
* @return uint256 The amount of token actually taken, which could be different for certain token type.
*/
// slither-disable-next-line locked-ether
function takeToken(bytes32 tokenId, bool tokenOnly, address from, uint256 amount) external payable returns (uint256);
/**
* @notice This function transfers token from and to a specified address.
* @param tokenId The token id of the token manager.
* @param from The address to transfer tokens from.
* @param to The address to transfer tokens to.
* @param amount The amount of token to transfer.
* @return uint256 The amount of token actually transferred, which could be different for certain token type.
* @return address The address of the token corresponding to the input tokenId.
*/
function transferTokenFrom(bytes32 tokenId, address from, address to, uint256 amount) external returns (uint256, address);
/**
* @notice This function prepares a token manager after it is deployed
* @param tokenManagerType The token manager type.
* @param tokenManager The address of the token manager.
*/
function postTokenManagerDeploy(uint256 tokenManagerType, ITokenManager tokenManager) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IImplementation } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IImplementation.sol';
import { IBaseTokenManager } from './IBaseTokenManager.sol';
import { IOperator } from './IOperator.sol';
import { IFlowLimit } from './IFlowLimit.sol';
/**
* @title ITokenManager Interface
* @notice This contract is responsible for managing tokens, such as setting locking token balances, or setting flow limits, for interchain transfers.
*/
interface ITokenManager is IBaseTokenManager, IOperator, IFlowLimit, IImplementation {
error TokenLinkerZeroAddress();
error NotService(address caller);
error TakeTokenFailed();
error GiveTokenFailed();
error NotToken(address caller);
error ZeroAddress();
error AlreadyFlowLimiter(address flowLimiter);
error NotFlowLimiter(address flowLimiter);
error NotSupported();
/**
* @notice Returns implementation type of this token manager.
* @return uint256 The implementation type of this token manager.
*/
function implementationType() external view returns (uint256);
function addFlowIn(uint256 amount) external;
function addFlowOut(uint256 amount) external;
/**
* @notice This function adds a flow limiter for this TokenManager.
* @dev Can only be called by the operator.
* @param flowLimiter the address of the new flow limiter.
*/
function addFlowLimiter(address flowLimiter) external;
/**
* @notice This function removes a flow limiter for this TokenManager.
* @dev Can only be called by the operator.
* @param flowLimiter the address of an existing flow limiter.
*/
function removeFlowLimiter(address flowLimiter) external;
/**
* @notice Query if an address is a flow limiter.
* @param addr The address to query for.
* @return bool Boolean value representing whether or not the address is a flow limiter.
*/
function isFlowLimiter(address addr) external view returns (bool);
/**
* @notice This function sets the flow limit for this TokenManager.
* @dev Can only be called by the flow limiters.
* @param flowLimit_ The maximum difference between the tokens flowing in and/or out at any given interval of time (6h).
*/
function setFlowLimit(uint256 flowLimit_) external;
/**
* @notice A function to renew approval to the service if we need to.
*/
function approveService() external;
/**
* @notice Getter function for the parameters of a lock/unlock TokenManager.
* @dev This function will be mainly used by frontends.
* @param operator_ The operator of the TokenManager.
* @param tokenAddress_ The token to be managed.
* @return params_ The resulting params to be passed to custom TokenManager deployments.
*/
function params(bytes calldata operator_, address tokenAddress_) external pure returns (bytes memory params_);
/**
* @notice External function to allow the service to mint tokens through the tokenManager
* @dev This function should revert if called by anyone but the service.
* @param tokenAddress_ The address of the token, since its cheaper to pass it in instead of reading it as the token manager.
* @param to The recipient.
* @param amount The amount to mint.
*/
function mintToken(address tokenAddress_, address to, uint256 amount) external;
/**
* @notice External function to allow the service to burn tokens through the tokenManager
* @dev This function should revert if called by anyone but the service.
* @param tokenAddress_ The address of the token, since its cheaper to pass it in instead of reading it as the token manager.
* @param from The address to burn the token from.
* @param amount The amount to burn.
*/
function burnToken(address tokenAddress_, address from, uint256 amount) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title ITokenManagerDeployer Interface
* @notice This interface is used to deploy new instances of the TokenManagerProxy contract.
*/
interface ITokenManagerDeployer {
error TokenManagerDeploymentFailed();
/**
* @notice Deploys a new instance of the TokenManagerProxy contract.
* @param tokenId The token ID.
* @param implementationType Token manager implementation type.
* @param params Additional parameters used in the setup of the token manager.
* @return tokenManager Address of the deployed tokenManager.
*/
function deployTokenManager(
bytes32 tokenId,
uint256 implementationType,
bytes calldata params
) external payable returns (address tokenManager);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title ITokenManagerImplementation Interface
* @notice Interface for returning the token manager implementation type.
*/
interface ITokenManagerImplementation {
/**
* @notice Returns the implementation address for a given token manager type.
* @param tokenManagerType The type of token manager.
* @return tokenManagerAddress_ The address of the token manager implementation.
*/
function tokenManagerImplementation(uint256 tokenManagerType) external view returns (address tokenManagerAddress_);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title ITokenManagerType Interface
* @notice A simple interface that defines all the token manager types.
*/
interface ITokenManagerType {
enum TokenManagerType {
NATIVE_INTERCHAIN_TOKEN, // This type is reserved for interchain tokens deployed by ITS, and can't be used by custom token managers.
MINT_BURN_FROM, // The token will be minted/burned on transfers. The token needs to give mint permission to the token manager, but burning happens via an approval.
LOCK_UNLOCK, // The token will be locked/unlocked at the token manager.
LOCK_UNLOCK_FEE, // The token will be locked/unlocked at the token manager, which will account for any fee-on-transfer behaviour.
MINT_BURN // The token will be minted/burned on transfers. The token needs to give mint and burn permission to the token manager.
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title ITransmitInterchainToken Interface
* @notice Interface for transmiting interchain tokens via the interchain token service
*/
interface ITransmitInterchainToken {
/**
* @notice Transmit an interchain transfer for the given tokenId.
* @dev Only callable by a token registered under a tokenId.
* @param tokenId The tokenId of the token (which must be the msg.sender).
* @param sourceAddress The address where the token is coming from.
* @param destinationChain The name of the chain to send tokens to.
* @param destinationAddress The destinationAddress for the interchainTransfer.
* @param amount The amount of token to give.
* @param metadata Optional metadata for the call for additional effects (such as calling a destination contract).
*/
function transmitInterchainTransfer(
bytes32 tokenId,
address sourceAddress,
string calldata destinationChain,
bytes memory destinationAddress,
uint256 amount,
bytes calldata metadata
) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title Create3AddressFixed contract
* @notice This contract can be used to predict the deterministic deployment address of a contract deployed with the `CREATE3` technique.
* It is equivalent to the Create3Address found in axelar-gmp-sdk-solidity repo but uses a fixed bytecode for CreateDeploy,
* which allows changing compilation options (like number of runs) without affecting the future deployment addresses.
*/
contract Create3AddressFixed {
// slither-disable-next-line too-many-digits
bytes internal constant CREATE_DEPLOY_BYTECODE =
hex'608060405234801561001057600080fd5b50610162806100206000396000f3fe60806040526004361061001d5760003560e01c806277436014610022575b600080fd5b61003561003036600461007b565b610037565b005b8051602082016000f061004957600080fd5b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561008d57600080fd5b813567ffffffffffffffff808211156100a557600080fd5b818401915084601f8301126100b957600080fd5b8135818111156100cb576100cb61004c565b604051601f8201601f19908116603f011681019083821181831017156100f3576100f361004c565b8160405282815287602084870101111561010c57600080fd5b82602086016020830137600092810160200192909252509594505050505056fea264697066735822122094780ce55d28f1d568f4e0ab1b9dc230b96e952b73d2e06456fbff2289fa27f464736f6c63430008150033';
bytes32 internal constant CREATE_DEPLOY_BYTECODE_HASH = keccak256(CREATE_DEPLOY_BYTECODE);
/**
* @notice Compute the deployed address that will result from the `CREATE3` method.
* @param deploySalt A salt to influence the contract address
* @return deployed The deterministic contract address if it was deployed
*/
function _create3Address(bytes32 deploySalt) internal view returns (address deployed) {
address deployer = address(
uint160(uint256(keccak256(abi.encodePacked(hex'ff', address(this), deploySalt, CREATE_DEPLOY_BYTECODE_HASH))))
);
deployed = address(uint160(uint256(keccak256(abi.encodePacked(hex'd6_94', deployer, hex'01')))));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { RolesBase } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/RolesBase.sol';
import { IOperator } from '../interfaces/IOperator.sol';
import { RolesConstants } from './RolesConstants.sol';
/**
* @title Operator Contract
* @notice A contract module which provides a basic access control mechanism, where
* there is an account (a operator) that can be granted exclusive access to
* specific functions.
* @dev This module is used through inheritance.
*/
contract Operator is IOperator, RolesBase, RolesConstants {
/**
* @notice Internal function that stores the new operator address in the correct storage slot
* @param operator The address of the new operator
*/
function _addOperator(address operator) internal {
_addRole(operator, uint8(Roles.OPERATOR));
}
/**
* @notice Change the operator of the contract.
* @dev Can only be called by the current operator.
* @param operator The address of the new operator.
*/
function transferOperatorship(address operator) external onlyRole(uint8(Roles.OPERATOR)) {
_transferRole(msg.sender, operator, uint8(Roles.OPERATOR));
}
/**
* @notice Propose a change of the operator of the contract.
* @dev Can only be called by the current operator.
* @param operator The address of the new operator.
*/
function proposeOperatorship(address operator) external onlyRole(uint8(Roles.OPERATOR)) {
_proposeRole(msg.sender, operator, uint8(Roles.OPERATOR));
}
/**
* @notice Accept a proposed change of operatorship.
* @dev Can only be called by the proposed operator.
* @param fromOperator The previous operator of the contract.
*/
function acceptOperatorship(address fromOperator) external {
_acceptRole(fromOperator, msg.sender, uint8(Roles.OPERATOR));
}
/**
* @notice Query if an address is a operator.
* @param addr The address to query for.
* @return bool Boolean value representing whether or not the address is an operator.
*/
function isOperator(address addr) external view returns (bool) {
return hasRole(addr, uint8(Roles.OPERATOR));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title RolesConstants
* @notice This contract contains enum values representing different contract roles.
*/
contract RolesConstants {
enum Roles {
MINTER,
OPERATOR,
FLOW_LIMITER
}
}{
"evmVersion": "london",
"optimizer": {
"enabled": true,
"runs": 100,
"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
Contract ABI
API[{"inputs":[{"internalType":"address","name":"tokenManagerDeployer_","type":"address"},{"internalType":"address","name":"interchainTokenDeployer_","type":"address"},{"internalType":"address","name":"gateway_","type":"address"},{"internalType":"address","name":"gasService_","type":"address"},{"internalType":"address","name":"interchainTokenFactory_","type":"address"},{"internalType":"string","name":"chainName_","type":"string"},{"internalType":"address","name":"tokenManagerImplementation_","type":"address"},{"internalType":"address","name":"tokenHandler_","type":"address"},{"internalType":"address","name":"gatewayCaller_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyExecuted","type":"error"},{"inputs":[{"internalType":"enum ITokenManagerType.TokenManagerType","name":"","type":"uint8"}],"name":"CannotDeploy","type":"error"},{"inputs":[],"name":"CannotDeployRemotelyToSelf","type":"error"},{"inputs":[],"name":"EmptyData","type":"error"},{"inputs":[],"name":"EmptyDestinationAddress","type":"error"},{"inputs":[],"name":"EmptyParams","type":"error"},{"inputs":[],"name":"EmptyTokenAddress","type":"error"},{"inputs":[],"name":"EmptyTokenName","type":"error"},{"inputs":[],"name":"EmptyTokenSymbol","type":"error"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"ExecuteWithInterchainTokenFailed","type":"error"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"ExpressExecuteWithInterchainTokenFailed","type":"error"},{"inputs":[],"name":"ExpressExecutorAlreadySet","type":"error"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"GatewayCallFailed","type":"error"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"GiveTokenFailed","type":"error"},{"inputs":[],"name":"InsufficientValue","type":"error"},{"inputs":[{"internalType":"bytes","name":"error","type":"bytes"}],"name":"InterchainTokenDeploymentFailed","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[{"internalType":"bytes","name":"bytesAddress","type":"bytes"}],"name":"InvalidBytesLength","type":"error"},{"inputs":[],"name":"InvalidChainName","type":"error"},{"inputs":[],"name":"InvalidCodeHash","type":"error"},{"inputs":[{"internalType":"uint256","name":"messageType","type":"uint256"}],"name":"InvalidExpressMessageType","type":"error"},{"inputs":[],"name":"InvalidImplementation","type":"error"},{"inputs":[{"internalType":"uint256","name":"messageType","type":"uint256"}],"name":"InvalidMessageType","type":"error"},{"inputs":[{"internalType":"uint32","name":"version","type":"uint32"}],"name":"InvalidMetadataVersion","type":"error"},{"inputs":[],"name":"InvalidOwner","type":"error"},{"inputs":[],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidPayload","type":"error"},{"inputs":[{"internalType":"address","name":"fromAccount","type":"address"},{"internalType":"address","name":"toAccount","type":"address"},{"internalType":"uint256","name":"accountRoles","type":"uint256"}],"name":"InvalidProposedRoles","type":"error"},{"inputs":[],"name":"LengthMismatch","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"accountRoles","type":"uint256"}],"name":"MissingAllRoles","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"accountRoles","type":"uint256"}],"name":"MissingAnyOfRoles","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint8","name":"role","type":"uint8"}],"name":"MissingRole","type":"error"},{"inputs":[],"name":"MulticallFailed","type":"error"},{"inputs":[],"name":"NotApprovedByGateway","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotInterchainTokenFactory","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"NotPaused","type":"error"},{"inputs":[],"name":"NotProxy","type":"error"},{"inputs":[],"name":"NotRemoteService","type":"error"},{"inputs":[],"name":"NotSupported","type":"error"},{"inputs":[],"name":"Pause","type":"error"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"PostDeployFailed","type":"error"},{"inputs":[],"name":"SetupFailed","type":"error"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"TakeTokenFailed","type":"error"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"TokenHandlerFailed","type":"error"},{"inputs":[{"internalType":"bytes","name":"error","type":"bytes"}],"name":"TokenManagerDeploymentFailed","type":"error"},{"inputs":[{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"name":"TokenManagerDoesNotExist","type":"error"},{"inputs":[],"name":"UntrustedChain","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"inputs":[],"name":"ZeroStringLength","type":"error"},{"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":false,"internalType":"bytes32","name":"payloadHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"expressExecutor","type":"address"}],"name":"ExpressExecuted","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":false,"internalType":"bytes32","name":"payloadHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"expressExecutor","type":"address"}],"name":"ExpressExecutionFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"InterchainTokenDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"indexed":false,"internalType":"string","name":"tokenName","type":"string"},{"indexed":false,"internalType":"string","name":"tokenSymbol","type":"string"},{"indexed":false,"internalType":"uint8","name":"tokenDecimals","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"minter","type":"bytes"},{"indexed":false,"internalType":"string","name":"destinationChain","type":"string"}],"name":"InterchainTokenDeploymentStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"deployer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"InterchainTokenIdClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sourceAddress","type":"address"},{"indexed":false,"internalType":"string","name":"destinationChain","type":"string"},{"indexed":false,"internalType":"bytes","name":"destinationAddress","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"dataHash","type":"bytes32"}],"name":"InterchainTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"commandId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"indexed":false,"internalType":"string","name":"sourceChain","type":"string"},{"indexed":false,"internalType":"bytes","name":"sourceAddress","type":"bytes"},{"indexed":true,"internalType":"address","name":"destinationAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"dataHash","type":"bytes32"}],"name":"InterchainTransferReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"indexed":false,"internalType":"string","name":"destinationChain","type":"string"},{"indexed":false,"internalType":"bytes","name":"sourceTokenAddress","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"destinationTokenAddress","type":"bytes"},{"indexed":true,"internalType":"enum ITokenManagerType.TokenManagerType","name":"tokenManagerType","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"params","type":"bytes"}],"name":"LinkTokenStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"accountRoles","type":"uint256"}],"name":"RolesAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"fromAccount","type":"address"},{"indexed":true,"internalType":"address","name":"toAccount","type":"address"},{"indexed":false,"internalType":"uint256","name":"accountRoles","type":"uint256"}],"name":"RolesProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"accountRoles","type":"uint256"}],"name":"RolesRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"tokenManager","type":"address"},{"indexed":true,"internalType":"enum ITokenManagerType.TokenManagerType","name":"tokenManagerType","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"params","type":"bytes"}],"name":"TokenManagerDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"TokenMetadataRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"chain","type":"string"}],"name":"TrustedAddressRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"chain","type":"string"},{"indexed":false,"internalType":"string","name":"address_","type":"string"}],"name":"TrustedAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newImplementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[{"internalType":"address","name":"fromOperator","type":"address"}],"name":"acceptOperatorship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"chainName","outputs":[{"internalType":"string","name":"chainName_","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainNameHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"sourceChain","type":"string"},{"internalType":"string","name":"sourceAddress","type":"string"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"contractCallValue","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"string","name":"destinationChain","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"bytes","name":"minter","type":"bytes"},{"internalType":"uint256","name":"gasValue","type":"uint256"}],"name":"deployInterchainToken","outputs":[{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"name":"deployedTokenManager","outputs":[{"internalType":"contract ITokenManager","name":"tokenManager_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commandId","type":"bytes32"},{"internalType":"string","name":"sourceChain","type":"string"},{"internalType":"string","name":"sourceAddress","type":"string"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"execute","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":"bytes","name":"payload","type":"bytes"}],"name":"expressExecute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"gasService","outputs":[{"internalType":"contract IAxelarGasService","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gateway","outputs":[{"internalType":"contract IAxelarGateway","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gatewayCaller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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":"getExpressExecutor","outputs":[{"internalType":"address","name":"expressExecutor","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint8","name":"role","type":"uint8"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"implementation_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"name":"interchainTokenAddress","outputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interchainTokenDeployer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interchainTokenFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"interchainTokenId","outputs":[{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"internalType":"string","name":"destinationChain","type":"string"},{"internalType":"bytes","name":"destinationAddress","type":"bytes"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"metadata","type":"bytes"},{"internalType":"uint256","name":"gasValue","type":"uint256"}],"name":"interchainTransfer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isOperator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"chain","type":"string"},{"internalType":"string","name":"address_","type":"string"}],"name":"isTrustedAddress","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"string","name":"destinationChain","type":"string"},{"internalType":"bytes","name":"destinationTokenAddress","type":"bytes"},{"internalType":"enum ITokenManagerType.TokenManagerType","name":"tokenManagerType","type":"uint8"},{"internalType":"bytes","name":"linkParams","type":"bytes"},{"internalType":"uint256","name":"gasValue","type":"uint256"}],"name":"linkToken","outputs":[{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"name":"migrateInterchainToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"owner_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"paused_","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"owner_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"proposeOperatorship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"proposeOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"enum ITokenManagerType.TokenManagerType","name":"tokenManagerType","type":"uint8"},{"internalType":"bytes","name":"linkParams","type":"bytes"}],"name":"registerCustomToken","outputs":[{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"gasValue","type":"uint256"}],"name":"registerTokenMetadata","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"name":"registeredTokenAddress","outputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"chain","type":"string"}],"name":"removeTrustedAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"tokenIds","type":"bytes32[]"},{"internalType":"uint256[]","name":"flowLimits","type":"uint256[]"}],"name":"setFlowLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"paused","type":"bool"}],"name":"setPauseStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"chain","type":"string"},{"internalType":"string","name":"address_","type":"string"}],"name":"setTrustedAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenHandler","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"name":"tokenManagerAddress","outputs":[{"internalType":"address","name":"tokenManagerAddress_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenManagerDeployer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenManagerImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"transferOperatorship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"internalType":"address","name":"sourceAddress","type":"address"},{"internalType":"string","name":"destinationChain","type":"string"},{"internalType":"bytes","name":"destinationAddress","type":"bytes"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"transmitInterchainTransfer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"chain","type":"string"}],"name":"trustedAddress","outputs":[{"internalType":"string","name":"trustedAddress_","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"chain","type":"string"}],"name":"trustedAddressHash","outputs":[{"internalType":"bytes32","name":"trustedAddressHash_","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes32","name":"newImplementationCodeHash","type":"bytes32"},{"internalType":"bytes","name":"params","type":"bytes"}],"name":"upgrade","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6101c060405234801561001157600080fd5b50604051615dd6380380615dd683398101604081905261003091610239565b600161003b81610164565b50306080526001600160a01b038616158061005d57506001600160a01b038916155b8061006f57506001600160a01b038816155b8061008157506001600160a01b038716155b8061009357506001600160a01b038516155b806100a557506001600160a01b038316155b806100b757506001600160a01b038216155b806100c957506001600160a01b038116155b156100e75760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0380881660a05286811660c0528981166101405288811661012052851660e052835160000361013057604051630470832760e11b815260040160405180910390fd5b8351602090940193909320610100526001600160a01b0391821661016052811661018052166101a0525061038c9350505050565b6001600160a01b03811661018b57604051633649397d60e21b815260040160405180910390fd5b6040516001600160a01b038216907f04dba622d284ed0014ee4b9a6a68386be1a4c08a4913ae272de89199cc68616390600090a27f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c05560007f9855384122b55936fbfb8ca5120e63c6537a1ac40caf6ae33502b3c5da8c87d155565b80516001600160a01b038116811461021e57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60008060008060008060008060006101208a8c03121561025857600080fd5b6102618a610207565b985061026f60208b01610207565b975061027d60408b01610207565b965061028b60608b01610207565b955061029960808b01610207565b60a08b01519095506001600160401b038111156102b557600080fd5b8a01601f81018c136102c657600080fd5b80516001600160401b038111156102df576102df610223565b604051601f8201601f19908116603f011681016001600160401b038111828210171561030d5761030d610223565b6040528181528282016020018e101561032557600080fd5b60005b8281101561034457602081850181015183830182015201610328565b5060006020838301015280965050505061036060c08b01610207565b925061036e60e08b01610207565b915061037d6101008b01610207565b90509295985092959850929598565b60805160a05160c05160e05161010051610120516101405161016051610180516101a05161595f610477600039600081816102c0015261277401526000818161035f015281816121ac015281816123af01528181612e9b0152613aff0152600081816103b5015261061501526000818161052d0152612da101526000818161046b0152612c2c0152600081816106bd01528181610a6601528181611c14015261290901526000818161084601528181610aae01528181611b590152611ce7015260006104f901526000818161032b01528181610de00152610f9301526000611498015261595f6000f3fe6080604052600436106102a95760003560e01c806383d2969611610165578063c7e6a3cc116100cc578063e30c397811610085578063e30c3978146108ce578063e82e71f8146108f0578063f2fde38b14610910578063f49c044a14610930578063f6e3a22914610943578063f8c8a82614610963578063ffd5982a1461098357600080fd5b8063c7e6a3cc14610814578063ca58b64414610834578063da081c7314610868578063da4886df1461087b578063dc88dfd11461089b578063e1d40c77146108bb57600080fd5b8063a3499c731161011e578063a3499c7314610754578063a5269ef114610774578063ac9650d814610794578063b90d6afd146107b4578063c38bb537146107d4578063c506bff4146107f457600080fd5b806383d296961461067d578063864a0dcf146106ab5780638da5cb5b146106df57806395a8c58d146106f45780639ded06df146107145780639f409d771461073457600080fd5b80635c975abb1161021457806370756cde116101cd57806370756cde1461058f578063710bf322146105a257806379ba5097146105c25780637e10eb15146105d75780637e151fa6146105f75780637fb53dc9146106375780638291286c1461064a57600080fd5b80635c975abb146104af57806365657636146104d45780636a22d8cc146104e75780636ac0d1121461051b5780636d70f7ae1461054f5780636f3eef621461056f57600080fd5b8063465a09e011610266578063465a09e0146103d7578063477aedc7146103f957806349160658146104195780634a6a42d8146104395780634f9ae608146104595780635c60da1b1461048d57600080fd5b80630af20483146102ae5780630f4433d3146102f8578063116191b6146103195780631b3d6e871461034d5780631c93b03a146103815780632a709b14146103a3575b600080fd5b3480156102ba57600080fd5b506102e27f000000000000000000000000000000000000000000000000000000000000000081565b6040516102ef9190613db4565b60405180910390f35b61030b610306366004613e16565b6109a3565b6040519081526020016102ef565b34801561032557600080fd5b506102e27f000000000000000000000000000000000000000000000000000000000000000081565b34801561035957600080fd5b506102e27f000000000000000000000000000000000000000000000000000000000000000081565b34801561038d57600080fd5b50610396610bfc565b6040516102ef9190613f2d565b3480156103af57600080fd5b506102e27f000000000000000000000000000000000000000000000000000000000000000081565b3480156103e357600080fd5b506103f76103f2366004613f84565b610c2c565b005b34801561040557600080fd5b506103966104143660046140b9565b610d43565b34801561042557600080fd5b506103f76104343660046140f5565b610d5c565b34801561044557600080fd5b506103f76104543660046141b7565b610ed3565b34801561046557600080fd5b506102e27f000000000000000000000000000000000000000000000000000000000000000081565b34801561049957600080fd5b50600080516020615748833981519152546102e2565b3480156104bb57600080fd5b506104c4610f12565b60405190151581526020016102ef565b6103f76104e23660046140f5565b610f25565b3480156104f357600080fd5b506102e27f000000000000000000000000000000000000000000000000000000000000000081565b34801561052757600080fd5b506102e27f000000000000000000000000000000000000000000000000000000000000000081565b34801561055b57600080fd5b506104c461056a3660046141b7565b6110b5565b34801561057b57600080fd5b506103f761058a3660046141b7565b6110c2565b6103f761059d3660046141d4565b6110fd565b3480156105ae57600080fd5b506103f76105bd3660046141b7565b611154565b3480156105ce57600080fd5b506103f76111f1565b3480156105e357600080fd5b506102e26105f2366004614297565b611240565b34801561060357600080fd5b506102e2610612366004614297565b507f000000000000000000000000000000000000000000000000000000000000000090565b6103f76106453660046142b0565b61127c565b34801561065657600080fd5b507ff407da03daa7b4243ffb261daad9b01d221ea90ab941948cd48101563654ea8661030b565b34801561068957600080fd5b5061069d6106983660046142dc565b6113db565b6040516102ef92919061437f565b3480156106b757600080fd5b5061030b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106eb57600080fd5b506102e261144e565b34801561070057600080fd5b506104c461070f3660046143b7565b611473565b34801561072057600080fd5b506103f761072f3660046143f0565b611495565b34801561074057600080fd5b506103f761074f366004614431565b6114e8565b34801561076057600080fd5b506103f761076f366004614498565b611522565b34801561078057600080fd5b5061030b61078f3660046142b0565b611787565b6107a76107a23660046144e7565b6117dc565b6040516102ef919061451c565b3480156107c057600080fd5b506102e26107cf366004614297565b611912565b3480156107e057600080fd5b506103f76107ef36600461458f565b61197e565b34801561080057600080fd5b506104c461080f3660046145ac565b6119c4565b34801561082057600080fd5b506102e261082f366004614603565b611a2a565b34801561084057600080fd5b506102e27f000000000000000000000000000000000000000000000000000000000000000081565b6103f7610876366004614688565b611a45565b34801561088757600080fd5b506103f76108963660046141b7565b611ae1565b3480156108a757600080fd5b506103f76108b63660046140b9565b611aed565b61030b6108c9366004614720565b611b26565b3480156108da57600080fd5b50600080516020615788833981519152546102e2565b3480156108fc57600080fd5b506102e261090b366004614297565b611c6e565b34801561091c57600080fd5b506103f761092b3660046141b7565b611c84565b61030b61093e366004614807565b611cb4565b34801561094f57600080fd5b506103f761095e366004614297565b611ddb565b34801561096f57600080fd5b506102e261097e366004614297565b611ed9565b34801561098f57600080fd5b5061030b61099e3660046140b9565b611ee4565b60006109ad610f12565b156109cb576040516334c2d01160e11b815260040160405180910390fd5b60008690036109ed5760405163c6f4c06f60e01b815260040160405180910390fd5b6000856004811115610a0157610a01614879565b03610a2a5784604051630a7dda8360e01b8152600401610a2191906148a3565b60405180910390fd5b6000889003610a4c57604051630280e1e560e61b815260040160405180910390fd5b8888604051610a5c9291906148b1565b60405180910390207f000000000000000000000000000000000000000000000000000000000000000003610aa357604051633a6aed5960e21b815260040160405180910390fd5b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168103610ad8575060005b610ae2818c611787565b91508a816001600160a01b03168360008051602061576883398151915260405160405180910390a46000610b26610b1884611912565b6001600160a01b0316611ef8565b9050866004811115610b3a57610b3a614879565b837f6d8eb6e760238fe99c48de1a8bec4365cbeead2dbe47669c989722eaaa64a8478d8d858e8e8d8d604051610b7697969594939291906148ea565b60405180910390a3600060058489848d8d8c8c604051602001610ba0989796959493929190614948565b60408051601f198184030181526020601f8f018190048102840181019092528d83529250610bec91908e908e908190840183828082843760009201829052508693509150899050611f26565b5050509998505050505050505050565b6060610c277f0e2c162a1f4b5cff9fdbd6b34678a9bcb9898a0b9fbca695b112d61688d8b2ac611f47565b905090565b6001610c47610c3a33611fda565b600160ff84161b16151590565b610c6857338160405163bb6c163960e01b8152600401610a219291906149ab565b83828114610c8c576040516001621398b960e31b0319815260040160405180910390fd5b60005b81811015610d3a57610cb8878783818110610cac57610cac6149c7565b90506020020135611240565b6001600160a01b031663a56dbe63868684818110610cd857610cd86149c7565b905060200201356040518263ffffffff1660e01b8152600401610cfd91815260200190565b600060405180830381600087803b158015610d1757600080fd5b505af1158015610d2b573d6000803e3d6000fd5b50505050806001019050610c8f565b50505050505050565b6060610d56610d5183611fe6565b611f47565b92915050565b85858585610d6c848484846119c4565b610d895760405163157e5fbf60e21b815260040160405180910390fd5b610d91610f12565b15610daf576040516334c2d01160e11b815260040160405180910390fd5b60008686604051610dc19291906148b1565b604051908190038120635f6970c360e01b825291506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635f6970c390610e1f908f908f908f908f908f9089906004016149dd565b6020604051808303816000875af1158015610e3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e629190614a1e565b610e7f57604051631403112d60e21b815260040160405180910390fd5b610ec58c8c8c8c8c8c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a9250612038915050565b505050505050505050505050565b6001610ee1610c3a33611fda565b610f0257338160405163bb6c163960e01b8152600401610a219291906149ab565b610f0e338360016120c5565b5050565b6000805160206157288339815191525490565b610f2d610f12565b15610f4b576040516334c2d01160e11b815260040160405180910390fd5b6000610f5982840184614297565b90508015610f7d5760405163e94617f560e01b815260048101829052602401610a21565b604051630d26ff2160e41b8152600481018990527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063d26ff21090602401602060405180830381865afa158015610fe2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110069190614a1e565b1561102457604051630dc1019760e01b815260040160405180910390fd5b604051339060009061103990869086906148b1565b60405180910390209050816001600160a01b03168a7f6e18757e81c44a367109cbaa499add16f2ae7168aab9715c3cdc36b0f7ccce928b8b8b8b87604051611085959493929190614a3b565b60405180910390a361109c8a8a8a8a8a86886120db565b6110a98a8a8a8888612122565b50505050505050505050565b6000610d56826001611473565b60016110d0610c3a33611fda565b6110f157338160405163bb6c163960e01b8152600401610a219291906149ab565b610f0e33836001612397565b611105610f12565b15611123576040516334c2d01160e11b815260040160405180910390fd5b61113088888560016123a8565b925060008061113f84846124cc565b915091506110a98a8a8a8a8a8a88883461259f565b3361115d61144e565b6001600160a01b031614611184576040516330cd747160e01b815260040160405180910390fd5b6001600160a01b0381166111ab57604051633649397d60e21b815260040160405180910390fd5b6040516001600160a01b038216907fd9be0e8e07417e00f2521db636cb53e316fd288f5051f16d2aa2bf0c3938a87690600090a260008051602061578883398151915255565b60006112096000805160206157888339815191525490565b90506001600160a01b0381163314611234576040516349e27cff60e01b815260040160405180910390fd5b61123d816126bc565b50565b60008061124c83611ed9565b9050806001600160a01b03163b600003610d5657604051630b7616bf60e21b815260048101849052602401610a21565b6001600160a01b0382166112a35760405163c6f4c06f60e01b815260040160405180910390fd5b6000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113079190614a75565b90506000600661131f856001600160a01b0316611ef8565b8360405160200161133293929190614a92565b60408051601f198184030181529082905260ff8416825291506001600160a01b038516907f58480fc929990fed6b4f0f83c65bc9ee9a9025d9fa483749504587acdc6916fa9060200160405180910390a26113d56040518060400160405280600681526020016530bc32b630b960d11b8152506113cc6040518060400160405280600681526020016530bc32b630b960d11b815250610d43565b8360008761274d565b50505050565b600080878787876113ee848484846119c4565b61140b5760405163157e5fbf60e21b815260040160405180910390fd5b611413610f12565b15611431576040516334c2d01160e11b815260040160405180910390fd5b61143b8888612860565b9550955050505050965096945050505050565b7f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c05490565b600061148e61148184611fda565b600160ff85161b16151590565b9392505050565b307f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316036114de57604051635f886e9d60e11b815260040160405180910390fd5b610f0e82826128b3565b336114f161144e565b6001600160a01b031614611518576040516330cd747160e01b815260040160405180910390fd5b610f0e82826129d8565b3361152b61144e565b6001600160a01b031614611552576040516330cd747160e01b815260040160405180910390fd5b600080516020615748833981519152546001600160a01b0316638291286c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561159f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c39190614abe565b846001600160a01b0316638291286c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611601573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116259190614abe565b146116435760405163340aafcd60e11b815260040160405180910390fd5b836001600160a01b03163f831461166d576040516323e13ec960e21b815260040160405180910390fd5b6000805160206157488339815191528490556040516001600160a01b038516907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a280156113d5576000846001600160a01b0316639ded06df60e01b84846040516024016116e0929190614ad7565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161171e9190614aeb565b600060405180830381855af49150503d8060008114611759576040519150601f19603f3d011682016040523d82523d6000602084013e61175e565b606091505b5050905080611780576040516397905dfb60e01b815260040160405180910390fd5b5050505050565b60007f980c3be34c7ee75cc250c76223092614e21653cdf2faece10ac24fcef821df1083836040516020016117be93929190614b07565b60405160208183030381529060405280519060200120905092915050565b6060816001600160401b038111156117f6576117f6613ff3565b60405190808252806020026020018201604052801561182957816020015b60608152602001906001900390816118145790505b5090506000606060005b84811015611909573086868381811061184e5761184e6149c7565b90506020028101906118609190614b26565b60405161186e9291906148b1565b600060405180830381855af49150503d80600081146118a9576040519150601f19603f3d011682016040523d82523d6000602084013e6118ae565b606091505b509093509150826118e35781516000036118db576040516309ad446560e31b815260040160405180910390fd5b815182602001fd5b818482815181106118f6576118f66149c7565b6020908102919091010152600101611833565b50505092915050565b600061191d82611240565b6001600160a01b0316639d76ea586040518163ffffffff1660e01b8152600401602060405180830381865afa15801561195a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d569190614b6c565b3361198761144e565b6001600160a01b0316146119ae576040516330cd747160e01b815260040160405180910390fd5b80156119bc5761123d612a87565b61123d612acb565b60008083836040516119d79291906148b1565b60405180910390209050611a2086868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611ee492505050565b1495945050505050565b6000611a3a878787878787612b0f565b979650505050505050565b611a4d610f12565b15611a6b576040516334c2d01160e11b815260040160405180910390fd5b611a7889338660006123a8565b9350600080611a8785856124cc565b91509150611ad48b338c8c8c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508e92508a91508990508b61259f565b5050505050505050505050565b61123d81336001612b2d565b33611af661144e565b6001600160a01b031614611b1d576040516330cd747160e01b815260040160405180910390fd5b61123d81612b3e565b6000611b30610f12565b15611b4e576040516334c2d01160e11b815260040160405180910390fd5b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611b995733604051630b160a0560e11b8152600401610a219190613db4565b6000611ba5818b611787565b915089816001600160a01b03168360008051602061576883398151915260405160405180910390a46000889003611bfa576000611be583868a8a8a612bbd565b9050611bf48360008388612d76565b50611c61565b8888604051611c0a9291906148b1565b60405180910390207f000000000000000000000000000000000000000000000000000000000000000003611c5157604051633a6aed5960e21b815260040160405180910390fd5b611c6182888888888e8e8a612fcf565b5098975050505050505050565b6000611c79826130c9565b9150610d5682613104565b33611c8d61144e565b6001600160a01b031614611234576040516330cd747160e01b815260040160405180910390fd5b6000611cbe610f12565b15611cdc576040516334c2d01160e11b815260040160405180910390fd5b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611d275733604051630b160a0560e11b8152600401610a219190613db4565b6000846004811115611d3b57611d3b614879565b03611d5b5783604051630a7dda8360e01b8152600401610a2191906148a3565b6000611d678188611787565b915086816001600160a01b03168360008051602061576883398151915260405160405180910390a4611dd182868887878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612d7692505050565b5095945050505050565b33611de461144e565b6001600160a01b031614611e0b576040516330cd747160e01b815260040160405180910390fd5b6000611e1682611240565b90506000816001600160a01b0316639d76ea586040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e7c9190614b6c565b6040516367c354ad60e11b81529091506001600160a01b0382169063cf86a95a90611eab908590600401613db4565b600060405180830381600087803b158015611ec557600080fd5b505af1158015610d3a573d6000803e3d6000fd5b6000610d5682613104565b600080611ef0836131c6565b549392505050565b6040805160148082528183019092526060916020820181803683375050506014808201939093529182525090565b6060611f3285856131fb565b9196509094509050611780858286868661274d565b6060818054611f5590614b89565b80601f0160208091040260200160405190810160405280929190818152602001828054611f8190614b89565b8015611fce5780601f10611fa357610100808354040283529160200191611fce565b820191906000526020600020905b815481529060010190602001808311611fb157829003601f168201915b50505050509050919050565b600080611ef08361336d565b60007fa5b4aa1bcb538076d57d083e3004c6907e2eba42d84c21922d441967a02b472f8260405160200161201b929190614bc3565b604051602081830303815290604052805190602001209050919050565b600060606120478888866133b8565b95509092509050816120775760006120638a8a8a8a8a896135c5565b90506120718a82848861363b565b506120ba565b6001820361208d57612088846137d9565b6120ba565b6005820361209e576120888461381e565b6040516324af919760e11b815260048101839052602401610a21565b505050505050505050565b6120d68383600160ff85161b61389b565b505050565b60006120eb8888888888886138e3565b80549091506001600160a01b038116156121185760405163725f13f160e01b815260040160405180910390fd5b5055505050505050565b60008080808061213486880188614bdc565b9550955095509550955050600061214a84613944565b60408051602481018990523360448201526001600160a01b03838116606483015260848083018890528351808403909101815260a490920183526020820180516001600160e01b031663041eebc160e31b1790529151929350600092839283927f0000000000000000000000000000000000000000000000000000000000000000909116916121d99190614aeb565b600060405180830381855af49150503d8060008114612214576040519150601f19603f3d011682016040523d82523d6000602084013e612219565b606091505b50915091508161223e5780604051633a5cf90560e01b8152600401610a219190613f2d565b808060200190518101906122529190614c89565b80945081975050505050816001600160a01b0316878d7fbdb65cfd017af0876344138f62bc895163b5fd120cbe6e666ed306afd658de4b8e8e8b8a8a516000146122a2578a5160208c01206122a5565b60005b6040516122b6959493929190614caf565b60405180910390a4825115610ec5576000826001600160a01b03166377c790258e8e8e8b898e898d6040518963ffffffff1660e01b8152600401612301989796959493929190614cea565b6020604051808303816000875af1158015612320573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123449190614abe565b90507f692b2deb10f974787eb65450ba9a90dc0bb28141a633fa3fb556d5292fba42e18114612388578260405163c646a62360e01b8152600401610a219190613db4565b50505050505050505050505050565b6120d68383600160ff85161b613972565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ea52548360e01b88868989604051602401612415949392919093845291151560208401526001600160a01b03166040830152606082015260800190565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516124539190614aeb565b600060405180830381855af49150503d806000811461248e576040519150601f19603f3d011682016040523d82523d6000602084013e612493565b606091505b5091509150816124b85780604051631a59c9bd60e01b8152600401610a219190613f2d565b80806020019051810190611a3a9190614abe565b6000606060048310156124e25760009150612598565b60006124f16004828688614d54565b6124fa91614d7e565b60e01c905060018111156125295760405163b47a9b4b60e01b815263ffffffff82166004820152602401610a21565b8063ffffffff16600181111561254157612541614879565b925060048490036125525750612598565b61255f8460048188614d54565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929450505050505b9250929050565b84516000036125c15760405163d0639b6560e01b815260040160405180910390fd5b836000036125e257604051631f2a200560e01b815260040160405180910390fd5b8151156125f557815160208301206125f8565b60005b886001600160a01b03168a7fcd05f5b9dc4bb03babf40f5da98f5f46819846207d916f89b67d36fd1f7fd74f8a8a8a8a6040516126389493929190614db6565b60405180910390a46000808a6126568b6001600160a01b0316611ef8565b88888760405160200161266e96959493929190614dee565b60408051601f198184030181526020601f8b0181900481028401810190925289835292506110a991908a908a9081908401838280828437600092019190915250859250889150869050611f26565b6001600160a01b0381166126e357604051633649397d60e21b815260040160405180910390fd5b6040516001600160a01b038216907f04dba622d284ed0014ee4b9a6a68386be1a4c08a4913ae272de89199cc68616390600090a27f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c055600060008051602061578883398151915255565b835160000361276f57604051631f23114d60e31b815260040160405180910390fd5b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bbf4f1bd60e01b88888888886040516024016127bd959493929190614e46565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516127fb9190614aeb565b600060405180830381855af49150503d8060008114612836576040519150601f19603f3d011682016040523d82523d6000602084013e61283b565b606091505b509150915081610d3a5780604051637f32207b60e11b8152600401610a219190613f2d565b60008080808061287286880188614ea5565b94505050925092506000831461289e5760405163e94617f560e01b815260048101849052602401610a21565b6128a782611912565b97909650945050505050565b60008080806128c485870187614fc3565b8151939750919550935091506001600160a01b0385166128f75760405163d92e233d60e01b815260040160405180910390fd5b8351158061292b5750835160208501207f000000000000000000000000000000000000000000000000000000000000000014155b1561294957604051630470832760e11b815260040160405180910390fd5b8151811461296d576040516001621398b960e31b0319815260040160405180910390fd5b612976856139fc565b61297f84613a07565b60005b818110156129ce576129c684828151811061299f5761299f6149c7565b60200260200101518483815181106129b9576129b96149c7565b60200260200101516129d8565b600101612982565b5050505050505050565b81516000036129fa5760405163deba168960e01b815260040160405180910390fd5b8051600003612a1c5760405163deba168960e01b815260040160405180910390fd5b612a2e612a2883611fe6565b82613a2d565b6000612a39836131c6565b82516020840120808255604051919250907fdb6b260ea45f7fe513e1d3b8c21017a29e3a41610e95aefb8862b81c69aec61c90612a799086908690615067565b60405180910390a150505050565b612a9e600160008051602061572883398151915255565b60405133907f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890600090a2565b612ae2600060008051602061572883398151915255565b60405133907f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa90600090a2565b600080612b208888888888886138e3565b5498975050505050505050565b6120d68383600160ff85161b613a38565b8051600003612b605760405163deba168960e01b815260040160405180910390fd5b612b71612b6c82611fe6565b613a92565b6000612b7c826131c6565b9050600081557ff9400637a329865492b8d0d4dba4eafc7e8d5d0fae5e27b56766816d2ae1b2ca82604051612bb19190613f2d565b60405180910390a15050565b60008351600003612be15760405163e2592aed60e01b815260040160405180910390fd5b8251600003612c0357604051630ce3838560e11b815260040160405180910390fd5b6000612c0e876130c9565b905060008651600014612c2757612c2487613944565b90505b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f575f35b60e01b858c868c8c8c604051602401612c7796959493929190615095565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612cb59190614aeb565b600060405180830381855af49150503d8060008114612cf0576040519150601f19603f3d011682016040523d82523d6000602084013e612cf5565b606091505b509150915081612d1a578060405163c226af8b60e01b8152600401610a219190613f2d565b60208101519450826001600160a01b03168a7ff0d7beb2b03d35e597f432391dc2a6f6eb1a621be6cb5b325f55a49090085239878b8b8b604051612d6194939291906150eb565b60405180910390a35050505095945050505050565b60008183604051602001612d8b929190615136565b60405160208183030381529060405290506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636519d04b60e01b888886604051602401612de693929190615160565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612e249190614aeb565b600060405180830381855af49150503d8060008114612e5f576040519150601f19603f3d011682016040523d82523d6000602084013e612e64565b606091505b509150915081612e895780604051637cf77c1560e11b8152600401610a219190613f2d565b60208101516040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063dbd15f2f60e01b90612ed5908a908590602401615186565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612f139190614aeb565b600060405180830381855af49150503d8060008114612f4e576040519150601f19603f3d011682016040523d82523d6000602084013e612f53565b606091505b50909350915082612f795781604051631b559efb60e21b8152600401610a219190613f2d565b866004811115612f8b57612f8b614879565b887f5284c2478b9c1a55e973429331078be39b5fb3eeb9d87d10b34d65a4c89ee4eb8387604051612fbd9291906151ac565b60405180910390a35050505050505050565b8651600003612ff15760405163e2592aed60e01b815260040160405180910390fd5b855160000361301357604051630ce3838560e11b815260040160405180910390fd5b61301c88611240565b50877fe470f4bdd33c8676127d3c20ff725d8dc1605609001389ce3a59c28b54b7992f888888888888604051613057969594939291906151d0565b60405180910390a260006001898989898960405160200161307d96959493929190615227565b60408051601f198184030181526020601f870181900481028401810190925285835292506120ba9190869086908190840183828082843760009201829052508693509150869050611f26565b604080517f610507e221586f499adb972fbdbe7f0619bdae0112c78ebaa562448d0ca7071f602082015290810182905260009060600161201b565b6000803083604051806101c0016040528061018281526020016157a86101829139805160209182012060405161316a949392016001600160f81b0319815260609390931b6001600160601b03191660018401526015830191909152603582015260550190565b60408051601f1981840301815282825280516020918201206135a560f21b8285015260601b6001600160601b0319166022840152600160f81b603684015281516017818503018152603790930190915281519101209392505050565b60007f5f58fea7d48d37d5d1cc2546dfcc3d3cbfe8d758d5ca19c44087f52e15a105058260405160200161201b929190614bc3565b6060806060600061320b86610d43565b90506040518060400160405280600681526020016530bc32b630b960d11b81525060405160200161323c9190614aeb565b60405160208183030381529060405280519060200120866040516020016132639190614aeb565b604051602081830303815290604052805190602001200361329757604051631f23114d60e31b815260040160405180910390fd5b60405180604001604052806003815260200162343ab160e91b8152506040516020016132c39190614aeb565b60405160208183030381529060405280519060200120816040516020016132ea9190614aeb565b6040516020818303038152906040528051906020012003613365576003868660405160200161331b93929190615275565b60408051601f19818403018152828201825260068084526530bc32b630b960d11b602085810182905284518086019095529184529083015291975090955061336290610d43565b90505b949592505050565b60007fde9bdca322e1a848f72215bc15cf2c87fe7749145789a9ee281a2a6290af26ab8260405160200161201b92919091825260601b6001600160601b031916602082015260340190565b600060608060006133c885613a9d565b9050600087878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092935050506003198301905061352c576040518060400160405280600681526020016530bc32b630b960d11b81525060405160200161343e9190614aeb565b6040516020818303038152906040528051906020012088886040516020016134679291906148b1565b604051602081830303815290604052805190602001201461349b57604051631f23114d60e31b815260040160405180910390fd5b858060200190518101906134af91906152e7565b6040805180820182526003815262343ab160e91b6020808301919091529151929a509294506134df935001614aeb565b604051602081830303815290604052805190602001206134fe82611ee4565b1461351c57604051631f23114d60e31b815260040160405180910390fd5b61352586613a9d565b91506135b8565b6040518060400160405280600681526020016530bc32b630b960d11b81525060405160200161355b9190614aeb565b6040516020818303038152906040528051906020012088886040516020016135849291906148b1565b60405160208183030381529060405280519060200120036135b857604051631f23114d60e31b815260040160405180910390fd5b9097909650939450505050565b60006135d5878787878787613aca565b90506001600160a01b0381161561363157806001600160a01b0316877f8fe61b2d4701a29265508750790e322b2c214399abdf98472158b8908b660d418888888888604051613628959493929190614a3b565b60405180910390a35b9695505050505050565b60006060600080606080868060200190518101906136599190615358565b939a509198509095509093509150613672905081613944565b9350506001600160a01b0388161561369b5761368f858984613af7565b505050505050506113d5565b60006136a8868585613af7565b8092508194505050836001600160a01b0316868b7fbdb65cfd017af0876344138f62bc895163b5fd120cbe6e666ed306afd658de4b8b898888516000146136f557885160208a01206136f8565b60005b60405161370894939291906153fb565b60405180910390a48151156110a9576040516314920a8160e11b81526000906001600160a01b03861690632924150290613752908e908d908b9089908e908a908d90600401615434565b6020604051808303816000875af1158015613771573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137959190614abe565b90507fe84001f3dedacf7f9ddc370e9f09c26b37473e9e959ffdc4925f6fe33c9877e48114611ad45784604051631ef6f3b360e01b8152600401610a219190613db4565b6000806000806000858060200190518101906137f5919061549c565b9550955095509550955050600061380f8683878787612bbd565b9050610d3a8660008385612d76565b60008060008084806020019051810190613838919061553b565b955095505094509450506000600481111561385557613855614879565b83600481111561386757613867614879565b036138875782604051630a7dda8360e01b8152600401610a2191906148a3565b611780848461389585613944565b84612d76565b6138ae6138a784611fda565b8216821490565b6138cf578281604051631fe9beed60e21b8152600401610a2192919061437f565b6138d98382613c09565b6120d68282613c6b565b60007f2a41fec9a0df4e0996b975f71622c7164b0f652ea69d9dbcd6b24e81b20ab5e587878787878760405160200161392297969594939291906155da565b6040516020818303038152906040528051906020012090509695505050505050565b6000815160141461396a578160405163d08dbec560e01b8152600401610a219190613f2d565b506014015190565b61397e6138a784611fda565b61399f578281604051631fe9beed60e21b8152600401610a2192919061437f565b6139aa838383613cbf565b816001600160a01b0316836001600160a01b03167ff7158d1591c2cf17c0e6b9459d86365c47fe0969c79f40ef49e0c437d8f39914836040516139ef91815260200190565b60405180910390a3505050565b61123d816001613cd4565b61123d7f0e2c162a1f4b5cff9fdbd6b34678a9bcb9898a0b9fbca695b112d61688d8b2ac825b816120d68282615669565b80613a438484613ce4565b14613a7b5760405163018013f960e61b81526001600160a01b0380851660048301528316602482015260448101829052606401610a21565b613a8783836000613cbf565b6120d683838361389b565b61123d816000613d66565b6000602082511015613ac257604051637c6953f960e01b815260040160405180910390fd5b506020015190565b600080613adb8888888888886138e3565b9050805491508115613aec57600081555b509695505050505050565b6000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fb1ea8cf60e01b888888604051602401613b4493929190614b07565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613b829190614aeb565b600060405180830381855af49150503d8060008114613bbd576040519150601f19603f3d011682016040523d82523d6000602084013e613bc2565b606091505b509150915081613be75780604051630f94097360e01b8152600401610a219190613f2d565b80806020019051810190613bfb9190614c89565b909890975095505050505050565b60008119613c1684611fda565b169050613c238382613cfa565b826001600160a01b03167fccf920c8facee98a9c2a6c6124f2857b87b17e9f3a819bfcc6945196ee77366b83604051613c5e91815260200190565b60405180910390a2505050565b600081613c7784611fda565b179050613c848382613cfa565b826001600160a01b03167f34e73c57659d4b6809b53db4feee9b007b892e978114eda420d2991aba15014383604051613c5e91815260200190565b6000613ccb8484613d0d565b91909155505050565b610f0e82600160ff84161b613c6b565b600080613cf18484613d0d565b54949350505050565b6000613d058361336d565b919091555050565b60007ff96e07b2f4fbb81c31567d2b261589af429e98f0958d53f7e6ad5d63aea0ab7c83836040516020016117be93929190928352606091821b6001600160601b03199081166020850152911b16603482015260480190565b508054613d7290614b89565b6000825580601f10613d82575050565b601f01602090049060005260206000209081019061123d91905b80821115613db05760008155600101613d9c565b5090565b6001600160a01b0391909116815260200190565b60008083601f840112613dda57600080fd5b5081356001600160401b03811115613df157600080fd5b60208301915083602082850101111561259857600080fd5b6005811061123d57600080fd5b600080600080600080600080600060c08a8c031215613e3457600080fd5b8935985060208a01356001600160401b03811115613e5157600080fd5b613e5d8c828d01613dc8565b90995097505060408a01356001600160401b03811115613e7c57600080fd5b613e888c828d01613dc8565b90975095505060608a0135613e9c81613e09565b935060808a01356001600160401b03811115613eb757600080fd5b613ec38c828d01613dc8565b9a9d999c50979a9699959894979660a00135949350505050565b60005b83811015613ef8578181015183820152602001613ee0565b50506000910152565b60008151808452613f19816020860160208601613edd565b601f01601f19169290920160200192915050565b60208152600061148e6020830184613f01565b60008083601f840112613f5257600080fd5b5081356001600160401b03811115613f6957600080fd5b6020830191508360208260051b850101111561259857600080fd5b60008060008060408587031215613f9a57600080fd5b84356001600160401b03811115613fb057600080fd5b613fbc87828801613f40565b90955093505060208501356001600160401b03811115613fdb57600080fd5b613fe787828801613f40565b95989497509550505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561403157614031613ff3565b604052919050565b60006001600160401b0382111561405257614052613ff3565b50601f01601f191660200190565b600082601f83011261407157600080fd5b813560208301600061408a61408584614039565b614009565b905082815285838301111561409e57600080fd5b82826020830137600092810160200192909252509392505050565b6000602082840312156140cb57600080fd5b81356001600160401b038111156140e157600080fd5b6140ed84828501614060565b949350505050565b60008060008060008060006080888a03121561411057600080fd5b8735965060208801356001600160401b0381111561412d57600080fd5b6141398a828b01613dc8565b90975095505060408801356001600160401b0381111561415857600080fd5b6141648a828b01613dc8565b90955093505060608801356001600160401b0381111561418357600080fd5b61418f8a828b01613dc8565b989b979a50959850939692959293505050565b6001600160a01b038116811461123d57600080fd5b6000602082840312156141c957600080fd5b813561148e816141a2565b60008060008060008060008060c0898b0312156141f057600080fd5b883597506020890135614202816141a2565b965060408901356001600160401b0381111561421d57600080fd5b6142298b828c01613dc8565b90975095505060608901356001600160401b0381111561424857600080fd5b6142548b828c01614060565b9450506080890135925060a08901356001600160401b0381111561427757600080fd5b6142838b828c01613dc8565b999c989b5096995094979396929594505050565b6000602082840312156142a957600080fd5b5035919050565b600080604083850312156142c357600080fd5b82356142ce816141a2565b946020939093013593505050565b600080600080600080606087890312156142f557600080fd5b86356001600160401b0381111561430b57600080fd5b61431789828a01613dc8565b90975095505060208701356001600160401b0381111561433657600080fd5b61434289828a01613dc8565b90955093505060408701356001600160401b0381111561436157600080fd5b61436d89828a01613dc8565b979a9699509497509295939492505050565b6001600160a01b03929092168252602082015260400190565b60ff8116811461123d57600080fd5b80356143b281614398565b919050565b600080604083850312156143ca57600080fd5b82356143d5816141a2565b915060208301356143e581614398565b809150509250929050565b6000806020838503121561440357600080fd5b82356001600160401b0381111561441957600080fd5b61442585828601613dc8565b90969095509350505050565b6000806040838503121561444457600080fd5b82356001600160401b0381111561445a57600080fd5b61446685828601614060565b92505060208301356001600160401b0381111561448257600080fd5b61448e85828601614060565b9150509250929050565b600080600080606085870312156144ae57600080fd5b84356144b9816141a2565b93506020850135925060408501356001600160401b038111156144db57600080fd5b613fe787828801613dc8565b600080602083850312156144fa57600080fd5b82356001600160401b0381111561451057600080fd5b61442585828601613f40565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b8281101561457557603f19878603018452614560858351613f01565b94506020938401939190910190600101614544565b50929695505050505050565b801515811461123d57600080fd5b6000602082840312156145a157600080fd5b813561148e81614581565b600080600080604085870312156145c257600080fd5b84356001600160401b038111156145d857600080fd5b6145e487828801613dc8565b90955093505060208501356001600160401b038111156144db57600080fd5b6000806000806000806080878903121561461c57600080fd5b8635955060208701356001600160401b0381111561463957600080fd5b61464589828a01613dc8565b90965094505060408701356001600160401b0381111561466457600080fd5b61467089828a01613dc8565b979a9699509497949695606090950135949350505050565b600080600080600080600080600060c08a8c0312156146a657600080fd5b8935985060208a01356001600160401b038111156146c357600080fd5b6146cf8c828d01613dc8565b90995097505060408a01356001600160401b038111156146ee57600080fd5b6146fa8c828d01613dc8565b90975095505060608a0135935060808a01356001600160401b03811115613eb757600080fd5b60008060008060008060008060e0898b03121561473c57600080fd5b8835975060208901356001600160401b0381111561475957600080fd5b6147658b828c01613dc8565b90985096505060408901356001600160401b0381111561478457600080fd5b6147908b828c01614060565b95505060608901356001600160401b038111156147ac57600080fd5b6147b88b828c01614060565b9450506147c760808a016143a7565b925060a08901356001600160401b038111156147e257600080fd5b6147ee8b828c01614060565b989b979a50959894979396929550929360c00135925050565b60008060008060006080868803121561481f57600080fd5b853594506020860135614831816141a2565b9350604086013561484181613e09565b925060608601356001600160401b0381111561485c57600080fd5b61486888828901613dc8565b969995985093965092949392505050565b634e487b7160e01b600052602160045260246000fd5b6005811061489f5761489f614879565b9052565b60208101610d56828461488f565b8183823760009101908152919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6080815260006148fe60808301898b6148c1565b82810360208401526149108189613f01565b905082810360408401526149258187896148c1565b9050828103606084015261493a8185876148c1565b9a9950505050505050505050565b88815287602082015261495e604082018861488f565b60c06060820152600061497460c0830188613f01565b82810360808401526149878187896148c1565b905082810360a084015261499c8185876148c1565b9b9a5050505050505050505050565b6001600160a01b0392909216825260ff16602082015260400190565b634e487b7160e01b600052603260045260246000fd5b8681526080602082015260006149f76080830187896148c1565b8281036040840152614a0a8186886148c1565b915050826060830152979650505050505050565b600060208284031215614a3057600080fd5b815161148e81614581565b606081526000614a4f6060830187896148c1565b8281036020840152614a628186886148c1565b9150508260408301529695505050505050565b600060208284031215614a8757600080fd5b815161148e81614398565b838152606060208201526000614aab6060830185613f01565b905060ff83166040830152949350505050565b600060208284031215614ad057600080fd5b5051919050565b6020815260006140ed6020830184866148c1565b60008251614afd818460208701613edd565b9190910192915050565b9283526001600160a01b03919091166020830152604082015260600190565b6000808335601e19843603018112614b3d57600080fd5b8301803591506001600160401b03821115614b5757600080fd5b60200191503681900382131561259857600080fd5b600060208284031215614b7e57600080fd5b815161148e816141a2565b600181811c90821680614b9d57607f821691505b602082108103614bbd57634e487b7160e01b600052602260045260246000fd5b50919050565b8281526040602082015260006140ed6040830184613f01565b60008060008060008060c08789031215614bf557600080fd5b863595506020870135945060408701356001600160401b03811115614c1957600080fd5b614c2589828a01614060565b94505060608701356001600160401b03811115614c4157600080fd5b614c4d89828a01614060565b9350506080870135915060a08701356001600160401b03811115614c7057600080fd5b614c7c89828a01614060565b9150509295509295509295565b60008060408385031215614c9c57600080fd5b825160208401519092506143e5816141a2565b608081526000614cc36080830187896148c1565b8281036020840152614cd58187613f01565b60408401959095525050606001529392505050565b88815260e060208201526000614d0460e08301898b6148c1565b8281036040840152614d168189613f01565b90508281036060840152614d2a8188613f01565b608084019690965250506001600160a01b039290921660a083015260c09091015295945050505050565b60008085851115614d6457600080fd5b83861115614d7157600080fd5b5050820193919092039150565b80356001600160e01b03198116906004841015614daf576001600160e01b0319600485900360031b81901b82161691505b5092915050565b606081526000614dca6060830186886148c1565b8281036020840152614ddc8186613f01565b91505082604083015295945050505050565b86815285602082015260c060408201526000614e0d60c0830187613f01565b8281036060840152614e1f8187613f01565b905084608084015282810360a0840152614e398185613f01565b9998505050505050505050565b60a081526000614e5960a0830188613f01565b8281036020840152614e6b8188613f01565b90508281036040840152614e7f8187613f01565b91505060028410614e9257614e92614879565b6060820193909352608001529392505050565b600080600080600060a08688031215614ebd57600080fd5b853594506020860135935060408601356001600160401b03811115614ee157600080fd5b614eed88828901614060565b93505060608601356001600160401b03811115614f0957600080fd5b614f1588828901614060565b95989497509295608001359392505050565b600082601f830112614f3857600080fd5b81356001600160401b03811115614f5157614f51613ff3565b8060051b614f6160208201614009565b91825260208185018101929081019086841115614f7d57600080fd5b6020860192505b838310156136315782356001600160401b03811115614fa257600080fd5b614fb1886020838a0101614060565b83525060209283019290910190614f84565b60008060008060808587031215614fd957600080fd5b8435614fe4816141a2565b935060208501356001600160401b03811115614fff57600080fd5b61500b87828801614060565b93505060408501356001600160401b0381111561502757600080fd5b61503387828801614f27565b92505060608501356001600160401b0381111561504f57600080fd5b61505b87828801614f27565b91505092959194509250565b60408152600061507a6040830185613f01565b828103602084015261508c8185613f01565b95945050505050565b86815285602082015260018060a01b038516604082015260c0606082015260006150c260c0830186613f01565b82810360808401526150d48186613f01565b91505060ff831660a0830152979650505050505050565b6001600160a01b038516815260806020820181905260009061510f90830186613f01565b82810360408401526151218186613f01565b91505060ff8316606083015295945050505050565b6040815260006151496040830185613f01565b905060018060a01b03831660208301529392505050565b838152615170602082018461488f565b60606040820152600061508c6060830184613f01565b60408101615194828561488f565b6001600160a01b039290921660209190910152919050565b6001600160a01b03831681526040602082018190526000906140ed90830184613f01565b60a0815260006151e360a0830189613f01565b82810360208401526151f58189613f01565b905060ff8716604084015282810360608401526152128187613f01565b90508281036080840152614e398185876148c1565b86815285602082015260c06040820152600061524660c0830187613f01565b82810360608401526152588187613f01565b905060ff8516608084015282810360a0840152614e398185613f01565b83815260606020820152600061528e6060830185613f01565b82810360408401526136318185613f01565b600082601f8301126152b157600080fd5b81516020830160006152c561408584614039565b90508281528583830111156152d957600080fd5b61508c836020830184613edd565b6000806000606084860312156152fc57600080fd5b835160208501519093506001600160401b0381111561531a57600080fd5b615326868287016152a0565b92505060408401516001600160401b0381111561534257600080fd5b61534e868287016152a0565b9150509250925092565b60008060008060008060c0878903121561537157600080fd5b86516020880151604089015191975095506001600160401b0381111561539657600080fd5b6153a289828a016152a0565b94505060608701516001600160401b038111156153be57600080fd5b6153ca89828a016152a0565b608089015160a08a0151919550935090506001600160401b038111156153ef57600080fd5b614c7c89828a016152a0565b60808152600061540e6080830187613f01565b82810360208401526154208187613f01565b604084019590955250506060015292915050565b87815260e06020820152600061544d60e0830189613f01565b828103604084015261545f8189613f01565b905082810360608401526154738188613f01565b608084019690965250506001600160a01b039290921660a083015260c090910152949350505050565b60008060008060008060c087890312156154b557600080fd5b86516020880151604089015191975095506001600160401b038111156154da57600080fd5b6154e689828a016152a0565b94505060608701516001600160401b0381111561550257600080fd5b61550e89828a016152a0565b935050608087015161551f81614398565b60a08801519092506001600160401b038111156153ef57600080fd5b60008060008060008060c0878903121561555457600080fd5b865160208801516040890151919750955061556e81613e09565b60608801519094506001600160401b0381111561558a57600080fd5b61559689828a016152a0565b93505060808701516001600160401b038111156155b257600080fd5b6155be89828a016152a0565b92505060a08701516001600160401b038111156153ef57600080fd5b87815286602082015260a0604082015260006155fa60a0830187896148c1565b828103606084015261560d8186886148c1565b91505082608083015298975050505050505050565b601f8211156120d657806000526020600020601f840160051c810160208510156156495750805b601f840160051c820191505b818110156117805760008155600101615655565b81516001600160401b0381111561568257615682613ff3565b615696816156908454614b89565b84615622565b6020601f8211600181146156ca57600083156156b25750848201515b600019600385901b1c1916600184901b178455611780565b600084815260208120601f198516915b828110156156fa57878501518255602094850194600190920191016156da565b50848210156157185786840151600019600387901b60f8161c191681555b50505050600190811b0190555056feee35723ac350a69d2a92d3703f17439cbaadf2f093a21ba5bf5f1a53eb2a14d8360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc04ddbfaa222e81ab9447c070310e87608bf6a4c5d42be5c2fdf0f370b186af799855384122b55936fbfb8ca5120e63c6537a1ac40caf6ae33502b3c5da8c87d1608060405234801561001057600080fd5b50610162806100206000396000f3fe60806040526004361061001d5760003560e01c806277436014610022575b600080fd5b61003561003036600461007b565b610037565b005b8051602082016000f061004957600080fd5b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561008d57600080fd5b813567ffffffffffffffff808211156100a557600080fd5b818401915084601f8301126100b957600080fd5b8135818111156100cb576100cb61004c565b604051601f8201601f19908116603f011681019083821181831017156100f3576100f361004c565b8160405282815287602084870101111561010c57600080fd5b82602086016020830137600092810160200192909252509594505050505056fea264697066735822122094780ce55d28f1d568f4e0ab1b9dc230b96e952b73d2e06456fbff2289fa27f464736f6c63430008150033a2646970667358221220a42e4ec55ccace331728af82aa9182b763f2aef8d6c325aa9acc21ae9da968b064736f6c634300081b0033000000000000000000000000e50a35500805b555a8318bdb98e542fb50dd6e080000000000000000000000004c555f2e0c69ac02747986ce5f6a14e2bce44f13000000000000000000000000e432150cce91c13a887f7d836923d5597add8e310000000000000000000000002d5d7d31f671f86c782533cc367f14109a08271200000000000000000000000083a93500d23fbc3e82b410ad07a6a9f7a0670d6600000000000000000000000000000000000000000000000000000000000001200000000000000000000000009d3583cbeb5542287b635bf09d693c8106284c27000000000000000000000000cc360c322f72a89e5247f3875a02c214f31da035000000000000000000000000994014b7f3e5ac898aad533b10534b69d65dd6de00000000000000000000000000000000000000000000000000000000000000076672617874616c00000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106102a95760003560e01c806383d2969611610165578063c7e6a3cc116100cc578063e30c397811610085578063e30c3978146108ce578063e82e71f8146108f0578063f2fde38b14610910578063f49c044a14610930578063f6e3a22914610943578063f8c8a82614610963578063ffd5982a1461098357600080fd5b8063c7e6a3cc14610814578063ca58b64414610834578063da081c7314610868578063da4886df1461087b578063dc88dfd11461089b578063e1d40c77146108bb57600080fd5b8063a3499c731161011e578063a3499c7314610754578063a5269ef114610774578063ac9650d814610794578063b90d6afd146107b4578063c38bb537146107d4578063c506bff4146107f457600080fd5b806383d296961461067d578063864a0dcf146106ab5780638da5cb5b146106df57806395a8c58d146106f45780639ded06df146107145780639f409d771461073457600080fd5b80635c975abb1161021457806370756cde116101cd57806370756cde1461058f578063710bf322146105a257806379ba5097146105c25780637e10eb15146105d75780637e151fa6146105f75780637fb53dc9146106375780638291286c1461064a57600080fd5b80635c975abb146104af57806365657636146104d45780636a22d8cc146104e75780636ac0d1121461051b5780636d70f7ae1461054f5780636f3eef621461056f57600080fd5b8063465a09e011610266578063465a09e0146103d7578063477aedc7146103f957806349160658146104195780634a6a42d8146104395780634f9ae608146104595780635c60da1b1461048d57600080fd5b80630af20483146102ae5780630f4433d3146102f8578063116191b6146103195780631b3d6e871461034d5780631c93b03a146103815780632a709b14146103a3575b600080fd5b3480156102ba57600080fd5b506102e27f000000000000000000000000994014b7f3e5ac898aad533b10534b69d65dd6de81565b6040516102ef9190613db4565b60405180910390f35b61030b610306366004613e16565b6109a3565b6040519081526020016102ef565b34801561032557600080fd5b506102e27f000000000000000000000000e432150cce91c13a887f7d836923d5597add8e3181565b34801561035957600080fd5b506102e27f000000000000000000000000cc360c322f72a89e5247f3875a02c214f31da03581565b34801561038d57600080fd5b50610396610bfc565b6040516102ef9190613f2d565b3480156103af57600080fd5b506102e27f0000000000000000000000009d3583cbeb5542287b635bf09d693c8106284c2781565b3480156103e357600080fd5b506103f76103f2366004613f84565b610c2c565b005b34801561040557600080fd5b506103966104143660046140b9565b610d43565b34801561042557600080fd5b506103f76104343660046140f5565b610d5c565b34801561044557600080fd5b506103f76104543660046141b7565b610ed3565b34801561046557600080fd5b506102e27f0000000000000000000000004c555f2e0c69ac02747986ce5f6a14e2bce44f1381565b34801561049957600080fd5b50600080516020615748833981519152546102e2565b3480156104bb57600080fd5b506104c4610f12565b60405190151581526020016102ef565b6103f76104e23660046140f5565b610f25565b3480156104f357600080fd5b506102e27f0000000000000000000000002d5d7d31f671f86c782533cc367f14109a08271281565b34801561052757600080fd5b506102e27f000000000000000000000000e50a35500805b555a8318bdb98e542fb50dd6e0881565b34801561055b57600080fd5b506104c461056a3660046141b7565b6110b5565b34801561057b57600080fd5b506103f761058a3660046141b7565b6110c2565b6103f761059d3660046141d4565b6110fd565b3480156105ae57600080fd5b506103f76105bd3660046141b7565b611154565b3480156105ce57600080fd5b506103f76111f1565b3480156105e357600080fd5b506102e26105f2366004614297565b611240565b34801561060357600080fd5b506102e2610612366004614297565b507f0000000000000000000000009d3583cbeb5542287b635bf09d693c8106284c2790565b6103f76106453660046142b0565b61127c565b34801561065657600080fd5b507ff407da03daa7b4243ffb261daad9b01d221ea90ab941948cd48101563654ea8661030b565b34801561068957600080fd5b5061069d6106983660046142dc565b6113db565b6040516102ef92919061437f565b3480156106b757600080fd5b5061030b7f39520897016aaf0ab8e5bf7b0c72c0875359483112298e4b64220a3abfb31c1a81565b3480156106eb57600080fd5b506102e261144e565b34801561070057600080fd5b506104c461070f3660046143b7565b611473565b34801561072057600080fd5b506103f761072f3660046143f0565b611495565b34801561074057600080fd5b506103f761074f366004614431565b6114e8565b34801561076057600080fd5b506103f761076f366004614498565b611522565b34801561078057600080fd5b5061030b61078f3660046142b0565b611787565b6107a76107a23660046144e7565b6117dc565b6040516102ef919061451c565b3480156107c057600080fd5b506102e26107cf366004614297565b611912565b3480156107e057600080fd5b506103f76107ef36600461458f565b61197e565b34801561080057600080fd5b506104c461080f3660046145ac565b6119c4565b34801561082057600080fd5b506102e261082f366004614603565b611a2a565b34801561084057600080fd5b506102e27f00000000000000000000000083a93500d23fbc3e82b410ad07a6a9f7a0670d6681565b6103f7610876366004614688565b611a45565b34801561088757600080fd5b506103f76108963660046141b7565b611ae1565b3480156108a757600080fd5b506103f76108b63660046140b9565b611aed565b61030b6108c9366004614720565b611b26565b3480156108da57600080fd5b50600080516020615788833981519152546102e2565b3480156108fc57600080fd5b506102e261090b366004614297565b611c6e565b34801561091c57600080fd5b506103f761092b3660046141b7565b611c84565b61030b61093e366004614807565b611cb4565b34801561094f57600080fd5b506103f761095e366004614297565b611ddb565b34801561096f57600080fd5b506102e261097e366004614297565b611ed9565b34801561098f57600080fd5b5061030b61099e3660046140b9565b611ee4565b60006109ad610f12565b156109cb576040516334c2d01160e11b815260040160405180910390fd5b60008690036109ed5760405163c6f4c06f60e01b815260040160405180910390fd5b6000856004811115610a0157610a01614879565b03610a2a5784604051630a7dda8360e01b8152600401610a2191906148a3565b60405180910390fd5b6000889003610a4c57604051630280e1e560e61b815260040160405180910390fd5b8888604051610a5c9291906148b1565b60405180910390207f39520897016aaf0ab8e5bf7b0c72c0875359483112298e4b64220a3abfb31c1a03610aa357604051633a6aed5960e21b815260040160405180910390fd5b336001600160a01b037f00000000000000000000000083a93500d23fbc3e82b410ad07a6a9f7a0670d66168103610ad8575060005b610ae2818c611787565b91508a816001600160a01b03168360008051602061576883398151915260405160405180910390a46000610b26610b1884611912565b6001600160a01b0316611ef8565b9050866004811115610b3a57610b3a614879565b837f6d8eb6e760238fe99c48de1a8bec4365cbeead2dbe47669c989722eaaa64a8478d8d858e8e8d8d604051610b7697969594939291906148ea565b60405180910390a3600060058489848d8d8c8c604051602001610ba0989796959493929190614948565b60408051601f198184030181526020601f8f018190048102840181019092528d83529250610bec91908e908e908190840183828082843760009201829052508693509150899050611f26565b5050509998505050505050505050565b6060610c277f0e2c162a1f4b5cff9fdbd6b34678a9bcb9898a0b9fbca695b112d61688d8b2ac611f47565b905090565b6001610c47610c3a33611fda565b600160ff84161b16151590565b610c6857338160405163bb6c163960e01b8152600401610a219291906149ab565b83828114610c8c576040516001621398b960e31b0319815260040160405180910390fd5b60005b81811015610d3a57610cb8878783818110610cac57610cac6149c7565b90506020020135611240565b6001600160a01b031663a56dbe63868684818110610cd857610cd86149c7565b905060200201356040518263ffffffff1660e01b8152600401610cfd91815260200190565b600060405180830381600087803b158015610d1757600080fd5b505af1158015610d2b573d6000803e3d6000fd5b50505050806001019050610c8f565b50505050505050565b6060610d56610d5183611fe6565b611f47565b92915050565b85858585610d6c848484846119c4565b610d895760405163157e5fbf60e21b815260040160405180910390fd5b610d91610f12565b15610daf576040516334c2d01160e11b815260040160405180910390fd5b60008686604051610dc19291906148b1565b604051908190038120635f6970c360e01b825291506001600160a01b037f000000000000000000000000e432150cce91c13a887f7d836923d5597add8e311690635f6970c390610e1f908f908f908f908f908f9089906004016149dd565b6020604051808303816000875af1158015610e3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e629190614a1e565b610e7f57604051631403112d60e21b815260040160405180910390fd5b610ec58c8c8c8c8c8c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a9250612038915050565b505050505050505050505050565b6001610ee1610c3a33611fda565b610f0257338160405163bb6c163960e01b8152600401610a219291906149ab565b610f0e338360016120c5565b5050565b6000805160206157288339815191525490565b610f2d610f12565b15610f4b576040516334c2d01160e11b815260040160405180910390fd5b6000610f5982840184614297565b90508015610f7d5760405163e94617f560e01b815260048101829052602401610a21565b604051630d26ff2160e41b8152600481018990527f000000000000000000000000e432150cce91c13a887f7d836923d5597add8e316001600160a01b03169063d26ff21090602401602060405180830381865afa158015610fe2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110069190614a1e565b1561102457604051630dc1019760e01b815260040160405180910390fd5b604051339060009061103990869086906148b1565b60405180910390209050816001600160a01b03168a7f6e18757e81c44a367109cbaa499add16f2ae7168aab9715c3cdc36b0f7ccce928b8b8b8b87604051611085959493929190614a3b565b60405180910390a361109c8a8a8a8a8a86886120db565b6110a98a8a8a8888612122565b50505050505050505050565b6000610d56826001611473565b60016110d0610c3a33611fda565b6110f157338160405163bb6c163960e01b8152600401610a219291906149ab565b610f0e33836001612397565b611105610f12565b15611123576040516334c2d01160e11b815260040160405180910390fd5b61113088888560016123a8565b925060008061113f84846124cc565b915091506110a98a8a8a8a8a8a88883461259f565b3361115d61144e565b6001600160a01b031614611184576040516330cd747160e01b815260040160405180910390fd5b6001600160a01b0381166111ab57604051633649397d60e21b815260040160405180910390fd5b6040516001600160a01b038216907fd9be0e8e07417e00f2521db636cb53e316fd288f5051f16d2aa2bf0c3938a87690600090a260008051602061578883398151915255565b60006112096000805160206157888339815191525490565b90506001600160a01b0381163314611234576040516349e27cff60e01b815260040160405180910390fd5b61123d816126bc565b50565b60008061124c83611ed9565b9050806001600160a01b03163b600003610d5657604051630b7616bf60e21b815260048101849052602401610a21565b6001600160a01b0382166112a35760405163c6f4c06f60e01b815260040160405180910390fd5b6000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113079190614a75565b90506000600661131f856001600160a01b0316611ef8565b8360405160200161133293929190614a92565b60408051601f198184030181529082905260ff8416825291506001600160a01b038516907f58480fc929990fed6b4f0f83c65bc9ee9a9025d9fa483749504587acdc6916fa9060200160405180910390a26113d56040518060400160405280600681526020016530bc32b630b960d11b8152506113cc6040518060400160405280600681526020016530bc32b630b960d11b815250610d43565b8360008761274d565b50505050565b600080878787876113ee848484846119c4565b61140b5760405163157e5fbf60e21b815260040160405180910390fd5b611413610f12565b15611431576040516334c2d01160e11b815260040160405180910390fd5b61143b8888612860565b9550955050505050965096945050505050565b7f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c05490565b600061148e61148184611fda565b600160ff85161b16151590565b9392505050565b307f000000000000000000000000d4b79294cd4b1f3c0781da83b846c7558d9ee9216001600160a01b0316036114de57604051635f886e9d60e11b815260040160405180910390fd5b610f0e82826128b3565b336114f161144e565b6001600160a01b031614611518576040516330cd747160e01b815260040160405180910390fd5b610f0e82826129d8565b3361152b61144e565b6001600160a01b031614611552576040516330cd747160e01b815260040160405180910390fd5b600080516020615748833981519152546001600160a01b0316638291286c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561159f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c39190614abe565b846001600160a01b0316638291286c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611601573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116259190614abe565b146116435760405163340aafcd60e11b815260040160405180910390fd5b836001600160a01b03163f831461166d576040516323e13ec960e21b815260040160405180910390fd5b6000805160206157488339815191528490556040516001600160a01b038516907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a280156113d5576000846001600160a01b0316639ded06df60e01b84846040516024016116e0929190614ad7565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161171e9190614aeb565b600060405180830381855af49150503d8060008114611759576040519150601f19603f3d011682016040523d82523d6000602084013e61175e565b606091505b5050905080611780576040516397905dfb60e01b815260040160405180910390fd5b5050505050565b60007f980c3be34c7ee75cc250c76223092614e21653cdf2faece10ac24fcef821df1083836040516020016117be93929190614b07565b60405160208183030381529060405280519060200120905092915050565b6060816001600160401b038111156117f6576117f6613ff3565b60405190808252806020026020018201604052801561182957816020015b60608152602001906001900390816118145790505b5090506000606060005b84811015611909573086868381811061184e5761184e6149c7565b90506020028101906118609190614b26565b60405161186e9291906148b1565b600060405180830381855af49150503d80600081146118a9576040519150601f19603f3d011682016040523d82523d6000602084013e6118ae565b606091505b509093509150826118e35781516000036118db576040516309ad446560e31b815260040160405180910390fd5b815182602001fd5b818482815181106118f6576118f66149c7565b6020908102919091010152600101611833565b50505092915050565b600061191d82611240565b6001600160a01b0316639d76ea586040518163ffffffff1660e01b8152600401602060405180830381865afa15801561195a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d569190614b6c565b3361198761144e565b6001600160a01b0316146119ae576040516330cd747160e01b815260040160405180910390fd5b80156119bc5761123d612a87565b61123d612acb565b60008083836040516119d79291906148b1565b60405180910390209050611a2086868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611ee492505050565b1495945050505050565b6000611a3a878787878787612b0f565b979650505050505050565b611a4d610f12565b15611a6b576040516334c2d01160e11b815260040160405180910390fd5b611a7889338660006123a8565b9350600080611a8785856124cc565b91509150611ad48b338c8c8c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508e92508a91508990508b61259f565b5050505050505050505050565b61123d81336001612b2d565b33611af661144e565b6001600160a01b031614611b1d576040516330cd747160e01b815260040160405180910390fd5b61123d81612b3e565b6000611b30610f12565b15611b4e576040516334c2d01160e11b815260040160405180910390fd5b336001600160a01b037f00000000000000000000000083a93500d23fbc3e82b410ad07a6a9f7a0670d661614611b995733604051630b160a0560e11b8152600401610a219190613db4565b6000611ba5818b611787565b915089816001600160a01b03168360008051602061576883398151915260405160405180910390a46000889003611bfa576000611be583868a8a8a612bbd565b9050611bf48360008388612d76565b50611c61565b8888604051611c0a9291906148b1565b60405180910390207f39520897016aaf0ab8e5bf7b0c72c0875359483112298e4b64220a3abfb31c1a03611c5157604051633a6aed5960e21b815260040160405180910390fd5b611c6182888888888e8e8a612fcf565b5098975050505050505050565b6000611c79826130c9565b9150610d5682613104565b33611c8d61144e565b6001600160a01b031614611234576040516330cd747160e01b815260040160405180910390fd5b6000611cbe610f12565b15611cdc576040516334c2d01160e11b815260040160405180910390fd5b336001600160a01b037f00000000000000000000000083a93500d23fbc3e82b410ad07a6a9f7a0670d661614611d275733604051630b160a0560e11b8152600401610a219190613db4565b6000846004811115611d3b57611d3b614879565b03611d5b5783604051630a7dda8360e01b8152600401610a2191906148a3565b6000611d678188611787565b915086816001600160a01b03168360008051602061576883398151915260405160405180910390a4611dd182868887878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612d7692505050565b5095945050505050565b33611de461144e565b6001600160a01b031614611e0b576040516330cd747160e01b815260040160405180910390fd5b6000611e1682611240565b90506000816001600160a01b0316639d76ea586040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e7c9190614b6c565b6040516367c354ad60e11b81529091506001600160a01b0382169063cf86a95a90611eab908590600401613db4565b600060405180830381600087803b158015611ec557600080fd5b505af1158015610d3a573d6000803e3d6000fd5b6000610d5682613104565b600080611ef0836131c6565b549392505050565b6040805160148082528183019092526060916020820181803683375050506014808201939093529182525090565b6060611f3285856131fb565b9196509094509050611780858286868661274d565b6060818054611f5590614b89565b80601f0160208091040260200160405190810160405280929190818152602001828054611f8190614b89565b8015611fce5780601f10611fa357610100808354040283529160200191611fce565b820191906000526020600020905b815481529060010190602001808311611fb157829003601f168201915b50505050509050919050565b600080611ef08361336d565b60007fa5b4aa1bcb538076d57d083e3004c6907e2eba42d84c21922d441967a02b472f8260405160200161201b929190614bc3565b604051602081830303815290604052805190602001209050919050565b600060606120478888866133b8565b95509092509050816120775760006120638a8a8a8a8a896135c5565b90506120718a82848861363b565b506120ba565b6001820361208d57612088846137d9565b6120ba565b6005820361209e576120888461381e565b6040516324af919760e11b815260048101839052602401610a21565b505050505050505050565b6120d68383600160ff85161b61389b565b505050565b60006120eb8888888888886138e3565b80549091506001600160a01b038116156121185760405163725f13f160e01b815260040160405180910390fd5b5055505050505050565b60008080808061213486880188614bdc565b9550955095509550955050600061214a84613944565b60408051602481018990523360448201526001600160a01b03838116606483015260848083018890528351808403909101815260a490920183526020820180516001600160e01b031663041eebc160e31b1790529151929350600092839283927f000000000000000000000000cc360c322f72a89e5247f3875a02c214f31da035909116916121d99190614aeb565b600060405180830381855af49150503d8060008114612214576040519150601f19603f3d011682016040523d82523d6000602084013e612219565b606091505b50915091508161223e5780604051633a5cf90560e01b8152600401610a219190613f2d565b808060200190518101906122529190614c89565b80945081975050505050816001600160a01b0316878d7fbdb65cfd017af0876344138f62bc895163b5fd120cbe6e666ed306afd658de4b8e8e8b8a8a516000146122a2578a5160208c01206122a5565b60005b6040516122b6959493929190614caf565b60405180910390a4825115610ec5576000826001600160a01b03166377c790258e8e8e8b898e898d6040518963ffffffff1660e01b8152600401612301989796959493929190614cea565b6020604051808303816000875af1158015612320573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123449190614abe565b90507f692b2deb10f974787eb65450ba9a90dc0bb28141a633fa3fb556d5292fba42e18114612388578260405163c646a62360e01b8152600401610a219190613db4565b50505050505050505050505050565b6120d68383600160ff85161b613972565b60008060007f000000000000000000000000cc360c322f72a89e5247f3875a02c214f31da0356001600160a01b031663ea52548360e01b88868989604051602401612415949392919093845291151560208401526001600160a01b03166040830152606082015260800190565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516124539190614aeb565b600060405180830381855af49150503d806000811461248e576040519150601f19603f3d011682016040523d82523d6000602084013e612493565b606091505b5091509150816124b85780604051631a59c9bd60e01b8152600401610a219190613f2d565b80806020019051810190611a3a9190614abe565b6000606060048310156124e25760009150612598565b60006124f16004828688614d54565b6124fa91614d7e565b60e01c905060018111156125295760405163b47a9b4b60e01b815263ffffffff82166004820152602401610a21565b8063ffffffff16600181111561254157612541614879565b925060048490036125525750612598565b61255f8460048188614d54565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929450505050505b9250929050565b84516000036125c15760405163d0639b6560e01b815260040160405180910390fd5b836000036125e257604051631f2a200560e01b815260040160405180910390fd5b8151156125f557815160208301206125f8565b60005b886001600160a01b03168a7fcd05f5b9dc4bb03babf40f5da98f5f46819846207d916f89b67d36fd1f7fd74f8a8a8a8a6040516126389493929190614db6565b60405180910390a46000808a6126568b6001600160a01b0316611ef8565b88888760405160200161266e96959493929190614dee565b60408051601f198184030181526020601f8b0181900481028401810190925289835292506110a991908a908a9081908401838280828437600092019190915250859250889150869050611f26565b6001600160a01b0381166126e357604051633649397d60e21b815260040160405180910390fd5b6040516001600160a01b038216907f04dba622d284ed0014ee4b9a6a68386be1a4c08a4913ae272de89199cc68616390600090a27f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c055600060008051602061578883398151915255565b835160000361276f57604051631f23114d60e31b815260040160405180910390fd5b6000807f000000000000000000000000994014b7f3e5ac898aad533b10534b69d65dd6de6001600160a01b031663bbf4f1bd60e01b88888888886040516024016127bd959493929190614e46565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516127fb9190614aeb565b600060405180830381855af49150503d8060008114612836576040519150601f19603f3d011682016040523d82523d6000602084013e61283b565b606091505b509150915081610d3a5780604051637f32207b60e11b8152600401610a219190613f2d565b60008080808061287286880188614ea5565b94505050925092506000831461289e5760405163e94617f560e01b815260048101849052602401610a21565b6128a782611912565b97909650945050505050565b60008080806128c485870187614fc3565b8151939750919550935091506001600160a01b0385166128f75760405163d92e233d60e01b815260040160405180910390fd5b8351158061292b5750835160208501207f39520897016aaf0ab8e5bf7b0c72c0875359483112298e4b64220a3abfb31c1a14155b1561294957604051630470832760e11b815260040160405180910390fd5b8151811461296d576040516001621398b960e31b0319815260040160405180910390fd5b612976856139fc565b61297f84613a07565b60005b818110156129ce576129c684828151811061299f5761299f6149c7565b60200260200101518483815181106129b9576129b96149c7565b60200260200101516129d8565b600101612982565b5050505050505050565b81516000036129fa5760405163deba168960e01b815260040160405180910390fd5b8051600003612a1c5760405163deba168960e01b815260040160405180910390fd5b612a2e612a2883611fe6565b82613a2d565b6000612a39836131c6565b82516020840120808255604051919250907fdb6b260ea45f7fe513e1d3b8c21017a29e3a41610e95aefb8862b81c69aec61c90612a799086908690615067565b60405180910390a150505050565b612a9e600160008051602061572883398151915255565b60405133907f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890600090a2565b612ae2600060008051602061572883398151915255565b60405133907f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa90600090a2565b600080612b208888888888886138e3565b5498975050505050505050565b6120d68383600160ff85161b613a38565b8051600003612b605760405163deba168960e01b815260040160405180910390fd5b612b71612b6c82611fe6565b613a92565b6000612b7c826131c6565b9050600081557ff9400637a329865492b8d0d4dba4eafc7e8d5d0fae5e27b56766816d2ae1b2ca82604051612bb19190613f2d565b60405180910390a15050565b60008351600003612be15760405163e2592aed60e01b815260040160405180910390fd5b8251600003612c0357604051630ce3838560e11b815260040160405180910390fd5b6000612c0e876130c9565b905060008651600014612c2757612c2487613944565b90505b6000807f0000000000000000000000004c555f2e0c69ac02747986ce5f6a14e2bce44f136001600160a01b031663f575f35b60e01b858c868c8c8c604051602401612c7796959493929190615095565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612cb59190614aeb565b600060405180830381855af49150503d8060008114612cf0576040519150601f19603f3d011682016040523d82523d6000602084013e612cf5565b606091505b509150915081612d1a578060405163c226af8b60e01b8152600401610a219190613f2d565b60208101519450826001600160a01b03168a7ff0d7beb2b03d35e597f432391dc2a6f6eb1a621be6cb5b325f55a49090085239878b8b8b604051612d6194939291906150eb565b60405180910390a35050505095945050505050565b60008183604051602001612d8b929190615136565b60405160208183030381529060405290506000807f000000000000000000000000e50a35500805b555a8318bdb98e542fb50dd6e086001600160a01b0316636519d04b60e01b888886604051602401612de693929190615160565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612e249190614aeb565b600060405180830381855af49150503d8060008114612e5f576040519150601f19603f3d011682016040523d82523d6000602084013e612e64565b606091505b509150915081612e895780604051637cf77c1560e11b8152600401610a219190613f2d565b60208101516040516001600160a01b037f000000000000000000000000cc360c322f72a89e5247f3875a02c214f31da035169063dbd15f2f60e01b90612ed5908a908590602401615186565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612f139190614aeb565b600060405180830381855af49150503d8060008114612f4e576040519150601f19603f3d011682016040523d82523d6000602084013e612f53565b606091505b50909350915082612f795781604051631b559efb60e21b8152600401610a219190613f2d565b866004811115612f8b57612f8b614879565b887f5284c2478b9c1a55e973429331078be39b5fb3eeb9d87d10b34d65a4c89ee4eb8387604051612fbd9291906151ac565b60405180910390a35050505050505050565b8651600003612ff15760405163e2592aed60e01b815260040160405180910390fd5b855160000361301357604051630ce3838560e11b815260040160405180910390fd5b61301c88611240565b50877fe470f4bdd33c8676127d3c20ff725d8dc1605609001389ce3a59c28b54b7992f888888888888604051613057969594939291906151d0565b60405180910390a260006001898989898960405160200161307d96959493929190615227565b60408051601f198184030181526020601f870181900481028401810190925285835292506120ba9190869086908190840183828082843760009201829052508693509150869050611f26565b604080517f610507e221586f499adb972fbdbe7f0619bdae0112c78ebaa562448d0ca7071f602082015290810182905260009060600161201b565b6000803083604051806101c0016040528061018281526020016157a86101829139805160209182012060405161316a949392016001600160f81b0319815260609390931b6001600160601b03191660018401526015830191909152603582015260550190565b60408051601f1981840301815282825280516020918201206135a560f21b8285015260601b6001600160601b0319166022840152600160f81b603684015281516017818503018152603790930190915281519101209392505050565b60007f5f58fea7d48d37d5d1cc2546dfcc3d3cbfe8d758d5ca19c44087f52e15a105058260405160200161201b929190614bc3565b6060806060600061320b86610d43565b90506040518060400160405280600681526020016530bc32b630b960d11b81525060405160200161323c9190614aeb565b60405160208183030381529060405280519060200120866040516020016132639190614aeb565b604051602081830303815290604052805190602001200361329757604051631f23114d60e31b815260040160405180910390fd5b60405180604001604052806003815260200162343ab160e91b8152506040516020016132c39190614aeb565b60405160208183030381529060405280519060200120816040516020016132ea9190614aeb565b6040516020818303038152906040528051906020012003613365576003868660405160200161331b93929190615275565b60408051601f19818403018152828201825260068084526530bc32b630b960d11b602085810182905284518086019095529184529083015291975090955061336290610d43565b90505b949592505050565b60007fde9bdca322e1a848f72215bc15cf2c87fe7749145789a9ee281a2a6290af26ab8260405160200161201b92919091825260601b6001600160601b031916602082015260340190565b600060608060006133c885613a9d565b9050600087878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092935050506003198301905061352c576040518060400160405280600681526020016530bc32b630b960d11b81525060405160200161343e9190614aeb565b6040516020818303038152906040528051906020012088886040516020016134679291906148b1565b604051602081830303815290604052805190602001201461349b57604051631f23114d60e31b815260040160405180910390fd5b858060200190518101906134af91906152e7565b6040805180820182526003815262343ab160e91b6020808301919091529151929a509294506134df935001614aeb565b604051602081830303815290604052805190602001206134fe82611ee4565b1461351c57604051631f23114d60e31b815260040160405180910390fd5b61352586613a9d565b91506135b8565b6040518060400160405280600681526020016530bc32b630b960d11b81525060405160200161355b9190614aeb565b6040516020818303038152906040528051906020012088886040516020016135849291906148b1565b60405160208183030381529060405280519060200120036135b857604051631f23114d60e31b815260040160405180910390fd5b9097909650939450505050565b60006135d5878787878787613aca565b90506001600160a01b0381161561363157806001600160a01b0316877f8fe61b2d4701a29265508750790e322b2c214399abdf98472158b8908b660d418888888888604051613628959493929190614a3b565b60405180910390a35b9695505050505050565b60006060600080606080868060200190518101906136599190615358565b939a509198509095509093509150613672905081613944565b9350506001600160a01b0388161561369b5761368f858984613af7565b505050505050506113d5565b60006136a8868585613af7565b8092508194505050836001600160a01b0316868b7fbdb65cfd017af0876344138f62bc895163b5fd120cbe6e666ed306afd658de4b8b898888516000146136f557885160208a01206136f8565b60005b60405161370894939291906153fb565b60405180910390a48151156110a9576040516314920a8160e11b81526000906001600160a01b03861690632924150290613752908e908d908b9089908e908a908d90600401615434565b6020604051808303816000875af1158015613771573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137959190614abe565b90507fe84001f3dedacf7f9ddc370e9f09c26b37473e9e959ffdc4925f6fe33c9877e48114611ad45784604051631ef6f3b360e01b8152600401610a219190613db4565b6000806000806000858060200190518101906137f5919061549c565b9550955095509550955050600061380f8683878787612bbd565b9050610d3a8660008385612d76565b60008060008084806020019051810190613838919061553b565b955095505094509450506000600481111561385557613855614879565b83600481111561386757613867614879565b036138875782604051630a7dda8360e01b8152600401610a2191906148a3565b611780848461389585613944565b84612d76565b6138ae6138a784611fda565b8216821490565b6138cf578281604051631fe9beed60e21b8152600401610a2192919061437f565b6138d98382613c09565b6120d68282613c6b565b60007f2a41fec9a0df4e0996b975f71622c7164b0f652ea69d9dbcd6b24e81b20ab5e587878787878760405160200161392297969594939291906155da565b6040516020818303038152906040528051906020012090509695505050505050565b6000815160141461396a578160405163d08dbec560e01b8152600401610a219190613f2d565b506014015190565b61397e6138a784611fda565b61399f578281604051631fe9beed60e21b8152600401610a2192919061437f565b6139aa838383613cbf565b816001600160a01b0316836001600160a01b03167ff7158d1591c2cf17c0e6b9459d86365c47fe0969c79f40ef49e0c437d8f39914836040516139ef91815260200190565b60405180910390a3505050565b61123d816001613cd4565b61123d7f0e2c162a1f4b5cff9fdbd6b34678a9bcb9898a0b9fbca695b112d61688d8b2ac825b816120d68282615669565b80613a438484613ce4565b14613a7b5760405163018013f960e61b81526001600160a01b0380851660048301528316602482015260448101829052606401610a21565b613a8783836000613cbf565b6120d683838361389b565b61123d816000613d66565b6000602082511015613ac257604051637c6953f960e01b815260040160405180910390fd5b506020015190565b600080613adb8888888888886138e3565b9050805491508115613aec57600081555b509695505050505050565b6000806000807f000000000000000000000000cc360c322f72a89e5247f3875a02c214f31da0356001600160a01b031663fb1ea8cf60e01b888888604051602401613b4493929190614b07565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613b829190614aeb565b600060405180830381855af49150503d8060008114613bbd576040519150601f19603f3d011682016040523d82523d6000602084013e613bc2565b606091505b509150915081613be75780604051630f94097360e01b8152600401610a219190613f2d565b80806020019051810190613bfb9190614c89565b909890975095505050505050565b60008119613c1684611fda565b169050613c238382613cfa565b826001600160a01b03167fccf920c8facee98a9c2a6c6124f2857b87b17e9f3a819bfcc6945196ee77366b83604051613c5e91815260200190565b60405180910390a2505050565b600081613c7784611fda565b179050613c848382613cfa565b826001600160a01b03167f34e73c57659d4b6809b53db4feee9b007b892e978114eda420d2991aba15014383604051613c5e91815260200190565b6000613ccb8484613d0d565b91909155505050565b610f0e82600160ff84161b613c6b565b600080613cf18484613d0d565b54949350505050565b6000613d058361336d565b919091555050565b60007ff96e07b2f4fbb81c31567d2b261589af429e98f0958d53f7e6ad5d63aea0ab7c83836040516020016117be93929190928352606091821b6001600160601b03199081166020850152911b16603482015260480190565b508054613d7290614b89565b6000825580601f10613d82575050565b601f01602090049060005260206000209081019061123d91905b80821115613db05760008155600101613d9c565b5090565b6001600160a01b0391909116815260200190565b60008083601f840112613dda57600080fd5b5081356001600160401b03811115613df157600080fd5b60208301915083602082850101111561259857600080fd5b6005811061123d57600080fd5b600080600080600080600080600060c08a8c031215613e3457600080fd5b8935985060208a01356001600160401b03811115613e5157600080fd5b613e5d8c828d01613dc8565b90995097505060408a01356001600160401b03811115613e7c57600080fd5b613e888c828d01613dc8565b90975095505060608a0135613e9c81613e09565b935060808a01356001600160401b03811115613eb757600080fd5b613ec38c828d01613dc8565b9a9d999c50979a9699959894979660a00135949350505050565b60005b83811015613ef8578181015183820152602001613ee0565b50506000910152565b60008151808452613f19816020860160208601613edd565b601f01601f19169290920160200192915050565b60208152600061148e6020830184613f01565b60008083601f840112613f5257600080fd5b5081356001600160401b03811115613f6957600080fd5b6020830191508360208260051b850101111561259857600080fd5b60008060008060408587031215613f9a57600080fd5b84356001600160401b03811115613fb057600080fd5b613fbc87828801613f40565b90955093505060208501356001600160401b03811115613fdb57600080fd5b613fe787828801613f40565b95989497509550505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561403157614031613ff3565b604052919050565b60006001600160401b0382111561405257614052613ff3565b50601f01601f191660200190565b600082601f83011261407157600080fd5b813560208301600061408a61408584614039565b614009565b905082815285838301111561409e57600080fd5b82826020830137600092810160200192909252509392505050565b6000602082840312156140cb57600080fd5b81356001600160401b038111156140e157600080fd5b6140ed84828501614060565b949350505050565b60008060008060008060006080888a03121561411057600080fd5b8735965060208801356001600160401b0381111561412d57600080fd5b6141398a828b01613dc8565b90975095505060408801356001600160401b0381111561415857600080fd5b6141648a828b01613dc8565b90955093505060608801356001600160401b0381111561418357600080fd5b61418f8a828b01613dc8565b989b979a50959850939692959293505050565b6001600160a01b038116811461123d57600080fd5b6000602082840312156141c957600080fd5b813561148e816141a2565b60008060008060008060008060c0898b0312156141f057600080fd5b883597506020890135614202816141a2565b965060408901356001600160401b0381111561421d57600080fd5b6142298b828c01613dc8565b90975095505060608901356001600160401b0381111561424857600080fd5b6142548b828c01614060565b9450506080890135925060a08901356001600160401b0381111561427757600080fd5b6142838b828c01613dc8565b999c989b5096995094979396929594505050565b6000602082840312156142a957600080fd5b5035919050565b600080604083850312156142c357600080fd5b82356142ce816141a2565b946020939093013593505050565b600080600080600080606087890312156142f557600080fd5b86356001600160401b0381111561430b57600080fd5b61431789828a01613dc8565b90975095505060208701356001600160401b0381111561433657600080fd5b61434289828a01613dc8565b90955093505060408701356001600160401b0381111561436157600080fd5b61436d89828a01613dc8565b979a9699509497509295939492505050565b6001600160a01b03929092168252602082015260400190565b60ff8116811461123d57600080fd5b80356143b281614398565b919050565b600080604083850312156143ca57600080fd5b82356143d5816141a2565b915060208301356143e581614398565b809150509250929050565b6000806020838503121561440357600080fd5b82356001600160401b0381111561441957600080fd5b61442585828601613dc8565b90969095509350505050565b6000806040838503121561444457600080fd5b82356001600160401b0381111561445a57600080fd5b61446685828601614060565b92505060208301356001600160401b0381111561448257600080fd5b61448e85828601614060565b9150509250929050565b600080600080606085870312156144ae57600080fd5b84356144b9816141a2565b93506020850135925060408501356001600160401b038111156144db57600080fd5b613fe787828801613dc8565b600080602083850312156144fa57600080fd5b82356001600160401b0381111561451057600080fd5b61442585828601613f40565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b8281101561457557603f19878603018452614560858351613f01565b94506020938401939190910190600101614544565b50929695505050505050565b801515811461123d57600080fd5b6000602082840312156145a157600080fd5b813561148e81614581565b600080600080604085870312156145c257600080fd5b84356001600160401b038111156145d857600080fd5b6145e487828801613dc8565b90955093505060208501356001600160401b038111156144db57600080fd5b6000806000806000806080878903121561461c57600080fd5b8635955060208701356001600160401b0381111561463957600080fd5b61464589828a01613dc8565b90965094505060408701356001600160401b0381111561466457600080fd5b61467089828a01613dc8565b979a9699509497949695606090950135949350505050565b600080600080600080600080600060c08a8c0312156146a657600080fd5b8935985060208a01356001600160401b038111156146c357600080fd5b6146cf8c828d01613dc8565b90995097505060408a01356001600160401b038111156146ee57600080fd5b6146fa8c828d01613dc8565b90975095505060608a0135935060808a01356001600160401b03811115613eb757600080fd5b60008060008060008060008060e0898b03121561473c57600080fd5b8835975060208901356001600160401b0381111561475957600080fd5b6147658b828c01613dc8565b90985096505060408901356001600160401b0381111561478457600080fd5b6147908b828c01614060565b95505060608901356001600160401b038111156147ac57600080fd5b6147b88b828c01614060565b9450506147c760808a016143a7565b925060a08901356001600160401b038111156147e257600080fd5b6147ee8b828c01614060565b989b979a50959894979396929550929360c00135925050565b60008060008060006080868803121561481f57600080fd5b853594506020860135614831816141a2565b9350604086013561484181613e09565b925060608601356001600160401b0381111561485c57600080fd5b61486888828901613dc8565b969995985093965092949392505050565b634e487b7160e01b600052602160045260246000fd5b6005811061489f5761489f614879565b9052565b60208101610d56828461488f565b8183823760009101908152919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6080815260006148fe60808301898b6148c1565b82810360208401526149108189613f01565b905082810360408401526149258187896148c1565b9050828103606084015261493a8185876148c1565b9a9950505050505050505050565b88815287602082015261495e604082018861488f565b60c06060820152600061497460c0830188613f01565b82810360808401526149878187896148c1565b905082810360a084015261499c8185876148c1565b9b9a5050505050505050505050565b6001600160a01b0392909216825260ff16602082015260400190565b634e487b7160e01b600052603260045260246000fd5b8681526080602082015260006149f76080830187896148c1565b8281036040840152614a0a8186886148c1565b915050826060830152979650505050505050565b600060208284031215614a3057600080fd5b815161148e81614581565b606081526000614a4f6060830187896148c1565b8281036020840152614a628186886148c1565b9150508260408301529695505050505050565b600060208284031215614a8757600080fd5b815161148e81614398565b838152606060208201526000614aab6060830185613f01565b905060ff83166040830152949350505050565b600060208284031215614ad057600080fd5b5051919050565b6020815260006140ed6020830184866148c1565b60008251614afd818460208701613edd565b9190910192915050565b9283526001600160a01b03919091166020830152604082015260600190565b6000808335601e19843603018112614b3d57600080fd5b8301803591506001600160401b03821115614b5757600080fd5b60200191503681900382131561259857600080fd5b600060208284031215614b7e57600080fd5b815161148e816141a2565b600181811c90821680614b9d57607f821691505b602082108103614bbd57634e487b7160e01b600052602260045260246000fd5b50919050565b8281526040602082015260006140ed6040830184613f01565b60008060008060008060c08789031215614bf557600080fd5b863595506020870135945060408701356001600160401b03811115614c1957600080fd5b614c2589828a01614060565b94505060608701356001600160401b03811115614c4157600080fd5b614c4d89828a01614060565b9350506080870135915060a08701356001600160401b03811115614c7057600080fd5b614c7c89828a01614060565b9150509295509295509295565b60008060408385031215614c9c57600080fd5b825160208401519092506143e5816141a2565b608081526000614cc36080830187896148c1565b8281036020840152614cd58187613f01565b60408401959095525050606001529392505050565b88815260e060208201526000614d0460e08301898b6148c1565b8281036040840152614d168189613f01565b90508281036060840152614d2a8188613f01565b608084019690965250506001600160a01b039290921660a083015260c09091015295945050505050565b60008085851115614d6457600080fd5b83861115614d7157600080fd5b5050820193919092039150565b80356001600160e01b03198116906004841015614daf576001600160e01b0319600485900360031b81901b82161691505b5092915050565b606081526000614dca6060830186886148c1565b8281036020840152614ddc8186613f01565b91505082604083015295945050505050565b86815285602082015260c060408201526000614e0d60c0830187613f01565b8281036060840152614e1f8187613f01565b905084608084015282810360a0840152614e398185613f01565b9998505050505050505050565b60a081526000614e5960a0830188613f01565b8281036020840152614e6b8188613f01565b90508281036040840152614e7f8187613f01565b91505060028410614e9257614e92614879565b6060820193909352608001529392505050565b600080600080600060a08688031215614ebd57600080fd5b853594506020860135935060408601356001600160401b03811115614ee157600080fd5b614eed88828901614060565b93505060608601356001600160401b03811115614f0957600080fd5b614f1588828901614060565b95989497509295608001359392505050565b600082601f830112614f3857600080fd5b81356001600160401b03811115614f5157614f51613ff3565b8060051b614f6160208201614009565b91825260208185018101929081019086841115614f7d57600080fd5b6020860192505b838310156136315782356001600160401b03811115614fa257600080fd5b614fb1886020838a0101614060565b83525060209283019290910190614f84565b60008060008060808587031215614fd957600080fd5b8435614fe4816141a2565b935060208501356001600160401b03811115614fff57600080fd5b61500b87828801614060565b93505060408501356001600160401b0381111561502757600080fd5b61503387828801614f27565b92505060608501356001600160401b0381111561504f57600080fd5b61505b87828801614f27565b91505092959194509250565b60408152600061507a6040830185613f01565b828103602084015261508c8185613f01565b95945050505050565b86815285602082015260018060a01b038516604082015260c0606082015260006150c260c0830186613f01565b82810360808401526150d48186613f01565b91505060ff831660a0830152979650505050505050565b6001600160a01b038516815260806020820181905260009061510f90830186613f01565b82810360408401526151218186613f01565b91505060ff8316606083015295945050505050565b6040815260006151496040830185613f01565b905060018060a01b03831660208301529392505050565b838152615170602082018461488f565b60606040820152600061508c6060830184613f01565b60408101615194828561488f565b6001600160a01b039290921660209190910152919050565b6001600160a01b03831681526040602082018190526000906140ed90830184613f01565b60a0815260006151e360a0830189613f01565b82810360208401526151f58189613f01565b905060ff8716604084015282810360608401526152128187613f01565b90508281036080840152614e398185876148c1565b86815285602082015260c06040820152600061524660c0830187613f01565b82810360608401526152588187613f01565b905060ff8516608084015282810360a0840152614e398185613f01565b83815260606020820152600061528e6060830185613f01565b82810360408401526136318185613f01565b600082601f8301126152b157600080fd5b81516020830160006152c561408584614039565b90508281528583830111156152d957600080fd5b61508c836020830184613edd565b6000806000606084860312156152fc57600080fd5b835160208501519093506001600160401b0381111561531a57600080fd5b615326868287016152a0565b92505060408401516001600160401b0381111561534257600080fd5b61534e868287016152a0565b9150509250925092565b60008060008060008060c0878903121561537157600080fd5b86516020880151604089015191975095506001600160401b0381111561539657600080fd5b6153a289828a016152a0565b94505060608701516001600160401b038111156153be57600080fd5b6153ca89828a016152a0565b608089015160a08a0151919550935090506001600160401b038111156153ef57600080fd5b614c7c89828a016152a0565b60808152600061540e6080830187613f01565b82810360208401526154208187613f01565b604084019590955250506060015292915050565b87815260e06020820152600061544d60e0830189613f01565b828103604084015261545f8189613f01565b905082810360608401526154738188613f01565b608084019690965250506001600160a01b039290921660a083015260c090910152949350505050565b60008060008060008060c087890312156154b557600080fd5b86516020880151604089015191975095506001600160401b038111156154da57600080fd5b6154e689828a016152a0565b94505060608701516001600160401b0381111561550257600080fd5b61550e89828a016152a0565b935050608087015161551f81614398565b60a08801519092506001600160401b038111156153ef57600080fd5b60008060008060008060c0878903121561555457600080fd5b865160208801516040890151919750955061556e81613e09565b60608801519094506001600160401b0381111561558a57600080fd5b61559689828a016152a0565b93505060808701516001600160401b038111156155b257600080fd5b6155be89828a016152a0565b92505060a08701516001600160401b038111156153ef57600080fd5b87815286602082015260a0604082015260006155fa60a0830187896148c1565b828103606084015261560d8186886148c1565b91505082608083015298975050505050505050565b601f8211156120d657806000526020600020601f840160051c810160208510156156495750805b601f840160051c820191505b818110156117805760008155600101615655565b81516001600160401b0381111561568257615682613ff3565b615696816156908454614b89565b84615622565b6020601f8211600181146156ca57600083156156b25750848201515b600019600385901b1c1916600184901b178455611780565b600084815260208120601f198516915b828110156156fa57878501518255602094850194600190920191016156da565b50848210156157185786840151600019600387901b60f8161c191681555b50505050600190811b0190555056feee35723ac350a69d2a92d3703f17439cbaadf2f093a21ba5bf5f1a53eb2a14d8360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc04ddbfaa222e81ab9447c070310e87608bf6a4c5d42be5c2fdf0f370b186af799855384122b55936fbfb8ca5120e63c6537a1ac40caf6ae33502b3c5da8c87d1608060405234801561001057600080fd5b50610162806100206000396000f3fe60806040526004361061001d5760003560e01c806277436014610022575b600080fd5b61003561003036600461007b565b610037565b005b8051602082016000f061004957600080fd5b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561008d57600080fd5b813567ffffffffffffffff808211156100a557600080fd5b818401915084601f8301126100b957600080fd5b8135818111156100cb576100cb61004c565b604051601f8201601f19908116603f011681019083821181831017156100f3576100f361004c565b8160405282815287602084870101111561010c57600080fd5b82602086016020830137600092810160200192909252509594505050505056fea264697066735822122094780ce55d28f1d568f4e0ab1b9dc230b96e952b73d2e06456fbff2289fa27f464736f6c63430008150033a2646970667358221220a42e4ec55ccace331728af82aa9182b763f2aef8d6c325aa9acc21ae9da968b064736f6c634300081b0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000e50a35500805b555a8318bdb98e542fb50dd6e080000000000000000000000004c555f2e0c69ac02747986ce5f6a14e2bce44f13000000000000000000000000e432150cce91c13a887f7d836923d5597add8e310000000000000000000000002d5d7d31f671f86c782533cc367f14109a08271200000000000000000000000083a93500d23fbc3e82b410ad07a6a9f7a0670d6600000000000000000000000000000000000000000000000000000000000001200000000000000000000000009d3583cbeb5542287b635bf09d693c8106284c27000000000000000000000000cc360c322f72a89e5247f3875a02c214f31da035000000000000000000000000994014b7f3e5ac898aad533b10534b69d65dd6de00000000000000000000000000000000000000000000000000000000000000076672617874616c00000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : tokenManagerDeployer_ (address): 0xe50A35500805b555A8318Bdb98E542FB50DD6E08
Arg [1] : interchainTokenDeployer_ (address): 0x4c555f2E0c69aC02747986ce5F6A14e2BCE44F13
Arg [2] : gateway_ (address): 0xe432150cce91c13a887f7D836923d5597adD8E31
Arg [3] : gasService_ (address): 0x2d5d7d31F671F86C782533cc367F14109a082712
Arg [4] : interchainTokenFactory_ (address): 0x83a93500d23Fbc3e82B410aD07A6a9F7A0670D66
Arg [5] : chainName_ (string): fraxtal
Arg [6] : tokenManagerImplementation_ (address): 0x9D3583cBeB5542287B635Bf09D693C8106284C27
Arg [7] : tokenHandler_ (address): 0xcC360c322f72a89E5247F3875a02c214F31DA035
Arg [8] : gatewayCaller_ (address): 0x994014b7f3E5Ac898aAD533b10534B69D65DD6dE
-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 000000000000000000000000e50a35500805b555a8318bdb98e542fb50dd6e08
Arg [1] : 0000000000000000000000004c555f2e0c69ac02747986ce5f6a14e2bce44f13
Arg [2] : 000000000000000000000000e432150cce91c13a887f7d836923d5597add8e31
Arg [3] : 0000000000000000000000002d5d7d31f671f86c782533cc367f14109a082712
Arg [4] : 00000000000000000000000083a93500d23fbc3e82b410ad07a6a9f7a0670d66
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [6] : 0000000000000000000000009d3583cbeb5542287b635bf09d693c8106284c27
Arg [7] : 000000000000000000000000cc360c322f72a89e5247f3875a02c214f31da035
Arg [8] : 000000000000000000000000994014b7f3e5ac898aad533b10534b69d65dd6de
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [10] : 6672617874616c00000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in FRAX
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
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.