Overview
CELO Balance
0 CELO
CELO Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 33 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Execute With Tok... | 28807319 | 17 days ago | IN | 0 CELO | 0.00558072 | ||||
Execute With Tok... | 28755908 | 20 days ago | IN | 0 CELO | 0.00636305 | ||||
Execute With Tok... | 28755453 | 20 days ago | IN | 0 CELO | 0.00538693 | ||||
Execute With Tok... | 28755043 | 20 days ago | IN | 0 CELO | 0.00538676 | ||||
Call Bridge Call | 28754654 | 20 days ago | IN | 0.42760499 CELO | 0.00575486 | ||||
Call Bridge Call | 28754500 | 20 days ago | IN | 0.56309932 CELO | 0.00706509 | ||||
Call Bridge Call | 28754488 | 20 days ago | IN | 0.31464396 CELO | 0.00688171 | ||||
Call Bridge Call | 28754469 | 20 days ago | IN | 0.38844185 CELO | 0.00667192 | ||||
Call Bridge Call | 28754430 | 20 days ago | IN | 0.42269275 CELO | 0.00613794 | ||||
Call Bridge Call | 28754353 | 20 days ago | IN | 2.5645153 CELO | 0.00588177 | ||||
Call Bridge Call | 28754348 | 20 days ago | IN | 1.66738916 CELO | 0.00588922 | ||||
Call Bridge Call | 28754339 | 20 days ago | IN | 0.97423521 CELO | 0.00655167 | ||||
Call Bridge Call | 28754327 | 20 days ago | IN | 0.31358515 CELO | 0.00588381 | ||||
Call Bridge Call | 28754324 | 20 days ago | IN | 0.29441724 CELO | 0.00626054 | ||||
Execute With Tok... | 28670561 | 25 days ago | IN | 0 CELO | 0.00681019 | ||||
Execute With Tok... | 28669992 | 25 days ago | IN | 0 CELO | 0.00557992 | ||||
Execute With Tok... | 28635873 | 27 days ago | IN | 0 CELO | 0.00575092 | ||||
Execute With Tok... | 28632771 | 27 days ago | IN | 0 CELO | 0.00558028 | ||||
Execute With Tok... | 28632587 | 27 days ago | IN | 0 CELO | 0.00558028 | ||||
Execute With Tok... | 28632156 | 27 days ago | IN | 0 CELO | 0.00538736 | ||||
Execute With Tok... | 28632033 | 27 days ago | IN | 0 CELO | 0.00617053 | ||||
Execute With Tok... | 28631608 | 27 days ago | IN | 0 CELO | 0.00631891 | ||||
Call Bridge Call | 28629928 | 27 days ago | IN | 0.38376835 CELO | 0.00689936 | ||||
Execute With Tok... | 28619975 | 28 days ago | IN | 0 CELO | 0.00681129 | ||||
Execute With Tok... | 28546835 | 32 days ago | IN | 0 CELO | 0.00695039 |
Latest 16 internal transactions
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
28754654 | 20 days ago | 0.42760499 CELO | ||||
28754500 | 20 days ago | 0.56309932 CELO | ||||
28754488 | 20 days ago | 0.31464396 CELO | ||||
28754469 | 20 days ago | 0.38844185 CELO | ||||
28754430 | 20 days ago | 0.42269275 CELO | ||||
28754353 | 20 days ago | 2.5645153 CELO | ||||
28754348 | 20 days ago | 1.66738916 CELO | ||||
28754339 | 20 days ago | 0.97423521 CELO | ||||
28754327 | 20 days ago | 0.31358515 CELO | ||||
28754324 | 20 days ago | 0.29441724 CELO | ||||
28629928 | 27 days ago | 0.38376835 CELO | ||||
28546824 | 32 days ago | 0.38003681 CELO | ||||
28528949 | 33 days ago | 0.3069398 CELO | ||||
28497168 | 35 days ago | 0.31460622 CELO | ||||
28493941 | 35 days ago | 0.26673779 CELO | ||||
28480044 | 36 days ago | Contract Creation | 0 CELO |
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 Source Code Verified (Exact Match)
Contract Name:
SquidRouter
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 99999 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {ISquidRouter} from "../interfaces/ISquidRouter.sol"; import {ISquidMulticall} from "../interfaces/ISquidMulticall.sol"; import {IPermit2} from "../interfaces/uniswap/IPermit2.sol"; import {IInterchainTokenService} from "../interfaces/its/IInterchainTokenService.sol"; import {ICFReceiver} from "../interfaces/chainflip/ICFReceiver.sol"; import {ICCTPTokenMessenger} from "../interfaces/cctp/ICCTPTokenMessenger.sol"; import {IAxelarGasService} from "@axelar-network/axelar-cgp-solidity/contracts/interfaces/IAxelarGasService.sol"; // Deprecated import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {AxelarExpressExecutable} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/express/AxelarExpressExecutable.sol"; import {InterchainTokenExpressExecutable} from "../interfaces/its/InterchainTokenExpressExecutable.sol"; import {Upgradable} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradable/Upgradable.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {StorageSlot} from "../libraries/StorageSlot.sol"; import {SquidPermit2} from "./SquidPermit2.sol"; import {RoledPausable} from "../libraries/RoledPausable.sol"; import {Utils} from "../libraries/Utils.sol"; contract SquidRouter is ISquidRouter, ICFReceiver, AxelarExpressExecutable, InterchainTokenExpressExecutable, Upgradable, SquidPermit2, RoledPausable { using SafeERC20 for IERC20; using StorageSlot for bytes32; address public immutable squidMulticall; address public immutable chainflipVault; address public immutable usdc; address public immutable cctpTokenMessenger; address public immutable axelarGasService; // Deprecated /// @param _squidMulticall Address of the relevant Squid's SquidMulticall.sol contract deployment. /// @param _permit2 Address of the relevant Uniswap's Permit2.sol contract deployment /// Can be zero address if not available on current network. /// @param _axelarGateway Address of the relevant Axelar's AxelarGateway.sol contract deployment. /// @param _interchainTokenService Address of the relevant Axelar's InterchainTokenService.sol contract /// deployment. /// @param _chainflipVault Address of the relevant Chainflip's Vault.sol contract deployment. Can be zero /// address if not available on current network. /// @param _usdc Address of the relevant Circle's USDC contract deployment (contract name defers from one chain /// to another). Can be zero address if not available on current network. /// @param _cctpTokenMessenger Address of the relevant Circle's TokenMessenger.sol contract deployment. Can be /// zero address if not available on current network. /// @param _axelarGasService Address of the relevant Axelar's AxelarGasService.sol contract deployment. The related /// logic is deprecated and will be removed in a future upgrade. constructor( address _squidMulticall, address _permit2, address _axelarGateway, address _interchainTokenService, address _chainflipVault, address _usdc, address _cctpTokenMessenger, address _axelarGasService // Deprecated ) AxelarExpressExecutable(_axelarGateway) InterchainTokenExpressExecutable(_interchainTokenService) SquidPermit2(_permit2) { if ( _squidMulticall == address(0) || _interchainTokenService == address(0) || _axelarGasService == address(0) // Deprecated ) revert ZeroAddressProvided(); squidMulticall = _squidMulticall; chainflipVault = _chainflipVault; usdc = _usdc; cctpTokenMessenger = _cctpTokenMessenger; axelarGasService = _axelarGasService; // Deprecated } ////////////////////////////////////////////////////////////// // // // Multicall // // // ////////////////////////////////////////////////////////////// /// @inheritdoc ISquidRouter function fundAndRunMulticall( address token, uint256 amount, ISquidMulticall.Call[] calldata calls ) public payable whenNotPaused { // No transfer done if native token is selected as token if (token != Utils.nativeToken) { _transferFrom2(token, msg.sender, address(squidMulticall), amount); } ISquidMulticall(squidMulticall).run{value: msg.value}(calls); } /// @inheritdoc ISquidRouter function permitFundAndRunMulticall( ISquidMulticall.Call[] calldata calls, address from, IPermit2.PermitTransferFrom calldata permit, bytes calldata signature ) external payable whenNotPaused onlyIfPermit2Available { IPermit2.SignatureTransferDetails memory transferDetails = IPermit2 .SignatureTransferDetails({ to: address(squidMulticall), requestedAmount: permit.permitted.amount }); if (from == msg.sender) { // If holder of the funds is sender of the transaction, call the relevant permit2 function. permit2.permitTransferFrom(permit, transferDetails, from, signature); } else { // If holder of the funds is not sender of the transaction, build the witness data and call the relevant // permit2 function. bytes32 hashedCalls = keccak256(abi.encode(calls)); bytes32 witness = keccak256( abi.encode(FUND_AND_RUN_MULTICALL_DATA_TYPEHASH, hashedCalls) ); permit2.permitWitnessTransferFrom( permit, transferDetails, from, witness, FUND_AND_RUN_MULTICALL_WITNESS_TYPE_STRING, signature ); } ISquidMulticall(squidMulticall).run{value: msg.value}(calls); } ////////////////////////////////////////////////////////////// // // // CCTP endpoints // // // ////////////////////////////////////////////////////////////// /// @inheritdoc ISquidRouter function cctpBridge( uint256 amount, uint32 destinationDomain, bytes32 destinationAddress, bytes32 destinationCaller ) external whenNotPaused { Utils.checkServiceAvailability(cctpTokenMessenger); if (destinationCaller == bytes32(0)) revert ZeroAddressProvided(); _transferFrom2(usdc, msg.sender, address(this), amount); ICCTPTokenMessenger(cctpTokenMessenger).depositForBurnWithCaller( amount, destinationDomain, destinationAddress, usdc, destinationCaller ); } /// @inheritdoc ISquidRouter function permitCctpBridge( uint32 destinationDomain, bytes32 destinationAddress, bytes32 destinationCaller, address from, IPermit2.PermitTransferFrom calldata permit, bytes calldata signature ) external whenNotPaused onlyIfPermit2Available { Utils.checkServiceAvailability(cctpTokenMessenger); if (destinationCaller == bytes32(0)) revert ZeroAddressProvided(); IPermit2.SignatureTransferDetails memory transferDetails = IPermit2 .SignatureTransferDetails({ to: address(this), requestedAmount: permit.permitted.amount }); if (from == msg.sender) { // If holder of the funds is sender of the transaction, call the relevant permit2 function. permit2.permitTransferFrom(permit, transferDetails, from, signature); } else { // If holder of the funds is not sender of the transaction, build the witness data and call the relevant // permit2 function. bytes32 witness = keccak256( abi.encode( CCTP_BRIDGE_DATA_TYPEHASH, destinationDomain, destinationAddress, destinationCaller ) ); permit2.permitWitnessTransferFrom( permit, transferDetails, from, witness, CCTP_BRIDGE_WITNESS_TYPE_STRING, signature ); } ICCTPTokenMessenger(cctpTokenMessenger).depositForBurnWithCaller( permit.permitted.amount, destinationDomain, destinationAddress, usdc, destinationCaller ); } /// @inheritdoc ISquidRouter function approveCctpTokenMessenger() external onlyOwner { // Unlimited approval is not security issue since the contract does not store any ERC20 token. IERC20(usdc).approve(cctpTokenMessenger, type(uint256).max); } ////////////////////////////////////////////////////////////// // // // Bridge receivers // // // ////////////////////////////////////////////////////////////// /// @inheritdoc ICFReceiver function cfReceive( uint32, bytes calldata, bytes calldata payload, address token, uint256 amount ) external payable { if (msg.sender != chainflipVault) revert OnlyCfVault(); _processDestinationCalls(payload, token, amount); } /// @notice Called by Axelar protocol when receiving ERC20 tokens on destination chain. /// Contains the logic that will run the payload calldata content. /// @param payload Value provided by Squid containing the calldata that will be ran on destination chain. /// Expected format is: abi.encode(ISquidMulticall.Call[] calls, address refundRecipient, /// bytes32 salt) or abi.encode(address refundRecipient, bytes32 salt) if funds need to be directly sent /// to destination address. /// @param tokenSymbol Symbol of the ERC20 token bridged. /// @param amount Amount of the ERC20 token bridged. function _executeWithToken( string calldata, string calldata, bytes calldata payload, string calldata tokenSymbol, uint256 amount ) internal override { address token = gateway.tokenAddresses(tokenSymbol); _processPayload(payload, token, amount); } /// @notice Called by Interchain Token Service when receiving tokens on destination chain. /// Contains the logic that will run the payload calldata content. /// @param payload Value provided by Squid containing the calldata that will be ran on destination chain. /// Expected format is: abi.encode(ISquidMulticall.Call[] calls, address refundRecipient, /// bytes32 salt) or abi.encode(address refundRecipient, bytes32 salt) if funds need to be directly sent /// to destination address. /// @param token Address of the ERC20 token bridged. /// @param amount Amount of the ERC20 token bridged. function _executeWithInterchainToken( bytes32, string calldata, bytes calldata, bytes calldata payload, bytes32, address token, uint256 amount ) internal override { _processPayload(payload, token, amount); } /// @notice Check size of payload and processes is accordingly. If there is no calls, send tokens /// directly to user. If there are calls, run them. /// @dev Does not work with native token. /// @param payload Value provided by Squid containing the calldata that will be ran on destination chain. /// Expected format is: abi.encode(ISquidMulticall.Call[] calls, address refundRecipient, /// bytes32 salt) or abi.encode(address refundRecipient, bytes32 salt) if funds need to be directly sent /// to destination address. /// @param token Address of the ERC20 token to be either provided to the multicall to run the calls, or /// sent to user. /// @param amount Amount of the ERC20 token used. Must match msg.value /// if native tokens. function _processPayload(bytes calldata payload, address token, uint256 amount) private { // If there is no call data, payload will be exactly 64 bytes (32 for padded address + 32 // for salt) if (payload.length == 64) { (address destinationAddress, ) = abi.decode(payload, (address, bytes32)); IERC20(token).safeTransfer(destinationAddress, amount); } else { _processDestinationCalls(payload, token, amount); } } /// @notice Parse payload, approve multicall and run calldata on it. In case of multicall fail, /// bridged ERC20 tokens are refunded to refund recipient address. /// @param token Address of the ERC20 token to be provided to the multicall to run the calls. /// 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE in case of native token. /// @param amount Amount of ERC20 or native tokens to be provided to the multicall. Must match msg.value /// if native tokens. /// @param payload Value to be parsed to get calldata that will be ran on multicall as well as /// refund recipient address. /// Expected format is: abi.encode(ISquidMulticall.Call[] calls, address refundRecipient, /// bytes32 salt). function _processDestinationCalls( bytes calldata payload, address token, uint256 amount ) private { (ISquidMulticall.Call[] memory calls, address payable refundRecipient, ) = abi.decode( payload, (ISquidMulticall.Call[], address, bytes32) // Last value is a salt that is only used to make to hash of payload vary in case of // identical content of 2 calls ); if (token != Utils.nativeToken) { Utils.smartApprove(token, address(squidMulticall), amount); } try ISquidMulticall(squidMulticall).run{value: msg.value}(calls) { emit CrossMulticallExecuted(keccak256(payload)); } catch (bytes memory reason) { // Refund tokens to refund recipient if swap fails Utils.smartTransfer(token, refundRecipient, amount); emit CrossMulticallFailed(keccak256(payload), reason, refundRecipient); } } ////////////////////////////////////////////////////////////// // // // Utilities // // // ////////////////////////////////////////////////////////////// /// @notice Enable onwer of the contract to transfer tokens that have been mistakenly sent to it. /// There is no custody risk as this contract is not meant to hold any funds in between users calls. /// @dev Only owner can call. /// @param token Address of the ERC20 token to be transfered. /// 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE in case of native token. /// @param to Address that will receive the tokens. /// @param amount Amount of ERC20 or native tokens to transfer. function rescueFunds(address token, address payable to, uint256 amount) external onlyOwner { Utils.smartTransfer(token, to, amount); } ////////////////////////////////////////////////////////////// // // // Proxy requirements // // // ////////////////////////////////////////////////////////////// /// @notice Return hard coded identifier for proxy check during upgrade. /// @return id Hardcoded id. function contractId() external pure override returns (bytes32 id) { id = keccak256("squid-router"); } /// @notice Called by proxy during upgrade. Set pauser role to provided address. /// @param data Bytes containing pauser address. Checked for not zero address. /// Expected format is: abi.encode(address pauser). function _setup(bytes calldata data) internal override { address _pauser = abi.decode(data, (address)); if (_pauser == address(0)) revert ZeroAddressProvided(); _setPauser(_pauser); } ////////////////////////////////////////////////////////////// // // // Deprecated endpoints // // // ////////////////////////////////////////////////////////////// /// @inheritdoc ISquidRouter function bridgeCall( string calldata bridgedTokenSymbol, uint256 amount, string calldata destinationChain, string calldata destinationAddress, bytes calldata payload, address gasRefundRecipient, bool enableExpress ) external payable whenNotPaused { address bridgedTokenAddress = gateway.tokenAddresses(bridgedTokenSymbol); _transferFrom2(bridgedTokenAddress, msg.sender, address(this), amount); _bridgeCall( bridgedTokenSymbol, bridgedTokenAddress, destinationChain, destinationAddress, payload, gasRefundRecipient, enableExpress ); } /// @inheritdoc ISquidRouter function callBridgeCall( address token, uint256 amount, ISquidMulticall.Call[] calldata calls, string calldata bridgedTokenSymbol, string calldata destinationChain, string calldata destinationAddress, bytes calldata payload, address gasRefundRecipient, bool enableExpress ) external payable whenNotPaused { uint256 valueToSend; if (token == Utils.nativeToken) { valueToSend = amount; } else { _transferFrom2(token, msg.sender, address(squidMulticall), amount); } ISquidMulticall(squidMulticall).run{value: valueToSend}(calls); address bridgedTokenAddress = gateway.tokenAddresses(bridgedTokenSymbol); _bridgeCall( bridgedTokenSymbol, bridgedTokenAddress, destinationChain, destinationAddress, payload, gasRefundRecipient, enableExpress ); } /// @notice Helper for handling Axelar gas service funding and Axelar bridging. /// @param bridgedTokenSymbol Symbol of the ERC20 token that will be sent to Axelar bridge. /// @param bridgedTokenAddress Address of the ERC20 token that will be sent to Axelar bridge. /// @param destinationChain Destination chain for bridging according to Axelar's nomenclature. /// @param destinationAddress Address that will receive bridged ERC20 tokens on destination chain. /// @param payload Bytes value containing calls to be ran by the multicall on destination chain. /// Expected format is: abi.encode(ISquidMulticall.Call[] calls, address refundRecipient, bytes32 salt). /// @param gasRefundRecipient Address that will receive native tokens left on gas service after process is /// done. /// @param enableExpress If true is provided, Axelar's express (aka Squid's boost) feature will be used. function _bridgeCall( string calldata bridgedTokenSymbol, address bridgedTokenAddress, string calldata destinationChain, string calldata destinationAddress, bytes calldata payload, address gasRefundRecipient, bool enableExpress ) private { uint256 bridgedTokenBalance = IERC20(bridgedTokenAddress).balanceOf(address(this)); if (address(this).balance > 0) { if (enableExpress) { IAxelarGasService(axelarGasService).payNativeGasForExpressCallWithToken{ value: address(this).balance }( address(this), destinationChain, destinationAddress, payload, bridgedTokenSymbol, bridgedTokenBalance, gasRefundRecipient ); } else { IAxelarGasService(axelarGasService).payNativeGasForContractCallWithToken{ value: address(this).balance }( address(this), destinationChain, destinationAddress, payload, bridgedTokenSymbol, bridgedTokenBalance, gasRefundRecipient ); } } Utils.smartApprove(bridgedTokenAddress, address(gateway), bridgedTokenBalance); gateway.callContractWithToken( destinationChain, destinationAddress, payload, bridgedTokenSymbol, bridgedTokenBalance ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IUpgradable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/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 IUpgradable { error InvalidAddress(); error NotCollector(); error InvalidAmounts(); 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 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 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; import { IAxelarGateway } from '../interfaces/IAxelarGateway.sol'; import { ExpressExecutorTracker } from './ExpressExecutorTracker.sol'; import { SafeTokenTransferFrom, SafeTokenTransfer } from '../libs/SafeTransfer.sol'; import { IERC20 } from '../interfaces/IERC20.sol'; contract AxelarExpressExecutable is ExpressExecutorTracker { using SafeTokenTransfer for IERC20; using SafeTokenTransferFrom for IERC20; IAxelarGateway public immutable gateway; constructor(address gateway_) { if (gateway_ == address(0)) revert InvalidAddress(); gateway = IAxelarGateway(gateway_); } function execute( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes calldata payload ) external { bytes32 payloadHash = keccak256(payload); if (!gateway.validateContractCall(commandId, sourceChain, sourceAddress, payloadHash)) revert NotApprovedByGateway(); address expressExecutor = _popExpressExecutor(commandId, sourceChain, sourceAddress, payloadHash); if (expressExecutor != address(0)) { // slither-disable-next-line reentrancy-events emit ExpressExecutionFulfilled(commandId, sourceChain, sourceAddress, payloadHash, expressExecutor); } else { _execute(sourceChain, sourceAddress, payload); } } function executeWithToken( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes calldata payload, string calldata tokenSymbol, uint256 amount ) external { bytes32 payloadHash = keccak256(payload); if ( !gateway.validateContractCallAndMint( commandId, sourceChain, sourceAddress, payloadHash, tokenSymbol, amount ) ) revert NotApprovedByGateway(); address expressExecutor = _popExpressExecutorWithToken( commandId, sourceChain, sourceAddress, payloadHash, tokenSymbol, amount ); if (expressExecutor != address(0)) { // slither-disable-next-line reentrancy-events emit ExpressExecutionWithTokenFulfilled( commandId, sourceChain, sourceAddress, payloadHash, tokenSymbol, amount, expressExecutor ); address gatewayToken = gateway.tokenAddresses(tokenSymbol); IERC20(gatewayToken).safeTransfer(expressExecutor, amount); } else { _executeWithToken(sourceChain, sourceAddress, payload, tokenSymbol, amount); } } function expressExecute( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes calldata payload ) external payable virtual { 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); _execute(sourceChain, sourceAddress, payload); } function expressExecuteWithToken( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes calldata payload, string calldata symbol, uint256 amount ) external payable virtual { if (gateway.isCommandExecuted(commandId)) revert AlreadyExecuted(); address expressExecutor = msg.sender; address gatewayToken = gateway.tokenAddresses(symbol); bytes32 payloadHash = keccak256(payload); emit ExpressExecutedWithToken( commandId, sourceChain, sourceAddress, payloadHash, symbol, amount, expressExecutor ); _setExpressExecutorWithToken( commandId, sourceChain, sourceAddress, payloadHash, symbol, amount, expressExecutor ); IERC20(gatewayToken).safeTransferFrom(expressExecutor, address(this), amount); _executeWithToken(sourceChain, sourceAddress, payload, symbol, amount); } function _execute( string calldata sourceChain, string calldata sourceAddress, bytes calldata payload ) internal virtual {} function _executeWithToken( string calldata sourceChain, string calldata sourceAddress, bytes calldata payload, string calldata tokenSymbol, uint256 amount ) internal virtual {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IAxelarExpressExecutable } from '../interfaces/IAxelarExpressExecutable.sol'; abstract contract ExpressExecutorTracker is IAxelarExpressExecutable { 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 ) external 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 ) external 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'; interface IAxelarExecutable { error InvalidAddress(); error NotApprovedByGateway(); function gateway() external view returns (IAxelarGateway); function execute( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes calldata payload ) external; function executeWithToken( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes calldata payload, string calldata tokenSymbol, uint256 amount ) 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(); error ExpressExecutorAlreadySet(); /** * @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 with a token 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 symbol The token symbol. * @param amount The amount of tokens. * @param expressExecutor The address of the express executor. */ event ExpressExecutedWithToken( bytes32 indexed commandId, string sourceChain, string sourceAddress, bytes32 payloadHash, string symbol, uint256 indexed amount, 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 Emitted when an express execution with a token is fulfilled. * @param commandId The commandId for the contractCallWithToken. * @param sourceChain The source chain. * @param sourceAddress The source address. * @param payloadHash The hash of the payload. * @param symbol The token symbol. * @param amount The amount of tokens. * @param expressExecutor The address of the express executor. */ event ExpressExecutionWithTokenFulfilled( bytes32 indexed commandId, string sourceChain, string sourceAddress, bytes32 payloadHash, string symbol, uint256 indexed amount, 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 Returns the express executor with token for a given command. * @param commandId The commandId for the contractCallWithToken. * @param sourceChain The source chain. * @param sourceAddress The source address. * @param payloadHash The hash of the payload. * @param symbol The token symbol. * @param amount The amount of tokens. * @return expressExecutor The address of the express executor. */ function getExpressExecutorWithToken( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes32 payloadHash, string calldata symbol, uint256 amount ) 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; /** * @notice Express executes a contract call with token. * @param commandId The commandId for the contractCallWithToken. * @param sourceChain The source chain. * @param sourceAddress The source address. * @param payload The payload data. * @param symbol The token symbol. * @param amount The amount of token. */ function expressExecuteWithToken( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes calldata payload, string calldata symbol, uint256 amount ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IGovernable } from './IGovernable.sol'; import { IImplementation } from './IImplementation.sol'; interface IAxelarGateway is IImplementation, IGovernable { /**********\ |* Errors *| \**********/ error NotSelf(); error InvalidCodeHash(); error SetupFailed(); error InvalidAuthModule(); error InvalidTokenDeployer(); error InvalidAmount(); error InvalidChainId(); error InvalidCommands(); error TokenDoesNotExist(string symbol); error TokenAlreadyExists(string symbol); error TokenDeployFailed(string symbol); error TokenContractDoesNotExist(address token); error BurnFailed(string symbol); error MintFailed(string symbol); error InvalidSetMintLimitsParams(); error ExceedMintLimit(string symbol); /**********\ |* Events *| \**********/ event TokenSent( address indexed sender, string destinationChain, string destinationAddress, string symbol, uint256 amount ); event ContractCall( address indexed sender, string destinationChain, string destinationContractAddress, bytes32 indexed payloadHash, bytes payload ); event ContractCallWithToken( address indexed sender, string destinationChain, string destinationContractAddress, bytes32 indexed payloadHash, bytes payload, string symbol, uint256 amount ); event Executed(bytes32 indexed commandId); event TokenDeployed(string symbol, address tokenAddresses); event ContractCallApproved( bytes32 indexed commandId, string sourceChain, string sourceAddress, address indexed contractAddress, bytes32 indexed payloadHash, bytes32 sourceTxHash, uint256 sourceEventIndex ); event ContractCallApprovedWithMint( bytes32 indexed commandId, string sourceChain, string sourceAddress, address indexed contractAddress, bytes32 indexed payloadHash, string symbol, uint256 amount, bytes32 sourceTxHash, uint256 sourceEventIndex ); event ContractCallExecuted(bytes32 indexed commandId); event TokenMintLimitUpdated(string symbol, uint256 limit); event OperatorshipTransferred(bytes newOperatorsData); event Upgraded(address indexed implementation); /********************\ |* Public Functions *| \********************/ function sendToken( string calldata destinationChain, string calldata destinationAddress, string calldata symbol, uint256 amount ) external; function callContract( string calldata destinationChain, string calldata contractAddress, bytes calldata payload ) external; function callContractWithToken( string calldata destinationChain, string calldata contractAddress, bytes calldata payload, string calldata symbol, uint256 amount ) external; function isContractCallApproved( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, address contractAddress, bytes32 payloadHash ) external view returns (bool); function isContractCallAndMintApproved( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, address contractAddress, bytes32 payloadHash, string calldata symbol, uint256 amount ) external view returns (bool); function validateContractCall( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes32 payloadHash ) external returns (bool); function validateContractCallAndMint( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes32 payloadHash, string calldata symbol, uint256 amount ) external returns (bool); /***********\ |* Getters *| \***********/ function authModule() external view returns (address); function tokenDeployer() external view returns (address); function tokenMintLimit(string memory symbol) external view returns (uint256); function tokenMintAmount(string memory symbol) external view returns (uint256); function allTokensFrozen() external view returns (bool); function implementation() external view returns (address); function tokenAddresses(string memory symbol) external view returns (address); function tokenFrozen(string memory symbol) external view returns (bool); function isCommandExecuted(bytes32 commandId) external view returns (bool); /************************\ |* Governance Functions *| \************************/ function setTokenMintLimits(string[] calldata symbols, uint256[] calldata limits) external; function upgrade( address newImplementation, bytes32 newImplementationCodeHash, bytes calldata setupParams ) external; /**********************\ |* External Functions *| \**********************/ function execute(bytes calldata input) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // General interface for upgradable contracts interface IContractIdentifier { /** * @notice Returns the contract ID. It can be used as a check during upgrades. * @dev Meant to be overridden in derived contracts. * @return bytes32 The contract ID */ function contractId() external pure returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { error InvalidAccount(); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title IGovernable Interface * @notice This is an interface used by the AxelarGateway contract to manage governance and mint limiter roles. */ interface IGovernable { error NotGovernance(); error NotMintLimiter(); error InvalidGovernance(); error InvalidMintLimiter(); event GovernanceTransferred(address indexed previousGovernance, address indexed newGovernance); event MintLimiterTransferred(address indexed previousGovernance, address indexed newGovernance); /** * @notice Returns the governance address. * @return address of the governance */ function governance() external view returns (address); /** * @notice Returns the mint limiter address. * @return address of the mint limiter */ function mintLimiter() external view returns (address); /** * @notice Transfer the governance role to another address. * @param newGovernance The new governance address */ function transferGovernance(address newGovernance) external; /** * @notice Transfer the mint limiter role to another address. * @param newGovernance The new mint limiter address */ function transferMintLimiter(address newGovernance) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IContractIdentifier } from './IContractIdentifier.sol'; interface IImplementation is IContractIdentifier { error NotProxy(); function setup(bytes calldata data) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title IOwnable Interface * @notice IOwnable is an interface that abstracts the implementation of a * contract with ownership control features. It's commonly used in upgradable * contracts and includes the functionality to get current owner, transfer * ownership, and propose and accept ownership. */ interface IOwnable { error NotOwner(); error InvalidOwner(); error InvalidOwnerAddress(); event OwnershipTransferStarted(address indexed newOwner); event OwnershipTransferred(address indexed newOwner); /** * @notice Returns the current owner of the contract. * @return address The address of the current owner */ function owner() external view returns (address); /** * @notice Returns the address of the pending owner of the contract. * @return address The address of the pending owner */ function pendingOwner() external view returns (address); /** * @notice Transfers ownership of the contract to a new address * @param newOwner The address to transfer ownership to */ function transferOwnership(address newOwner) external; /** * @notice Proposes to transfer the contract's ownership to a new address. * The new owner needs to accept the ownership explicitly. * @param newOwner The address to transfer ownership to */ function proposeOwnership(address newOwner) external; /** * @notice Transfers ownership to the pending owner. * @dev Can only be called by the pending owner */ function acceptOwnership() external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; 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; import { IERC20 } from '../interfaces/IERC20.sol'; error TokenTransferFailed(); /* * @title SafeTokenCall * @dev This library is used for performing safe token transfers. */ library SafeTokenCall { /* * @notice Make a safe call to a token contract. * @param token The token contract to interact with. * @param callData The function call data. * @throws TokenTransferFailed error if transfer of token is not successful. */ function safeCall(IERC20 token, bytes memory callData) internal { (bool success, bytes memory returnData) = address(token).call(callData); bool transferred = success && (returnData.length == uint256(0) || abi.decode(returnData, (bool))); if (!transferred || address(token).code.length == 0) revert TokenTransferFailed(); } } /* * @title SafeTokenTransfer * @dev This library safely transfers tokens from the contract to a recipient. */ library SafeTokenTransfer { /* * @notice Transfer tokens to a recipient. * @param token The token contract. * @param receiver The recipient of the tokens. * @param amount The amount of tokens to transfer. */ function safeTransfer( IERC20 token, address receiver, uint256 amount ) internal { SafeTokenCall.safeCall(token, abi.encodeWithSelector(IERC20.transfer.selector, receiver, amount)); } } /* * @title SafeTokenTransferFrom * @dev This library helps to safely transfer tokens on behalf of a token holder. */ library SafeTokenTransferFrom { /* * @notice Transfer tokens on behalf of a token holder. * @param token The token contract. * @param from The address of the token holder. * @param to The address the tokens are to be sent to. * @param amount The amount of tokens to be transferred. */ function safeTransferFrom( IERC20 token, address from, address to, uint256 amount ) internal { SafeTokenCall.safeCall(token, abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, amount)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IImplementation } from '../interfaces/IImplementation.sol'; /** * @title Implementation * @notice This contract serves as a base for other contracts and enforces a proxy-first access restriction. * @dev Derived contracts must implement the setup function. */ abstract contract Implementation is IImplementation { address private immutable implementationAddress; /** * @dev Contract constructor that sets the implementation address to the address of this contract. */ constructor() { implementationAddress = address(this); } /** * @dev Modifier to require the caller to be the proxy contract. * Reverts if the caller is the current contract (i.e., the implementation contract itself). */ modifier onlyProxy() { if (implementationAddress == address(this)) revert NotProxy(); _; } /** * @notice Initializes contract parameters. * This function is intended to be overridden by derived contracts. * The overriding function must have the onlyProxy modifier. * @param params The parameters to be used for initialization */ function setup(bytes calldata params) external virtual; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.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 { 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 // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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); /** * @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 `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /// @title TokenMessenger /// @notice Sends messages and receives messages to/from MessageTransmitters /// and to/from TokenMinters interface ICCTPTokenMessenger { /// @notice Deposits and burns tokens from sender to be minted on destination domain. /// Emits a `DepositForBurn` event. /// @dev reverts if: /// - given burnToken is not supported /// - given destinationDomain has no TokenMessenger registered /// - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance /// to this contract is less than `amount`. /// - burn() reverts. For example, if `amount` is 0. /// - MessageTransmitter returns false or reverts. /// @param amount amount of tokens to burn /// @param destinationDomain destination domain /// @param mintRecipient address of mint recipient on destination domain /// @param burnToken address of contract to burn deposited tokens, on local domain /// @return nonce unique nonce reserved by message function depositForBurn( uint256 amount, uint32 destinationDomain, bytes32 mintRecipient, address burnToken ) external returns (uint64 nonce); /// @notice Deposits and burns tokens from sender to be minted on destination domain. The mint /// on the destination domain must be called by `destinationCaller`. /// WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible /// to broadcast the message on the destination domain. This is an advanced feature, and the standard /// depositForBurn() should be preferred for use cases where a specific destination caller is not required. /// Emits a `DepositForBurn` event. /// @dev reverts if: /// - given destinationCaller is zero address /// - given burnToken is not supported /// - given destinationDomain has no TokenMessenger registered /// - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance /// to this contract is less than `amount`. /// - burn() reverts. For example, if `amount` is 0. /// - MessageTransmitter returns false or reverts. /// @param amount amount of tokens to burn /// @param destinationDomain destination domain /// @param mintRecipient address of mint recipient on destination domain /// @param burnToken address of contract to burn deposited tokens, on local domain /// @param destinationCaller caller on the destination domain, as bytes32 /// @return nonce unique nonce reserved by message function depositForBurnWithCaller( uint256 amount, uint32 destinationDomain, bytes32 mintRecipient, address burnToken, bytes32 destinationCaller ) external returns (uint64 nonce); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /// @title Chainflip Receiver Interface /// @dev The ICFReceiver interface is the interface required to receive tokens and /// cross-chain calls from the Chainflip Protocol. interface ICFReceiver { /// @notice Called by Chainflip protocol when receiving tokens on destination chain. /// Contains the logic that will run the payload calldata content. /// @param sourceChain Source chain according to the Chainflip Protocol's nomenclature. /// @param sourceAddress Source address on the source chain. /// @param payload Value provided by Squid containing the calldata that will be ran on destination chain. /// Expected format is: abi.encode(ISquidMulticall.Call[] calls, address refundRecipient, /// bytes32 salt). /// @param token Address of the ERC20 token received. 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE /// in case of native token. /// @param amount Amount of ERC20 token received. This will match msg.value for native tokens. function cfReceive( uint32 sourceChain, bytes calldata sourceAddress, bytes calldata payload, address token, uint256 amount ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /// @title RoledPausable /// @notice Provide logic to pause a contract and grant au pauser role. /// In case of a pauser update, current pauser provide the address of the potential new /// pauser. Potential new pauser then has to accept the role. /// @dev Contract uses hard coded slot values for variable to prevent storage clashes when upgrading. interface IRoledPausable { /// @notice Emitted when current pauser starts the update process. /// @param currentPauser Address of the current pauser proposing new one. /// @param pendingPauser Address of the potential new pauser. event PauserProposed(address indexed currentPauser, address indexed pendingPauser); /// @notice Emitted when pending pauser accepts pauser role. /// @param newPauser Address of the new pauser. event PauserUpdated(address indexed newPauser); /// @notice Emitted when contract is paused. event Paused(); /// @notice Emitted when contract is unpaused. event Unpaused(); /// @notice Thrown when a pausable function is called while the contract is paused. error ContractIsPaused(); /// @notice Thrown when function is only meant to be called by current pauser. error OnlyPauser(); /// @notice Thrown when function is only meant to be called by pending pauser. error OnlyPendingPauser(); /// @notice Start pauser role update process by providing new pauser address. /// @dev Only callable by current pauser. /// @param newPauser Address of the potential new pauser. function updatePauser(address newPauser) external; /// @notice Let pending pauser accept pauser role. /// @dev Only callable by pending pauser. function acceptPauser() external; /// @notice Let pauser pause the contract. /// @dev Only callable by current pauser. function pause() external; /// @notice Let pauser unpause the contract. /// @dev Only callable by current pauser. function unpause() external; /// @notice Get pause state. /// @dev Return true if paused and false if not paused. function paused() external view returns (bool value); /// @notice Get pauser address. function pauser() external view returns (address value); /// @notice Get pending pauser address. function pendingPauser() external view returns (address value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /// @title SquidMulticall /// @notice Multicall logic specific to Squid calls format. The contract specificity is mainly /// to enable ERC20 and native token amounts in calldata between two calls. /// @dev Support receiption of NFTs. interface ISquidMulticall { /// @notice Call type that enables to specific behaviours of the multicall. enum CallType { // Will simply run calldata Default, // Will update amount field in calldata with ERC20 token balance of the multicall contract. FullTokenBalance, // Will update amount field in calldata with native token balance of the multicall contract. FullNativeBalance, // Will run a safeTransferFrom to get full ERC20 token balance of the caller. CollectTokenBalance } /// @notice Calldata format expected by multicall. struct Call { // Call type, see CallType struct description. CallType callType; // Address that will be called. address target; // Native token amount that will be sent in call. uint256 value; // Calldata that will be send in call. bytes callData; // Extra data used by multicall depending on call type. // Default: unused (provide 0x) // FullTokenBalance: address of the ERC20 token to get balance of and zero indexed position // of the amount parameter to update in function call contained by calldata. // Expect format is: abi.encode(address token, uint256 amountParameterPosition) // Eg: for function swap(address tokenIn, uint amountIn, address tokenOut, uint amountOutMin,) // amountParameterPosition would be 1. // FullNativeBalance: unused (provide 0x) // CollectTokenBalance: address of the ERC20 token to collect. // Expect format is: abi.encode(address token) bytes payload; } /// Thrown when one of the calls fails. /// @param callPosition Zero indexed position of the call in the call set provided to the /// multicall. /// @param reason Revert data returned by contract called in failing call. error CallFailed(uint256 callPosition, bytes reason); /// @notice Main function of the multicall that runs the call set. /// @param calls Call set to be ran by multicall. function run(Call[] calldata calls) external payable; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; import {ISquidMulticall} from "./ISquidMulticall.sol"; import {IPermit2} from "../interfaces/uniswap/IPermit2.sol"; /// @title SquidRouter /// @notice Main entry point of the protocol. It mainly provides endpoints to interact safely /// with the multicall or CCTP, and receiver function to handle asset reception for bridges. interface ISquidRouter { /// @notice Emitted when the calldata content of a payload is successfully ran on destination chain. /// @param payloadHash Keccak256 of the payload bytes value. Differ from one call to another in case of /// identical parameters value thanks to a salt value. event CrossMulticallExecuted(bytes32 indexed payloadHash); /// @notice Emitted when the calldata content of a payload failed to be ran on destination chain and /// ERC20 tokens are sent to refund recipient address. /// @param payloadHash Keccak256 hash of the payload bytes value. Differ from one call to another in case /// of identical parameters value thanks to a salt value. /// @param reason Revert data returned by contract called in failing call. /// @param refundRecipient Address that will receive bridged ERC20 tokens on destination chain in case /// of multicall failure. event CrossMulticallFailed( bytes32 indexed payloadHash, bytes reason, address indexed refundRecipient ); /// @notice Thrown when address(0) is provided to a parameter that does not allow it. error ZeroAddressProvided(); /// @notice Thrown when Chainflip receiver function is called by any address other that Chainflip /// vault contract. error OnlyCfVault(); /// @notice Collect ERC20 and/or native tokens from user and send them to multicall. Then run multicall. /// @dev Require either ERC20 or permit2 allowance from the user to the router address. /// Indeed, permit2's transferFrom2 is used instead of regulat transferFrom. Meaning that if there is no /// regular allowance from user to the router for ERC20 token, permit2 allowance will be used if granted. /// @dev Native tokens can be provided on top of ERC20 tokens, both will be sent to multicall. /// @param token Address of the ERC20 token to be provided to the multicall to run the calls. /// 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE in case of native token. /// @param amount Amount of ERC20 tokens to be provided to the multicall. If native token is selected, this /// value has not effect. /// @param calls Calls to be ran by the multicall, formatted in accordance to Call struct. function fundAndRunMulticall( address token, uint256 amount, ISquidMulticall.Call[] calldata calls ) external payable; /// @notice Collect ERC20 tokens from user and send them to multicall thanks to a permit2 signed permit. Then run /// multicall. /// @dev Native tokens can be provided on top of ERC20 tokens by the relayer of the permit, both will be sent /// to multicall. /// @dev Transaction sender can either be the holder of the funds, or the separate relayer. In the later case, /// witness must be included in the data signed, according to the permit2 protocol. /// @dev See https://docs.uniswap.org/contracts/permit2/reference/signature-transfer for more information about /// permit2 protocol requirements. /// @dev ERC20 token and amount values to be used are provided in the permit data. /// @param calls Calls to be ran by the multicall, formatted in accordance to Call struct. /// @param from Holder of the funds to be provided. Can defer from the sender of the transaction in case of a /// relayed transaction. /// @param permit Permit data according to permit2 protocol. /// @param signature Signature data according to permit2 protocol. function permitFundAndRunMulticall( ISquidMulticall.Call[] memory calls, address from, IPermit2.PermitTransferFrom calldata permit, bytes calldata signature ) external payable; /// @notice Collect USDC tokens from user and trigger CCTP bridging. /// @dev This endpoint is meant to enable CCTP bridging at the end of a multicall. It also enable integrations /// with Squid CCTP bridging relayer infrasctructure. /// @dev Require either ERC20 or permit2 allowance from the user to the router address. /// Indeed, permit2's transferFrom2 is used instead of regulat transferFrom. Meaning that if there is no /// regular allowance from user to the router for ERC20 token, permit2 allowance will be used if granted. /// @dev CCTP's replaceDepositForBurn function is not made available for security reason. Integrators need to /// be careful with the parameters they provide. /// @dev Require owner to call `approveCctpTokenMessenger` function first. /// @param amount Amount of USDC tokens to be bridged. /// @param destinationDomain Destination chain according to CCTP's nomenclature. /// This param is checked for potential irrelevant values by CCTP contract. /// See https://developers.circle.com/stablecoins/docs/cctp-technical-reference. /// @param destinationAddress Address that will receive USDC tokens on destination chain. /// This param is checked for not zero value by CCTP contract. /// @param destinationCaller Address that will be able to trigger USDC tokens reception on destination chain. /// This param is checked for not zero value to disable anonymous actions. function cctpBridge( uint256 amount, uint32 destinationDomain, bytes32 destinationAddress, bytes32 destinationCaller ) external; /// @notice Collect USDC tokens from user thanks to a permit2 signed permit and trigger CCTP bridging. /// @dev Transaction sender can either be the holder of the funds, or the separate relayer. In the later case, /// witness must be included in the data signed, according to the permit2 protocol. /// @dev See https://docs.uniswap.org/contracts/permit2/reference/signature-transfer for more information about /// permit2 protocol requirements. /// @dev USDC token and amount values to be used are provided in the permit data. /// Permit token address value is checked to match USDC token address. /// @dev CCTP's replaceDepositForBurn function is not made available for security reason. Integrators need to /// be careful with the parameters they provide. /// @dev Require owner to call `approveCctpTokenMessenger` function first. /// @param destinationDomain Destination chain according to CCTP's nomenclature. /// This param is checked for potential irrelevant values by CCTP contract. /// See https://developers.circle.com/stablecoins/docs/cctp-technical-reference. /// @param destinationAddress Address that will receive USDC tokens on destination chain. /// This param is checked for not zero value by CCTP contract. /// @param destinationCaller Address that will be able to trigger USDC tokens reception on destination chain. /// This param is checked for not zero value to disable anonymous actions. /// @param from Holder of the funds to be provided. Can defer from the sender of the transaction in case of a /// relayed transaction. /// @param permit Permit data according to permit2 protocol. /// @param signature Signature data according to permit2 protocol. function permitCctpBridge( uint32 destinationDomain, bytes32 destinationAddress, bytes32 destinationCaller, address from, IPermit2.PermitTransferFrom calldata permit, bytes calldata signature ) external; /// @notice Approve CCTP Token Messenger to access unlimited amount of USDC. Enables to not have to /// approve each time a user wants to bridge USDC. Requires to monitor CCTP Token Messenger allowance. /// @dev Only owner can call. function approveCctpTokenMessenger() external; /// @notice Collect ERC20 and/or native tokens from user and send them to multicall. Then bridge tokens /// through Axelar bridge and run multicall on destination chain. This endpoint is deprecated and will be /// removed in a future upgrade. /// @dev Require either ERC20 or permit2 allowance from the user to the router address. /// Indeed, permit2's transferFrom2 is used instead of regulat transferFrom. Meaning that if there is no /// regular allowance from user to the router for ERC20 token, permit2 allowance will be used if granted. /// @dev Require to provide native amount to cover gas service. The amount has to be computed off chain with /// Axelar SDK. /// @dev Native tokens provided on top of an ERC20 token will be sent to gas service. Thus you need to provide /// native amount to cover gas service on top of native amount for calls /// @dev Gas service providing is handled internally. /// @param bridgedTokenSymbol Symbol of the token that will be sent to Axelar bridge. /// @param amount Amount of ERC20 tokens to be collect for bridging. /// @param destinationChain Destination chain for bridging according to Axelar's nomenclature. /// @param destinationAddress Address that will receive bridged ERC20 tokens on destination chain. /// @param payload Bytes value containing calls to be ran by the multicall on destination chain. /// Expected format is: abi.encode(ISquidMulticall.Call[] calls, address refundRecipient, bytes32 salt). /// @param gasRefundRecipient Address that will receive native tokens left on gas service after process is /// done. /// @param enableExpress If true is provided, Axelar's express (aka Squid's boost) feature will be used. function bridgeCall( string calldata bridgedTokenSymbol, uint256 amount, string calldata destinationChain, string calldata destinationAddress, bytes calldata payload, address gasRefundRecipient, bool enableExpress ) external payable; /// @notice Collect ERC20 and/or native tokens from user and send them to multicall. Then run multicall and /// bridge tokens through Axelar bridge before running multicall on destination chain. This endpoint is /// deprecated and will be removed in a future upgrade. /// @dev Require either ERC20 or permit2 allowance from the user to the router address. /// Indeed, permit2's transferFrom2 is used instead of regulat transferFrom. Meaning that if there is no /// regular allowance from user to the router for ERC20 token, permit2 allowance will be used if granted. /// @dev Require to provide native amount to cover gas service. The amount has to be computed off chain with /// Axelar SDK. /// @dev Native tokens provided on top of an ERC20 token will be sent to gas service. If input token is native /// tokens, input amount will be sent to multicall and the rest to gas service. Thus you need to provide native /// amount to cover gas service on top of native amount for calls. /// @dev Gas service providing is handled internally. /// @param token Address of the ERC20 token to be provided to the multicall to run the calls. /// 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE in case of native token. /// @param amount Amount of ERC20 or native tokens to be provided to the multicall. /// @param calls Calls to be ran by the multicall on source chain, formatted in accordance to Call struct. /// @param bridgedTokenSymbol Symbol of the token that will be sent to Axelar bridge. /// @param destinationChain Destination chain for bridging according to Axelar's nomenclature. /// @param destinationAddress Address that will receive bridged ERC20 tokens on destination chain. /// @param payload Bytes value containing calls to be ran by the multicall on destination chain. /// Expected format is: abi.encode(ISquidMulticall.Call[] calls, address refundRecipient, bytes32 salt). /// @param gasRefundRecipient Address that will receive native tokens left on gas service after process is /// done. /// @param enableExpress If true is provided, Axelar's express (aka Squid's boost) feature will be used. function callBridgeCall( address token, uint256 amount, ISquidMulticall.Call[] calldata calls, string calldata bridgedTokenSymbol, string calldata destinationChain, string calldata destinationAddress, bytes calldata payload, address gasRefundRecipient, bool enableExpress ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; interface IExpressCallHandler { error AlreadyExpressCalled(); error SameDestinationAsCaller(); event ExpressReceive(bytes payload, bytes32 indexed sendHash, address indexed expressCaller); event ExpressExecutionFulfilled(bytes payload, bytes32 indexed sendHash, address indexed expressCaller); /** * @notice Gets the address of the express caller for a specific token transfer * @param payload the payload for the receive token * @param commandId The unique hash for this token transfer * @return expressCaller The address of the express caller for this token transfer */ function getExpressReceiveToken( bytes calldata payload, bytes32 commandId ) external view returns (address expressCaller); }
// 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.9; import {IAxelarExecutable} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarExecutable.sol"; import {IContractIdentifier} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IContractIdentifier.sol"; import {IExpressCallHandler} from "./IExpressCallHandler.sol"; import {ITokenManagerType} from "./ITokenManagerType.sol"; import {IPausable} from "./IPausable.sol"; import {IMulticall} from "./IMulticall.sol"; interface IInterchainTokenService is ITokenManagerType, IExpressCallHandler, IAxelarExecutable, IPausable, IMulticall, IContractIdentifier { error ZeroAddress(); error LengthMismatch(); error InvalidTokenManagerImplementation(); error NotRemoteService(); error TokenManagerDoesNotExist(bytes32 tokenId); error NotTokenManager(); error ExecuteWithInterchainTokenFailed(address contractAddress); error NotCanonicalTokenManager(); error GatewayToken(); error TokenManagerDeploymentFailed(); error StandardizedTokenDeploymentFailed(); error DoesNotAcceptExpressExecute(address contractAddress); error SelectorUnknown(); error InvalidMetadataVersion(uint32 version); error AlreadyExecuted(bytes32 commandId); error ExecuteWithTokenNotSupported(); error InvalidExpressSelector(); event TokenSent(bytes32 indexed tokenId, string destinationChain, bytes destinationAddress, uint256 indexed amount); event TokenSentWithData( bytes32 indexed tokenId, string destinationChain, bytes destinationAddress, uint256 indexed amount, address indexed sourceAddress, bytes data ); event TokenReceived( bytes32 indexed tokenId, string sourceChain, address indexed destinationAddress, uint256 indexed amount ); event TokenReceivedWithData( bytes32 indexed tokenId, string sourceChain, address indexed destinationAddress, uint256 indexed amount, bytes sourceAddress, bytes data ); event RemoteTokenManagerDeploymentInitialized( bytes32 indexed tokenId, string destinationChain, uint256 indexed gasValue, TokenManagerType indexed tokenManagerType, bytes params ); event RemoteStandardizedTokenAndManagerDeploymentInitialized( bytes32 indexed tokenId, string tokenName, string tokenSymbol, uint8 tokenDecimals, bytes distributor, bytes mintTo, uint256 indexed mintAmount, bytes operator, string destinationChain, uint256 indexed gasValue ); event TokenManagerDeployed(bytes32 indexed tokenId, TokenManagerType indexed tokenManagerType, bytes params); event StandardizedTokenDeployed( bytes32 indexed tokenId, address indexed distributor, string name, string symbol, uint8 decimals, uint256 indexed mintAmount, address mintTo ); event CustomTokenIdClaimed(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 standardized token deployer contract. * @return standardizedTokenDeployerAddress The address of the standardized token deployer contract. */ function standardizedTokenDeployer() external view returns (address standardizedTokenDeployerAddress); /** * @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 getTokenManagerAddress(bytes32 tokenId) external view returns (address tokenManagerAddress); /** * @notice Returns the address of the valid token manager associated with the given tokenId. * @param tokenId The tokenId of the token manager. * @return tokenManagerAddress The address of the valid token manager. */ function getValidTokenManagerAddress(bytes32 tokenId) external view returns (address tokenManagerAddress); /** * @notice Returns the address of the token associated with the given tokenId. * @param tokenId The tokenId of the token manager. * @return tokenAddress The address of the token. */ function getTokenAddress(bytes32 tokenId) external view returns (address tokenAddress); /** * @notice Returns the address of the standardized token associated with the given tokenId. * @param tokenId The tokenId of the standardized token. * @return tokenAddress The address of the standardized token. */ function getStandardizedTokenAddress(bytes32 tokenId) external view returns (address tokenAddress); /** * @notice Returns the canonical tokenId associated with the given tokenAddress. * @param tokenAddress The address of the token. * @return tokenId The canonical tokenId associated with the tokenAddress. */ function getCanonicalTokenId(address tokenAddress) external view returns (bytes32 tokenId); /** * @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 getCustomTokenId(address operator, bytes32 salt) external view returns (bytes32 tokenId); /** * @notice Registers a canonical token and returns its associated tokenId. * @param tokenAddress The address of the canonical token. * @return tokenId The tokenId associated with the registered canonical token. */ function registerCanonicalToken(address tokenAddress) external payable returns (bytes32 tokenId); /** * @notice Deploys a standardized canonical token on a remote chain. * @param tokenId The tokenId of the canonical token. * @param destinationChain The name of the destination chain. * @param gasValue The gas value for deployment. */ function deployRemoteCanonicalToken( bytes32 tokenId, string calldata destinationChain, uint256 gasValue ) external payable; /** * @notice Deploys a custom token manager contract. * @param salt The salt used for token manager deployment. * @param tokenManagerType The type of token manager. * @param params The deployment parameters. * @return tokenId The tokenId of the deployed token manager. */ function deployCustomTokenManager( bytes32 salt, TokenManagerType tokenManagerType, bytes memory params ) external payable returns (bytes32 tokenId); /** * @notice Deploys a custom token manager contract on a remote chain. * @param salt The salt used for token manager deployment. * @param destinationChain The name of the destination chain. * @param tokenManagerType The type of token manager. * @param params The deployment parameters. * @param gasValue The gas value for deployment. */ function deployRemoteCustomTokenManager( bytes32 salt, string calldata destinationChain, TokenManagerType tokenManagerType, bytes calldata params, uint256 gasValue ) external payable returns (bytes32 tokenId); /** * @notice Deploys a standardized token and registers it. The token manager type will be lock/unlock unless the distributor matches its address, in which case it will be a mint/burn one. * @param salt The salt used for token deployment. * @param name The name of the standardized token. * @param symbol The symbol of the standardized token. * @param decimals The number of decimals for the standardized token. * @param mintAmount The amount of tokens to mint to the deployer. * @param distributor The address of the distributor for mint/burn operations. */ function deployAndRegisterStandardizedToken( bytes32 salt, string calldata name, string calldata symbol, uint8 decimals, uint256 mintAmount, address distributor ) external payable; /** * @notice Deploys and registers a standardized token on a remote chain. * @param salt The salt used for token deployment. * @param name The name of the standardized tokens. * @param symbol The symbol of the standardized tokens. * @param decimals The number of decimals for the standardized tokens. * @param distributor The distributor data for mint/burn operations. * @param mintTo The address where the minted tokens will be sent upon deployment. * @param mintAmount The amount of tokens to be minted upon deployment. * @param operator The operator data for standardized tokens. * @param destinationChain The name of the destination chain. * @param gasValue The gas value for deployment. */ function deployAndRegisterRemoteStandardizedToken( bytes32 salt, string memory name, string memory symbol, uint8 decimals, bytes memory distributor, bytes memory mintTo, uint256 mintAmount, bytes memory operator, string calldata destinationChain, uint256 gasValue ) external payable; /** * @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 getImplementation(uint256 tokenManagerType) external view returns (address tokenManagerAddress); function interchainTransfer( bytes32 tokenId, string calldata destinationChain, bytes calldata destinationAddress, uint256 amount, bytes calldata metadata ) external; function sendTokenWithData( bytes32 tokenId, string calldata destinationChain, bytes calldata destinationAddress, uint256 amount, bytes calldata data ) external; /** * @notice Initiates an interchain token transfer. Only callable by TokenManagers * @param tokenId The tokenId of the token to be transmitted. * @param sourceAddress The source address of the token. * @param destinationChain The name of the destination chain. * @param destinationAddress The destination address on the destination chain. * @param amount The amount of tokens to transmit. * @param metadata The metadata associated with the transmission. */ function transmitSendToken( bytes32 tokenId, address sourceAddress, string calldata destinationChain, bytes memory destinationAddress, uint256 amount, bytes calldata metadata ) 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 Returns the flow limit for a specific token. * @param tokenId The tokenId of the token. * @return flowLimit The flow limit for the token. */ function getFlowLimit(bytes32 tokenId) external view returns (uint256 flowLimit); /** * @notice Returns the total amount of outgoing flow for a specific token. * @param tokenId The tokenId of the token. * @return flowOutAmount The total amount of outgoing flow for the token. */ function getFlowOutAmount(bytes32 tokenId) external view returns (uint256 flowOutAmount); /** * @notice Returns the total amount of incoming flow for a specific token. * @param tokenId The tokenId of the token. * @return flowInAmount The total amount of incoming flow for the token. */ function getFlowInAmount(bytes32 tokenId) external view returns (uint256 flowInAmount); /** * @notice Sets the paused state of the contract. * @param paused The boolean value indicating whether the contract is paused or not. */ function setPaused(bool paused) external; /** * @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 payload the payload of the receive token * @param commandId the commandId calculated from the event at the sourceChain. */ function expressReceiveToken(bytes calldata payload, bytes32 commandId, string calldata sourceChain) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /** * @title IMulticall * @notice This contract is a multi-functional smart contract which allows for multiple * contract calls in a single transaction. */ interface 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) external payable returns (bytes[] memory results); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IInterchainTokenExecutable} from "./IInterchainTokenExecutable.sol"; /** * @title InterchainTokenExecutable * @notice Abstract contract that defines an interface for executing arbitrary logic * in the context of interchain token operations. * @dev This contract should be inherited by contracts that intend to execute custom * logic in response to interchain token actions such as transfers. This contract * will only be called by the interchain token service. */ abstract contract InterchainTokenExecutable is IInterchainTokenExecutable { error NotService(address caller); address public immutable interchainTokenService; bytes32 internal constant EXECUTE_SUCCESS = keccak256("its-execute-success"); /** * @notice Creates a new InterchainTokenExecutable contract. * @param interchainTokenService_ The address of the interchain token service that will call this contract. */ constructor(address interchainTokenService_) { interchainTokenService = interchainTokenService_; } /** * Modifier to restrict function execution to the interchain token service. */ modifier onlyService() { if (msg.sender != interchainTokenService) revert NotService(msg.sender); _; } /** * @notice Executes logic in the context of an interchain token transfer. * @dev Only callable by the interchain token service. * @param commandId The 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 being transferred. * @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 virtual onlyService returns (bytes32) { _executeWithInterchainToken(commandId, sourceChain, sourceAddress, data, tokenId, token, amount); return EXECUTE_SUCCESS; } /** * @notice Internal function containing the logic to be executed with interchain token transfer. * @dev Logic must be implemented by derived contracts. * @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 being transferred. */ function _executeWithInterchainToken( bytes32 commandId, string calldata sourceChain, bytes calldata sourceAddress, bytes calldata data, bytes32 tokenId, address token, uint256 amount ) internal virtual; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IInterchainTokenExpressExecutable} from "./IInterchainTokenExpressExecutable.sol"; import {InterchainTokenExecutable} from "./InterchainTokenExecutable.sol"; /** * @title InterchainTokenExpressExecutable * @notice Abstract contract that defines an interface for executing express logic in the context of interchain token operations. * @dev This contract extends `InterchainTokenExecutable` to provide express execution capabilities. It is intended to be inherited by contracts * that implement express logic for interchain token actions. This contract will only be called by the interchain token service. */ abstract contract InterchainTokenExpressExecutable is IInterchainTokenExpressExecutable, InterchainTokenExecutable { bytes32 internal constant EXPRESS_EXECUTE_SUCCESS = keccak256("its-express-execute-success"); /** * @notice Creates a new InterchainTokenExpressExecutable contract. * @param interchainTokenService_ The address of the interchain token service that will call this contract. */ constructor(address interchainTokenService_) InterchainTokenExecutable(interchainTokenService_) {} /** * @notice Executes express logic in the context of an interchain token transfer. * @dev Only callable by the interchain token service. * @param commandId The 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 virtual onlyService returns (bytes32) { _executeWithInterchainToken(commandId, sourceChain, sourceAddress, data, tokenId, token, amount); return EXPRESS_EXECUTE_SUCCESS; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /** * @title Pausable * @notice This contract provides a mechanism to halt the execution of specific functions * if a pause condition is activated. */ interface IPausable { event PausedSet(bool indexed paused); error Paused(); /** * @notice Check if the contract is paused * @return paused A boolean representing the pause status. True if paused, false otherwise. */ function isPaused() external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /** * @title ITokenManagerType * @notice A simple interface that defines all the token manager types */ interface ITokenManagerType { enum TokenManagerType { MINT_BURN, MINT_BURN_FROM, LOCK_UNLOCK, LOCK_UNLOCK_FEE } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /// @title Permit2 /// @notice Permit2 handles signature-based transfers in SignatureTransfer and allowance-based transfers in AllowanceTransfer. /// @dev Users must approve Permit2 before calling any of the transfer functions. interface IPermit2 { /// @notice The token and amount details for a transfer signed in the permit transfer signature struct TokenPermissions { // ERC20 token address address token; // the maximum amount that can be spent uint256 amount; } /// @notice The signed permit message for a single token transfer struct PermitTransferFrom { TokenPermissions permitted; // a unique value for every token owner's signature to prevent signature replays uint256 nonce; // deadline on the permit signature uint256 deadline; } /// @notice Specifies the recipient address and amount for batched transfers. /// @dev Recipients and amounts correspond to the index of the signed token permissions array. /// @dev Reverts if the requested amount is greater than the permitted signed amount. struct SignatureTransferDetails { // recipient address address to; // spender requested amount uint256 requestedAmount; } /// @notice Transfer approved tokens from one address to another /// @param from The address to transfer from /// @param to The address of the recipient /// @param amount The amount of the token to transfer /// @param token The token address to transfer /// @dev Requires the from address to have approved at least the desired amount /// of tokens to msg.sender. function transferFrom(address from, address to, uint160 amount, address token) external; /// @notice Transfers a token using a signed permit message /// @dev Reverts if the requested amount is greater than the permitted signed amount /// @param permit The permit data signed over by the owner /// @param owner The owner of the tokens to transfer /// @param transferDetails The spender's requested transfer details for the permitted token /// @param signature The signature to verify function permitTransferFrom( PermitTransferFrom memory permit, SignatureTransferDetails calldata transferDetails, address owner, bytes calldata signature ) external; /// @notice Transfers a token using a signed permit message /// @notice Includes extra data provided by the caller to verify signature over /// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition /// @dev Reverts if the requested amount is greater than the permitted signed amount /// @param permit The permit data signed over by the owner /// @param owner The owner of the tokens to transfer /// @param transferDetails The spender's requested transfer details for the permitted token /// @param witness Extra data to include when checking the user signature /// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash /// @param signature The signature to verify function permitWitnessTransferFrom( PermitTransferFrom memory permit, SignatureTransferDetails calldata transferDetails, address owner, bytes32 witness, string calldata witnessTypeString, bytes calldata signature ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; import {IRoledPausable} from "../interfaces/IRoledPausable.sol"; import {StorageSlot} from "./StorageSlot.sol"; abstract contract RoledPausable is IRoledPausable { using StorageSlot for bytes32; /// Hard coded slot numbers for contract variables. bytes32 internal constant PAUSED_SLOT = keccak256("RoledPausable.paused"); bytes32 internal constant PAUSER_SLOT = keccak256("RoledPausable.pauser"); bytes32 internal constant PENDING_PAUSER_SLOT = keccak256("RoledPausable.pendingPauser"); /// @notice msg.sender has the pauser role by default. constructor() { _setPauser(msg.sender); } /// @notice Check if contract is paused and revert if so. /// @dev Meant to be used in inheritor contract. modifier whenNotPaused() { if (paused()) revert ContractIsPaused(); _; } /// @inheritdoc IRoledPausable function updatePauser(address newPauser) external { _onlyPauser(); PENDING_PAUSER_SLOT.setAddress(newPauser); emit PauserProposed(msg.sender, newPauser); } /// @inheritdoc IRoledPausable function acceptPauser() external { if (msg.sender != pendingPauser()) revert OnlyPendingPauser(); _setPauser(msg.sender); PENDING_PAUSER_SLOT.setAddress(address(0)); } /// @inheritdoc IRoledPausable function pause() external virtual { _onlyPauser(); PAUSED_SLOT.setBool(true); emit Paused(); } /// @inheritdoc IRoledPausable function unpause() external virtual { _onlyPauser(); PAUSED_SLOT.setBool(false); emit Unpaused(); } /// @inheritdoc IRoledPausable function paused() public view returns (bool value) { value = PAUSED_SLOT.getBool(); } /// @inheritdoc IRoledPausable function pauser() public view returns (address value) { value = PAUSER_SLOT.getAddress(); } /// @inheritdoc IRoledPausable function pendingPauser() public view returns (address value) { value = PENDING_PAUSER_SLOT.getAddress(); } /// @notice Update pauser value in storage. /// @param _pauser New pauser address value. function _setPauser(address _pauser) internal { PAUSER_SLOT.setAddress(_pauser); emit PauserUpdated(_pauser); } /// @notice Check if caller is pauser and revert if not. /// @dev Meant to be used in inheritor contract. function _onlyPauser() internal view { if (msg.sender != pauser()) revert OnlyPauser(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /// @title StorageSlot /// @notice Provide functions to easily read and write different type of /// values at specific slots in storage. library StorageSlot { /// @notice Enable to set a uint256 value at a specific slot in storage. /// @param slot Slot to be written in. /// @param value Value to be written in the slot. function setUint256(bytes32 slot, uint256 value) internal { assembly { sstore(slot, value) } } /// @notice Enable to get a uint256 value at a specific slot in storage. /// @param slot Slot to get value from. function getUint256(bytes32 slot) internal view returns (uint256 value) { assembly { value := sload(slot) } } /// @notice Enable to set an address value at a specific slot in storage. /// @param slot Slot to be written in. /// @param value Value to be written in the slot. function setAddress(bytes32 slot, address value) internal { assembly { sstore(slot, value) } } /// @notice Enable to get a address value at a specific slot in storage. /// @param slot Slot to get value from. function getAddress(bytes32 slot) internal view returns (address value) { assembly { value := sload(slot) } } /// @notice Enable to set a bool value at a specific slot in storage. /// @param slot Slot to be written in. /// @param value Value to be written in the slot. function setBool(bytes32 slot, bool value) internal { assembly { sstore(slot, value) } } /// @notice Enable to get a bool value at a specific slot in storage. /// @param slot Slot to get value from. function getBool(bytes32 slot) internal view returns (bool value) { assembly { value := sload(slot) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; /// @title Utils /// @notice Library for general purpose functions and values. library Utils { using SafeERC20 for IERC20; using Address for address payable; /// @notice Thrown when an approval call to an ERC20 contract failed. error ApprovalFailed(); /// @notice Thrown when service has zero address because not available on current chain. error ServiceUnavailable(); /// @notice Arbitrary address chosen to represent native token of current network. address internal constant nativeToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; /// @notice Handle logic around approval for ERC20 token contracts depending on /// the context. Will give unlimited allowance on first call and only trigger /// again if allowance is below expected amount. /// @dev Handle allowance reset to comply with USDT token contract. /// @dev Should not be used with any contract that holds ERC20 tokens. /// @param token Address of the ERC20 token contract to send approval to. /// @param spender Address that will be granted allowance. /// @param amount Amount of ERC20 token to grant allowance for. function smartApprove(address token, address spender, uint256 amount) internal { uint256 allowance = IERC20(token).allowance(address(this), spender); if (allowance < amount) { if (allowance > 0) { _approveCall(token, spender, 0); } _approveCall(token, spender, type(uint256).max); } } /// @notice Create, send and check low level approval call. /// @dev Should not be used with any contract that holds ERC20 tokens. /// @param token Address of the ERC20 token contract to send approval to. /// @param spender Address that will be granted allowance. /// @param amount Amount of ERC20 token to grant allowance for. function _approveCall(address token, address spender, uint256 amount) private { // Unlimited approval is not security issue since the contract does not store any ERC20 token. (bool success, ) = token.call( abi.encodeWithSelector(IERC20.approve.selector, spender, amount) ); if (!success) revert ApprovalFailed(); } /// @notice Transfer token in a safe way wether it is ERC20 or native. /// @param token Address of the ERC20 token to be transfered. /// 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE in case of native token. /// @param to Address that will receive the tokens. /// @param amount Amount of ERC20 or native tokens to transfer. function smartTransfer(address token, address payable to, uint256 amount) internal { if (token == nativeToken) { to.sendValue(amount); } else { IERC20(token).safeTransfer(to, amount); } } /// @notice Make sure required service is available on current network by checking if an address /// have been provided for it. Revert transaction otherwise. /// @param service Address of the service to be checked. function checkServiceAvailability(address service) internal pure { if (service == address(0)) revert ServiceUnavailable(); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IPermit2} from "../interfaces/uniswap/IPermit2.sol"; abstract contract SquidPermit2 { // Type hashes required for witness encoding for permit2 in SquidRouter. bytes32 public constant FUND_AND_RUN_MULTICALL_DATA_TYPEHASH = keccak256("FundAndRunMulticallData(bytes32 hashedCalls)"); bytes32 public constant CCTP_BRIDGE_DATA_TYPEHASH = keccak256( "CCTPBridgeData(uint32 destinationDomain,bytes32 destinationAddress,bytes32 destinationCaller)" ); // Witness type strings required for witness encoding for permit2 in SquidRouter. string public constant FUND_AND_RUN_MULTICALL_WITNESS_TYPE_STRING = "FundAndRunMulticallData witness)FundAndRunMulticallData(bytes32 hashedCalls)TokenPermissions(address token,uint256 amount)"; string public constant CCTP_BRIDGE_WITNESS_TYPE_STRING = "CCTPBridgeData witness)CCTPBridgeData(uint32 destinationDomain,bytes32 destinationAddress,bytes32 destinationCaller)TokenPermissions(address token,uint256 amount)"; IPermit2 public immutable permit2; /// @notice Thrown when a function using permit2 protocol is called why it is not available on current network. error Permit2Unavailable(); /// @notice Thrown when a transferFrom2 call does not either have regular ERC20 or permit2 allowance. error TransferFailed(); /// @notice Thrown when a value greater than type(uint160).max is cast to uint160. error UnsafeCast(); /// @param _permit2 Address of the relevant Uniswap's Permit2.sol contract deployment /// Can be zero address if permit2 is not available on current network. constructor(address _permit2) { permit2 = IPermit2(_permit2); } /// @notice Check if permit2 is available on current network and revert otherwise. modifier onlyIfPermit2Available() { if (address(permit2) == address(0)) revert Permit2Unavailable(); _; } /// @notice Try to transferFrom tokens with regular ERC20 allowance, and falls back to permit2 allowance /// if not. /// @param token Address of the ERC20 token to be collected. /// @param from Address of the holder of the funds to be collected. /// @param to Address of the receiver of the funds to be collected. /// @param amount Amount of ERC20 token to be collected. function _transferFrom2(address token, address from, address to, uint256 amount) internal { // Generate calldata for a standard transferFrom call. bytes memory inputData = abi.encodeCall(IERC20.transferFrom, (from, to, amount)); bool success; // Call the token contract as normal, capturing whether it succeeded. assembly { success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0), 1), iszero(returndatasize())), // Counterintuitively, this call() must be positioned after the or() in the // surrounding and() because and() evaluates its arguments from right to left. // We use 0 and 32 to copy up to 32 bytes of return data into the first slot of scratch space. call(gas(), token, 0, add(inputData, 32), mload(inputData), 0, 32) ) } // We'll fall back to using Permit2 if calling transferFrom on the token directly reverted. if (!success) { // Revert transfer if Permit2 is not available. if (address(permit2) == address(0)) revert TransferFailed(); permit2.transferFrom(from, to, _toUint160(amount), address(token)); } } /// @notice Safely casts uint256 to uint160. /// @param value The uint256 to be cast. /// @return Casted uint160 value. function _toUint160(uint256 value) private pure returns (uint160) { if (value > type(uint160).max) revert UnsafeCast(); return uint160(value); } }
{ "optimizer": { "enabled": true, "runs": 99999 }, "viaIR": true, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_squidMulticall","type":"address"},{"internalType":"address","name":"_permit2","type":"address"},{"internalType":"address","name":"_axelarGateway","type":"address"},{"internalType":"address","name":"_interchainTokenService","type":"address"},{"internalType":"address","name":"_chainflipVault","type":"address"},{"internalType":"address","name":"_usdc","type":"address"},{"internalType":"address","name":"_cctpTokenMessenger","type":"address"},{"internalType":"address","name":"_axelarGasService","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyExecuted","type":"error"},{"inputs":[],"name":"ApprovalFailed","type":"error"},{"inputs":[],"name":"ContractIsPaused","type":"error"},{"inputs":[],"name":"ExpressExecutorAlreadySet","type":"error"},{"inputs":[],"name":"InsufficientValue","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidCodeHash","type":"error"},{"inputs":[],"name":"InvalidImplementation","type":"error"},{"inputs":[],"name":"InvalidOwner","type":"error"},{"inputs":[],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"NotApprovedByGateway","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"NotProxy","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"NotService","type":"error"},{"inputs":[],"name":"OnlyCfVault","type":"error"},{"inputs":[],"name":"OnlyPauser","type":"error"},{"inputs":[],"name":"OnlyPendingPauser","type":"error"},{"inputs":[],"name":"Permit2Unavailable","type":"error"},{"inputs":[],"name":"ServiceUnavailable","type":"error"},{"inputs":[],"name":"SetupFailed","type":"error"},{"inputs":[],"name":"TokenTransferFailed","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"UnsafeCast","type":"error"},{"inputs":[],"name":"ZeroAddressProvided","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"payloadHash","type":"bytes32"}],"name":"CrossMulticallExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"payloadHash","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"reason","type":"bytes"},{"indexed":true,"internalType":"address","name":"refundRecipient","type":"address"}],"name":"CrossMulticallFailed","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":"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":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"expressExecutor","type":"address"}],"name":"ExpressExecutedWithToken","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":"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":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"expressExecutor","type":"address"}],"name":"ExpressExecutionWithTokenFulfilled","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":[],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"currentPauser","type":"address"},{"indexed":true,"internalType":"address","name":"pendingPauser","type":"address"}],"name":"PauserProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newPauser","type":"address"}],"name":"PauserUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newImplementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"CCTP_BRIDGE_DATA_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CCTP_BRIDGE_WITNESS_TYPE_STRING","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FUND_AND_RUN_MULTICALL_DATA_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FUND_AND_RUN_MULTICALL_WITNESS_TYPE_STRING","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptPauser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"approveCctpTokenMessenger","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"axelarGasService","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"bridgedTokenSymbol","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"destinationChain","type":"string"},{"internalType":"string","name":"destinationAddress","type":"string"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"address","name":"gasRefundRecipient","type":"address"},{"internalType":"bool","name":"enableExpress","type":"bool"}],"name":"bridgeCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"internalType":"enum ISquidMulticall.CallType","name":"callType","type":"uint8"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct ISquidMulticall.Call[]","name":"calls","type":"tuple[]"},{"internalType":"string","name":"bridgedTokenSymbol","type":"string"},{"internalType":"string","name":"destinationChain","type":"string"},{"internalType":"string","name":"destinationAddress","type":"string"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"address","name":"gasRefundRecipient","type":"address"},{"internalType":"bool","name":"enableExpress","type":"bool"}],"name":"callBridgeCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint32","name":"destinationDomain","type":"uint32"},{"internalType":"bytes32","name":"destinationAddress","type":"bytes32"},{"internalType":"bytes32","name":"destinationCaller","type":"bytes32"}],"name":"cctpBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cctpTokenMessenger","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"cfReceive","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"chainflipVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractId","outputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"stateMutability":"pure","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":"bytes","name":"sourceAddress","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"executeWithInterchainToken","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"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"},{"internalType":"string","name":"tokenSymbol","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"executeWithToken","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":[{"internalType":"bytes32","name":"commandId","type":"bytes32"},{"internalType":"string","name":"sourceChain","type":"string"},{"internalType":"bytes","name":"sourceAddress","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"expressExecuteWithInterchainToken","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"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"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"expressExecuteWithToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"internalType":"enum ISquidMulticall.CallType","name":"callType","type":"uint8"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct ISquidMulticall.Call[]","name":"calls","type":"tuple[]"}],"name":"fundAndRunMulticall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"gateway","outputs":[{"internalType":"contract IAxelarGateway","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":"bytes32","name":"commandId","type":"bytes32"},{"internalType":"string","name":"sourceChain","type":"string"},{"internalType":"string","name":"sourceAddress","type":"string"},{"internalType":"bytes32","name":"payloadHash","type":"bytes32"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getExpressExecutorWithToken","outputs":[{"internalType":"address","name":"expressExecutor","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"implementation_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interchainTokenService","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"owner_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"value","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauser","outputs":[{"internalType":"address","name":"value","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"owner_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingPauser","outputs":[{"internalType":"address","name":"value","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permit2","outputs":[{"internalType":"contract IPermit2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"destinationDomain","type":"uint32"},{"internalType":"bytes32","name":"destinationAddress","type":"bytes32"},{"internalType":"bytes32","name":"destinationCaller","type":"bytes32"},{"internalType":"address","name":"from","type":"address"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IPermit2.TokenPermissions","name":"permitted","type":"tuple"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IPermit2.PermitTransferFrom","name":"permit","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"permitCctpBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"enum ISquidMulticall.CallType","name":"callType","type":"uint8"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct ISquidMulticall.Call[]","name":"calls","type":"tuple[]"},{"internalType":"address","name":"from","type":"address"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IPermit2.TokenPermissions","name":"permitted","type":"tuple"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IPermit2.PermitTransferFrom","name":"permit","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"permitFundAndRunMulticall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"proposeOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address payable","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescueFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"squidMulticall","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPauser","type":"address"}],"name":"updatePauser","outputs":[],"stateMutability":"nonpayable","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"},{"inputs":[],"name":"usdc","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101a0346200032957620051b838819003601f8101601f191683016001600160401b038111848210176200032e57839282916040528339610100928391810103126200032957620000508162000344565b6200005e6020830162000344565b916200006d6040820162000344565b916200007c6060830162000344565b906200008b6080840162000344565b946200009a60a0850162000344565b92620000b760e0620000af60c0880162000344565b960162000344565b956001600160a01b03908116801562000317576080528160a052806040519360017f04dba622d284ed0014ee4b9a6a68386be1a4c08a4913ae272de89199cc686163600080a260017f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c05560007f9855384122b55936fbfb8ca5120e63c6537a1ac40caf6ae33502b3c5da8c87d1553060c0521660e052337f23e06a2ed150be3aaebbce1156aecc5187e5e955ea717a17e165cca37ef8c37955337fa4336c0cb1e245b95ad204faed7e940d6dc999684fd8b5e1ff597a0c4efca8ab600080a2808416159182156200030b575b508115620002ff575b50620002f05750855261012093845261014090815261016091825261018092835260405193614e5e95866200035a873960805186818161083001528181610a4b015281816111980152818161167001528181612e05015281816136240152818161380c015281816139f00152613dc6015260a05186818161034701528181610e0201526119b9015260c05186611f4c015260e05186818161052c0152818161089f01528181612a6c0152613b820152518581816105540152818161140801528181611496015281816115380152818161375b015281816138840152818161430c01526144360152518481816110340152611966015251838181610ed6015281816126ff015281816128cc0152612b7f015251828181611e4d015281816126b50152818161287f0152612a9501525181818161128601528181613e5c0152613f040152f35b638474420160e01b8152600490fd5b905085161538620001ac565b811615915038620001a3565b60405163e6c4247b60e01b8152600490fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b0382168203620003295756fe6080604052600436101561001257600080fd5b60003560e01c806309c6bed9146102e757806310816d95146102e2578063116191b6146102dd57806312261ee7146102d8578063167a6f90146102d35780631a98b2e0146102ce57806321477960146102c957806329241502146102c45780633e413bee146102bf5780633f4ba83a146102ba5780634904ac5f146102b557806349160658146102b0578063545614cc146102ab578063554bab3c146102a657806358181a80146102a157806359ce62e91461029c5780635c60da1b146102975780635c975abb14610292578063656576361461028d5780636ccae05414610288578063710bf322146102835780637766d1ed1461027e57806377c790251461027957806379ba50971461027457806379ba68501461026f5780638291286c1461026a5780638456cb5914610265578063846a1bc614610260578063868a166d1461025b5780638da5cb5b146102565780639748cf7c146102515780639a7165e41461024c5780639ded06df146102475780639fd0506d14610242578063a3499c731461023d578063a376d15b14610238578063a9e756ce14610233578063b45e7ffb1461022e578063c3b3960d14610229578063c7e6a3cc14610224578063d9a004bb1461021f578063e30c39781461021a578063e4a974cc14610215578063e6778129146102105763f2fde38b1461020b57600080fd5b6130d1565b613097565b612ddb565b612d6a565b6129b4565b612918565b6127db565b61264e565b6125f5565b6125a7565b61205c565b611feb565b611ee2565b611e71565b611e02565b611d91565b611cc7565b611be8565b611b65565b611b0c565b611ab3565b611a12565b61198a565b61191b565b611824565b611766565b61162a565b6115cd565b61155c565b6114ed565b61134e565b6112aa565b61123b565b611118565b610fa2565b610efa565b610e8b565b610dd3565b610c80565b610a16565b6108c3565b610854565b6107e5565b61046f565b6102fc565b60009103126102f757565b600080fd5b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b9181601f840112156102f75782359167ffffffffffffffff83116102f7576020808501948460051b0101116102f757565b73ffffffffffffffffffffffffffffffffffffffff8116036102f757565b60a435906103c78261039c565b565b600435906103c78261039c565b60e435906103c78261039c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc60809101126102f757604490565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c60809101126102f757608490565b9181601f840112156102f75782359167ffffffffffffffff83116102f757602083818601950101116102f757565b60e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75767ffffffffffffffff600480358281116102f7576104ba903690830161036b565b9092602435906104c98261039c565b6104d2366103e3565b9060c4359081116102f7576104ea9036908601610441565b7fa42f2cf999e26109eb49cb7eef3654cc55b677b2db805f3eab8722cc5dd1af0c939193546107bc5773ffffffffffffffffffffffffffffffffffffffff93847f0000000000000000000000000000000000000000000000000000000000000000168015610793577f00000000000000000000000000000000000000000000000000000000000000009461057c612443565b73ffffffffffffffffffffffffffffffffffffffff871681529260208201356020850152338887161460001461068357823b156102f757896105f06000968793604051998a98899788967f30f28b7a0000000000000000000000000000000000000000000000000000000088528701613433565b03925af1801561066b57610670575b505b16803b156102f75761064493600093604051958694859384937ff87ef800000000000000000000000000000000000000000000000000000000008552840161322c565b039134905af1801561066b5761065657005b8061066361066992612395565b806102ec565b005b613427565b8061066361067d92612395565b386105ff565b60405160208101816106968c8f8461322c565b03916106c87fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093848101835282612402565b51902090610719604051918261070d6020820195869190602060408401937f56b4cec75df39b61d8ed17899d3c73074060d969d0c9e51b342fa7afa2f3423b81520152565b03908101835282612402565b51902061072461248a565b90843b156102f75760009687938d9361076b936040519b8c9a8b998a987f137c29fe000000000000000000000000000000000000000000000000000000008a5289016133a5565b03925af1801561066b57610780575b50610601565b8061066361078d92612395565b3861077a565b876040517fdd2732e2000000000000000000000000000000000000000000000000000000008152fd5b856040517f6d39fcd0000000000000000000000000000000000000000000000000000000008152fd5b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102f7576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261096b577fe330cfee289e568e8774e923acd6e2a00f84be86aa1d02356835d33dbb93970273ffffffffffffffffffffffffffffffffffffffff815416330361094157819061093d3361390f565b5580f35b60046040517f86291239000000000000000000000000000000000000000000000000000000008152fd5b80fd5b9060c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8301126102f7576004359167ffffffffffffffff906024358281116102f757816109be91600401610441565b939093926044358181116102f757836109d991600401610441565b939093926064358381116102f757826109f491600401610441565b939093926084359182116102f757610a0e91600401610441565b909160a43590565b346102f757610a243661096e565b829587839994988b949986859d899f8b819b3690610a419261349b565b80519060200120977f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169e8f958a8a604051998a9889987f1876eed9000000000000000000000000000000000000000000000000000000008a5260048a0198610abe996134e7565b03815a602094600091f190811561066b57600091610c2c575b5015610c0257610aee8b8b8a8686868b8b8e613970565b9b73ffffffffffffffffffffffffffffffffffffffff8d16978815610bed575050938a93610b528b8a610b8a9f9d9b99967fdb3db9dfc9262f4fe09dbadef104f799d8181ec565e09275d80ed3355aab68d39660209e9c9a60405197889788613535565b0390a46040518097819482937f935b13f60000000000000000000000000000000000000000000000000000000084526004840161358a565b03915afa92831561066b576106699373ffffffffffffffffffffffffffffffffffffffff91600091610bbe575b5016613a4c565b610be0915060203d602011610be6575b610bd88183612402565b810190613575565b38610bb7565b503d610bce565b97509798505050505050506106699550613993565b60046040517f500c44b4000000000000000000000000000000000000000000000000000000008152fd5b610c4e915060203d602011610c54575b610c468183612402565b8101906134d2565b38610ad7565b503d610c3c565b801515036102f757565b60c435906103c782610c5b565b61010435906103c782610c5b565b60e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75767ffffffffffffffff6004358181116102f757610ccb903690600401610441565b906044358381116102f757610ce4903690600401610441565b906064358581116102f757610cfd903690600401610441565b906084359687116102f757610d19610669973690600401610441565b949093610d246103ba565b96610d2d610c65565b986024359161359b565b60e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126102f7576004359167ffffffffffffffff6024358181116102f75783610d8591600401610441565b939093926044358381116102f75782610da091600401610441565b939093926064359182116102f757610dba91600401610441565b90916084359060a435610dcc8161039c565b9060c43590565b346102f757610de136610d37565b9750955050925094505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163303610e5b57610e31936148ab565b60206040517fe84001f3dedacf7f9ddc370e9f09c26b37473e9e959ffdc4925f6fe33c9877e48152f35b60246040517f0d6c7be9000000000000000000000000000000000000000000000000000000008152336004820152fd5b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102f7576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261096b57610f32613fca565b807fa42f2cf999e26109eb49cb7eef3654cc55b677b2db805f3eab8722cc5dd1af0c557fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d169338180a180f35b6004359063ffffffff821682036102f757565b6024359063ffffffff821682036102f757565b60a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757610fd4610f7c565b5067ffffffffffffffff6024358181116102f757610ff6903690600401610441565b50506044359081116102f757611010903690600401610441565b9060643561101d8161039c565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633036110675761066992608435926142c1565b60046040517fdd86bb04000000000000000000000000000000000000000000000000000000008152fd5b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126102f7576004359167ffffffffffffffff6024358181116102f757836110df91600401610441565b939093926044358381116102f757826110fa91600401610441565b939093926064359182116102f75761111491600401610441565b9091565b346102f75761113561112936611091565b9691949296369161349b565b602081519101209473ffffffffffffffffffffffffffffffffffffffff83602084886111918b8a8860405197889687967f5f6970c300000000000000000000000000000000000000000000000000000000885260048801613690565b03816000867f0000000000000000000000000000000000000000000000000000000000000000165af190811561066b5760009161121c575b5015610c02576111dd87868487878b614460565b16958615610669577f8fe61b2d4701a29265508750790e322b2c214399abdf98472158b8908b660d419461121792604051958695866136c1565b0390a3005b611235915060203d602011610c5457610c468183612402565b386111c9565b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102f75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75773ffffffffffffffffffffffffffffffffffffffff6004356112fa8161039c565b611302613fca565b807fe330cfee289e568e8774e923acd6e2a00f84be86aa1d02356835d33dbb9397025516337f3210edd3f0fc490ffc59a4adae6f48dbda2d8e89afe5b37a0145a54762f3ecf9600080a3005b600060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261096b576004356113868161039c565b60443567ffffffffffffffff8111611488576113a690369060040161036b565b7fa42f2cf999e26109eb49cb7eef3654cc55b677b2db805f3eab8722cc5dd1af0c929192546114c357839173ffffffffffffffffffffffffffffffffffffffff9073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8282160361148c575b507f000000000000000000000000000000000000000000000000000000000000000016803b1561148857611468936040518095819482937ff87ef8000000000000000000000000000000000000000000000000000000000084526004840161322c565b039134905af1801561066b5761147c575080f35b61148590612395565b80f35b8280fd5b6114bd90602435907f0000000000000000000000000000000000000000000000000000000000000000903390613ad8565b38611405565b60046040517f6d39fcd0000000000000000000000000000000000000000000000000000000008152fd5b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760207f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760207fa42f2cf999e26109eb49cb7eef3654cc55b677b2db805f3eab8722cc5dd1af0c546040519015158152f35b61163336611091565b6040517fd26ff2100000000000000000000000000000000000000000000000000000000081526004810188905291969594929392916020816024817f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff165afa90811561066b5760009161173c575b5061171257610669966116ca91369161349b565b6020815191012093604051867f6e18757e81c44a367109cbaa499add16f2ae7168aab9715c3cdc36b0f7ccce923392806117088a8a8a8a8a866136c1565b0390a3339561446e565b60046040517f0dc10197000000000000000000000000000000000000000000000000000000008152fd5b611755915060203d602011610c5457610c468183612402565b386116b6565b35906103c78261039c565b346102f75760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f7576004356117a18161039c565b602435906117ae8261039c565b7f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c05473ffffffffffffffffffffffffffffffffffffffff339116036117fa5761066991604435916144c5565b60046040517f30cd7471000000000000000000000000000000000000000000000000000000008152fd5b346102f75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760043561185f8161039c565b7f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c05473ffffffffffffffffffffffffffffffffffffffff9081339116036117fa57811680156118f1577fd9be0e8e07417e00f2521db636cb53e316fd288f5051f16d2aa2bf0c3938a876600080a27f9855384122b55936fbfb8ca5120e63c6537a1ac40caf6ae33502b3c5da8c87d155005b60046040517fd924e5f4000000000000000000000000000000000000000000000000000000008152fd5b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102f75761199836610d37565b9750955050925094505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163303610e5b576119e8936148ab565b60206040517f692b2deb10f974787eb65450ba9a90dc0bb28141a633fa3fb556d5292fba42e18152f35b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f7577f9855384122b55936fbfb8ca5120e63c6537a1ac40caf6ae33502b3c5da8c87d1543373ffffffffffffffffffffffffffffffffffffffff821603611a89576106699061460d565b60046040517f49e27cff000000000000000000000000000000000000000000000000000000008152fd5b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760206040517fc12702232f029df5a278a7d28216e7b7292ca74f2638269ebed149478b3210178152f35b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760206040517fc097d45e5a99ca772ab5ec2e5457c2e249760944b95b0b97cbb6b03ec55bae848152f35b346102f7576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261096b57611b9d613fca565b60017fa42f2cf999e26109eb49cb7eef3654cc55b677b2db805f3eab8722cc5dd1af0c557f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e7528180a180f35b6101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757611c1b6103c9565b67ffffffffffffffff906044358281116102f757611c3d90369060040161036b565b6064358481116102f757611c55903690600401610441565b6084929192358681116102f757611c70903690600401610441565b60a4929192358881116102f757611c8b903690600401610441565b93909260c435998a116102f757611ca96106699a3690600401610441565b979096611cb46103d6565b99611cbd610c72565b9b602435906136eb565b346102f75760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75767ffffffffffffffff6024358181116102f757611d17903690600401610441565b6044929192358281116102f757611d32903690600401610441565b906084359384116102f757611d8d94611d52611d65953690600401610441565b93909260a4359560643593600435614697565b5460405173ffffffffffffffffffffffffffffffffffffffff90911681529081906020820190565b0390f35b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760207f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c05473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760207fe330cfee289e568e8774e923acd6e2a00f84be86aa1d02356835d33dbb9397025473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b346102f75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760043567ffffffffffffffff81116102f757611f31903690600401610441565b9073ffffffffffffffffffffffffffffffffffffffff9130837f00000000000000000000000000000000000000000000000000000000000000001614611fc15781602091810103126102f75735611f878161039c565b168015611f97576106699061390f565b60046040517f84744201000000000000000000000000000000000000000000000000000000008152fd5b60046040517fbf10dd3a000000000000000000000000000000000000000000000000000000008152fd5b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760207f23e06a2ed150be3aaebbce1156aecc5187e5e955ea717a17e165cca37ef8c3795473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b346102f75760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757600480356120988161039c565b60443567ffffffffffffffff81116102f7576120b79036908401610441565b7f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c09291925473ffffffffffffffffffffffffffffffffffffffff90813391160361233d578216916040938451937f8291286c000000000000000000000000000000000000000000000000000000009485815260209586828a81865afa91821561066b5760009261231e575b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc91876121a0612187855473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1690565b928b8b518095819382525afa91821561066b576000926122ef575b50036122c757833f6024350361229f578390558551907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a2836121fd57005b612265816122396000979688978301957f9ded06df0000000000000000000000000000000000000000000000000000000087526024840161358a565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282612402565b51915af46122716138bf565b501561227957005b517f97905dfb000000000000000000000000000000000000000000000000000000008152fd5b8787517f8f84fb24000000000000000000000000000000000000000000000000000000008152fd5b8787517f68155f9a000000000000000000000000000000000000000000000000000000008152fd5b612310919250883d8a11612317575b6123088183612402565b8101906138b0565b90386121bb565b503d6122fe565b612336919250873d8911612317576123088183612402565b9038612142565b846040517f30cd7471000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff81116123a957604052565b612366565b60a0810190811067ffffffffffffffff8211176123a957604052565b6040810190811067ffffffffffffffff8211176123a957604052565b6080810190811067ffffffffffffffff8211176123a957604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176123a957604052565b604051906103c7826123ca565b67ffffffffffffffff81116123a957601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60405190612497826123ae565b607a82527f7265737320746f6b656e2c75696e7432353620616d6f756e74290000000000006080837f46756e64416e6452756e4d756c746963616c6c44617461207769746e6573732960208201527f46756e64416e6452756e4d756c746963616c6c4461746128627974657333322060408201527f68617368656443616c6c7329546f6b656e5065726d697373696f6e732861646460608201520152565b919082519283825260005b84811061257f5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b602081830181015184830182015201612540565b9060206125a4928181520190612535565b90565b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757611d8d6125e161248a565b604051918291602083526020830190612535565b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760206040517f56b4cec75df39b61d8ed17899d3c73074060d969d0c9e51b342fa7afa2f3423b8152f35b346102f75760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757600435612688610f8f565b90606435917fa42f2cf999e26109eb49cb7eef3654cc55b677b2db805f3eab8722cc5dd1af0c546114c3577f00000000000000000000000000000000000000000000000000000000000000006126dd81614755565b8315611f9757602092600073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000009461272b84303389613ad8565b6127a2604051988997889687947ff856ddb60000000000000000000000000000000000000000000000000000000086526044359160048701919360809363ffffffff73ffffffffffffffffffffffffffffffffffffffff9398979660a0860199865216602085015260408401521660608201520152565b0393165af1801561066b576127b357005b6106699060203d6020116127d4575b6127cc8183612402565b8101906138ef565b503d6127c2565b346102f7576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261096b577f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c05473ffffffffffffffffffffffffffffffffffffffff9081339116036117fa57602082916044604051809481937f095ea7b3000000000000000000000000000000000000000000000000000000008352807f00000000000000000000000000000000000000000000000000000000000000001660048401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248401527f0000000000000000000000000000000000000000000000000000000000000000165af1801561066b576128fc575080f35b6129149060203d602011610c5457610c468183612402565b5080f35b346102f75760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75767ffffffffffffffff6024358181116102f757612968903690600401610441565b91906044359182116102f757602092612988612995933690600401610441565b916064359360043561479c565b5473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b346102f7576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f7576129ec610f7c565b606435906044356024356129ff8461039c565b612a0836610412565b610104359367ffffffffffffffff85116102f757612a2b60049536908701610441565b96907fa42f2cf999e26109eb49cb7eef3654cc55b677b2db805f3eab8722cc5dd1af0c54612d415773ffffffffffffffffffffffffffffffffffffffff90817f000000000000000000000000000000000000000000000000000000000000000016988915612d18577f000000000000000000000000000000000000000000000000000000000000000095612abe87614755565b8815612cef5760209a818c8093013594888b8d612ad9612443565b308152968981890152338b8d1614600014612c1a5750505050823b156102f7578c612b3660009687936040519b8c98899788967f30f28b7a0000000000000000000000000000000000000000000000000000000088528701613433565b03925af1801561066b578997600094612be092612c07575b505b604051998a98899788957ff856ddb60000000000000000000000000000000000000000000000000000000087527f0000000000000000000000000000000000000000000000000000000000000000938701919360809363ffffffff73ffffffffffffffffffffffffffffffffffffffff9398979660a0860199865216602085015260408401521660608201520152565b0393165af1801561066b57612bf157005b8161066992903d106127d4576127cc8183612402565b80610663612c1492612395565b38612b4e565b604080517fc12702232f029df5a278a7d28216e7b7292ca74f2638269ebed149478b32101792810192835263ffffffff9095166020830152810192909252606082015290612c6b8160808401612239565b519020612c76612f8f565b90843b156102f7576000968f92938894612cbe936040519d8e9a8b998a987f137c29fe000000000000000000000000000000000000000000000000000000008a5289016133a5565b03925af1801561066b578997600094612be092612cdc575b50612b50565b80610663612ce992612395565b38612cd6565b896040517f84744201000000000000000000000000000000000000000000000000000000008152fd5b886040517fdd2732e2000000000000000000000000000000000000000000000000000000008152fd5b866040517f6d39fcd0000000000000000000000000000000000000000000000000000000008152fd5b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760207f9855384122b55936fbfb8ca5120e63c6537a1ac40caf6ae33502b3c5da8c87d15473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b612de43661096e565b979195909698929473ffffffffffffffffffffffffffffffffffffffff91827f000000000000000000000000000000000000000000000000000000000000000016946040517fd26ff21000000000000000000000000000000000000000000000000000000000815260208180612e6285600483019190602083019252565b03818a5afa90811561066b57600091612f70575b50611712576040517f935b13f60000000000000000000000000000000000000000000000000000000081529560209087908180612eb78f8f6004840161358a565b03915afa91821561066b578a8a8d976106699f9689948d988d612f429d60009a612f47575b50612eed90612f389a9b369161349b565b6020815191012093604051888a7f5844b8bbe3fd2b0354e73f27bfde28d2e6d991f14139c382876ec4360391a47b339380612f2e8d8d8d8d8d8d8d88613535565b0390a43398614832565b3091339116614843565b613993565b612f389a5090612f68612eed9260203d602011610be657610bd88183612402565b9a5090612edc565b612f89915060203d602011610c5457610c468183612402565b38612e76565b6040519060e0820182811067ffffffffffffffff8211176123a95760405260a282527f742900000000000000000000000000000000000000000000000000000000000060c0837f4343545042726964676544617461207769746e6573732943435450427269646760208201527f65446174612875696e7433322064657374696e6174696f6e446f6d61696e2c6260408201527f7974657333322064657374696e6174696f6e416464726573732c62797465733360608201527f322064657374696e6174696f6e43616c6c657229546f6b656e5065726d69737360808201527f696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e60a08201520152565b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757611d8d6125e1612f8f565b346102f75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760043561310c8161039c565b7f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c05473ffffffffffffffffffffffffffffffffffffffff339116036117fa576106699061460d565b359060048210156102f757565b90600482101561316e5752565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1823603018112156102f757016020813591019167ffffffffffffffff82116102f75781360383136102f757565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0938186528686013760008582860101520116010190565b6020928084830185845252604093604083019260408360051b8201019585600080935b8685106132625750505050505050505090565b9091929394959697987fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc082820301895289357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff618536030181121561335f578761334e600193878394019061333060a06132e3836132de86613154565b613161565b73ffffffffffffffffffffffffffffffffffffffff868501356133058161039c565b16868401528b8401358c840152606090806133228387018761319d565b9290938601528401916131ed565b916133406080918281019061319d565b9290918185039101526131ed565b9b019901979695019392919061324f565b8380fd5b6060809173ffffffffffffffffffffffffffffffffffffffff81356133878161039c565b16845260208101356020850152604081013560408501520135910152565b959373ffffffffffffffffffffffffffffffffffffffff613418946133fe6125a49a98956133d68b61014097613363565b805173ffffffffffffffffffffffffffffffffffffffff1660808c01526020015160a08b0152565b1660c088015260e087015280610100870152850190612535565b926101208185039101526131ed565b6040513d6000823e3d90fd5b90916125a4959361348873ffffffffffffffffffffffffffffffffffffffff926134608561010097613363565b805173ffffffffffffffffffffffffffffffffffffffff1660808601526020015160a0850152565b1660c08201528160e082015201916131ed565b9291926134a782612450565b916134b56040519384612402565b8294818452818301116102f7578281602093846000960137010152565b908160209103126102f757516125a481610c5b565b99989793909461350f61351d9360a0999560c08e6135309b9a815281602082015201916131ed565b918b830360408d01526131ed565b92606089015287830360808901526131ed565b930152565b9290936135546125a498969795613562946080875260808701916131ed565b9184830360208601526131ed565b93604082015260608185039101526131ed565b908160209103126102f757516125a48161039c565b9160206125a49381815201916131ed565b999897969594939291907fa42f2cf999e26109eb49cb7eef3654cc55b677b2db805f3eab8722cc5dd1af0c546114c3576040519a7f935b13f6000000000000000000000000000000000000000000000000000000008c52602060048d015260208c8061360b6024820186866131ed565b038173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa92831561066b576103c79c60009461366b575b5061366690303386613ad8565b613d48565b6136669194506136899060203d602011610be657610bd88183612402565b9390613659565b9695949060609492613530946136b3928a52608060208b015260808a01916131ed565b9187830360408901526131ed565b9594936136dd604094926135309460608a5260608a01916131ed565b9187830360208901526131ed565b9c9b9a99989796959492907fa42f2cf999e26109eb49cb7eef3654cc55b677b2db805f3eab8722cc5dd1af0c546114c357600073ffffffffffffffffffffffffffffffffffffffff9e8f811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1460001461387b575050905b8d7f000000000000000000000000000000000000000000000000000000000000000016803b156102f7576137be936000936040518096819582947ff87ef8000000000000000000000000000000000000000000000000000000000084526004840161322c565b03925af1801561066b57613868575b506020604051809c7f935b13f6000000000000000000000000000000000000000000000000000000008252818061380886886004840161358a565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa91821561066b576103c79b600093613847575b50613d48565b61386191935060203d602011610be657610bd88183612402565b9138613841565b8061066361387592612395565b386137cd565b916138ab9193927f0000000000000000000000000000000000000000000000000000000000000000903390613ad8565b613758565b908160209103126102f7575190565b3d156138ea573d906138d082612450565b916138de6040519384612402565b82523d6000602084013e565b606090565b908160209103126102f7575167ffffffffffffffff811681036102f75790565b73ffffffffffffffffffffffffffffffffffffffff90807f23e06a2ed150be3aaebbce1156aecc5187e5e955ea717a17e165cca37ef8c37955167fa4336c0cb1e245b95ad204faed7e940d6dc999684fd8b5e1ff597a0c4efca8ab600080a2565b906139819897969594939291614697565b908154918261398d5750565b60009055565b916020906139d7959460405196879283927f935b13f600000000000000000000000000000000000000000000000000000000845285600485015260248401916131ed565b038173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa91821561066b576103c794600093613a2b575b506148ab565b613a4591935060203d602011610be657610bd88183612402565b9138613a25565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000602082015273ffffffffffffffffffffffffffffffffffffffff909216602483015260448201929092526103c791613ad382606481015b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101845283612402565b6148f8565b9260405192613b5f6020808601957f23b872dd000000000000000000000000000000000000000000000000000000008752613b478161223987878a6024850160409194939294606082019573ffffffffffffffffffffffffffffffffffffffff80921683521660208201520152565b60009687915190828a5af185516001143d1517161590565b613b6b575b5050505050565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016918215613c4c57613bb29061499f565b92823b15613c48576040517f36c7851600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152918116602483015292831660448201529390911660648401528290608490829084905af1801561066b57613c35575b80808080613b64565b80610663613c4292612395565b38613c2c565b8480fd5b60046040517f90b8ec18000000000000000000000000000000000000000000000000000000008152fd5b999b9a9796939298959491909873ffffffffffffffffffffffffffffffffffffffff809a168b5260208b0160e0905260e08b0190613cb3926131ed565b9089820360408b0152613cc5926131ed565b908782036060890152613cd7926131ed565b908582036080870152613ce9926131ed565b9460a0840152169060c00152565b99989793613d3a93613d2c91613d1e613530999460809b99968f60a09081815201916131ed565b8d810360208f0152916131ed565b918a830360408c01526131ed565b9187830360608901526131ed565b6040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152969a909995989297949692959394939073ffffffffffffffffffffffffffffffffffffffff90602085602481858e165afa94851561066b57600095613fa7575b5090849147613e51575b50613ded92507f00000000000000000000000000000000000000000000000000000000000000001680996149ea565b863b156102f7576000988995613e33946040519c8d9b8c9a8b997fb5417084000000000000000000000000000000000000000000000000000000008b5260048b01613cf7565b03925af1801561066b57613e445750565b806106636103c792612395565b90915015613f0157807f0000000000000000000000000000000000000000000000000000000000000000169147833b156102f7578d938a8d928f613ed06000968b8f8f948f918e926040519e8f9c8d9b8c9a7f2e9b7470000000000000000000000000000000000000000000000000000000008c523060048d01613c76565b03925af190811561066b57613ded928592613eee575b505b38613dbe565b80610663613efb92612395565b38613ee6565b807f0000000000000000000000000000000000000000000000000000000000000000169147833b156102f7578d938a8d928f613f786000968b8f8f948f918e926040519e8f9c8d9b8c9a7fc62c2002000000000000000000000000000000000000000000000000000000008c523060048d01613c76565b03925af190811561066b57613ded928592613f94575b50613ee8565b80610663613fa192612395565b38613f8e565b613fc29192955060203d602011612317576123088183612402565b939038613db4565b73ffffffffffffffffffffffffffffffffffffffff7f23e06a2ed150be3aaebbce1156aecc5187e5e955ea717a17e165cca37ef8c3795416330361400a57565b60046040517f75df51dc000000000000000000000000000000000000000000000000000000008152fd5b9080601f830112156102f7578160206125a49335910161349b565b906060828203126102f75781359067ffffffffffffffff82116102f75780601f8385010112156102f757818301359167ffffffffffffffff83116123a9578260051b91604051936140a36020850186612402565b84526020840190806020858589010101116102f757602083870101915b602085858901010183106140e85750505050509160406140e26020840161175b565b92013590565b823567ffffffffffffffff81116102f75760a0807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe083888c0101860301126102f7578592899161414a6020858760405196614142886123ae565b010101613154565b8352604084868d0101013561415e8161039c565b6020840152938a018301606081013560408401526080949067ffffffffffffffff90860135116102f75761419e86898d0186018088013501602001614034565b606084015283888c010101359167ffffffffffffffff83116102f7576020946141d387878097968f978d839901010101614034565b9082015281520193019290506140c0565b6020808201908083528351809252604092604081018260408560051b8401019601946000925b85841061421b575050505050505090565b9091929394959685806142b0837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030188528b5161429d60a0614263848451613161565b73ffffffffffffffffffffffffffffffffffffffff868401511686850152898301518a850152606090808285015192860152840190612535565b9160808092015191818403910152612535565b99019401940192959493919061420a565b929091926142d18382018261404f565b5093909273ffffffffffffffffffffffffffffffffffffffff9373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85881603614430575b847f000000000000000000000000000000000000000000000000000000000000000016803b156102f75761436e9160009160405180809581947ff87ef800000000000000000000000000000000000000000000000000000000008352600483016141e4565b039134905af1908161441d575b506143df57916143c1916143ba7fdd7b1484db8d21f4fbda2407f2920037dc379dd66e18b0851aa9d6c14ef493b99594876143b46138bf565b996144c5565b369161349b565b60208151910120926143da604051928392169582612593565b0390a3565b506143ef9450369350915061349b565b602081519101207f7c3aa10c5d96985be6de7d2e6fa79bdef95a95a9cb272f4113b3fe1ca89fedae600080a2565b8061066361442a92612395565b3861437b565b61445b827f0000000000000000000000000000000000000000000000000000000000000000896149ea565b614309565b90613981959493929161479c565b9061447c959493929161479c565b73ffffffffffffffffffffffffffffffffffffffff81541661449b5755565b60046040517f725f13f1000000000000000000000000000000000000000000000000000000008152fd5b90919073ffffffffffffffffffffffffffffffffffffffff90811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee810361460157508147106145a357600092839283928392165af16145176138bf565b501561451f57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152fd5b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152fd5b906103c7931690614b23565b73ffffffffffffffffffffffffffffffffffffffff811680156118f1577f04dba622d284ed0014ee4b9a6a68386be1a4c08a4913ae272de89199cc686163600080a27f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c05560007f9855384122b55936fbfb8ca5120e63c6537a1ac40caf6ae33502b3c5da8c87d155565b97939592969096949194604051978896602088019a7febf4535caee8019297b7be3ed867db0d00b69fedcdda98c5e2c41ea6e41a98d58c5260408901526060880160e090526101008801906146eb926131ed565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09788888303016080890152614720926131ed565b9160a0860152858583030160c0860152614739926131ed565b9060e083015203908101825261474f9082612402565b51902090565b73ffffffffffffffffffffffffffffffffffffffff161561477257565b60046040517fef2827d0000000000000000000000000000000000000000000000000000000008152fd5b9461482061474f949392956147ee604051978895602087019a7f2a41fec9a0df4e0996b975f71622c7164b0f652ea69d9dbcd6b24e81b20ab5e58c52604088015260a0606088015260c08701916131ed565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe095868684030160808701526131ed565b9060a083015203908101835282612402565b9061447c9897969594939291614697565b6040517f23b872dd00000000000000000000000000000000000000000000000000000000602082015273ffffffffffffffffffffffffffffffffffffffff928316602482015292909116604483015260648201929092526103c791613ad38260848101613aa7565b929190604081036148ef5783604091810103126102f7576103c792356148d08161039c565b73ffffffffffffffffffffffffffffffffffffffff8091169116614b23565b6103c7936142c1565b600073ffffffffffffffffffffffffffffffffffffffff8192169260208151910182855af16149256138bf565b81614970575b5015908115614966575b5061493c57565b60046040517f045c4b02000000000000000000000000000000000000000000000000000000008152fd5b90503b1538614935565b8051801592508215614985575b50503861492b565b61499892506020809183010191016134d2565b388061497d565b73ffffffffffffffffffffffffffffffffffffffff908181116149c0571690565b60046040517fc4bd89a9000000000000000000000000000000000000000000000000000000008152fd5b9173ffffffffffffffffffffffffffffffffffffffff90604051907fdd62ed3e0000000000000000000000000000000000000000000000000000000082523060048301526020826044818688169687602483015289165afa91821561066b57600092614b02575b508110614a5f575b50505050565b614a77575b50614a6e91614ccc565b38808080614a59565b6000809160405160208101917f095ea7b3000000000000000000000000000000000000000000000000000000008352602482015282604482015260448152614abe816123e6565b519082865af1614acc6138bf565b5015614ad85738614a64565b60046040517f8164f842000000000000000000000000000000000000000000000000000000008152fd5b614b1c91925060203d602011612317576123088183612402565b9038614a51565b614c179160008073ffffffffffffffffffffffffffffffffffffffff60405194614bcc86614ba060209a8b8301987fa9059cbb000000000000000000000000000000000000000000000000000000008a52602484016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101885287612402565b169260405194614bdb866123ca565b8786527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656488870152519082855af1614c116138bf565b91614d60565b805190828215928315614cb4575b50505015614c305750565b608490604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b614cc493508201810191016134d2565b388281614c25565b6000919082918260405173ffffffffffffffffffffffffffffffffffffffff60208201937f095ea7b30000000000000000000000000000000000000000000000000000000085521660248201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff604482015260448152614d4c816123e6565b51925af1614d586138bf565b5015614ad857565b91929015614ddb5750815115614d74575090565b3b15614d7d5790565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b825190915015614dee5750805190602001fd5b614e24906040519182917f08c379a000000000000000000000000000000000000000000000000000000000835260048301612593565b0390fdfea26469706673582212208a0262d645ddad635fe584dac63acd7e0fbf4f1c58aefc2da4cd8c019de4546264736f6c63430008170033000000000000000000000000ad6cea45f98444a922a2b4fe96b8c90f0862d2f4000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3000000000000000000000000e432150cce91c13a887f7d836923d5597add8e31000000000000000000000000b5fb4be02232b1bba4dc8f81dc24c26980de9e3c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ceba9300f2b948710d2653dd7b07f33a8b32118c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000002d5d7d31f671f86c782533cc367f14109a082712
Deployed Bytecode
0x6080604052600436101561001257600080fd5b60003560e01c806309c6bed9146102e757806310816d95146102e2578063116191b6146102dd57806312261ee7146102d8578063167a6f90146102d35780631a98b2e0146102ce57806321477960146102c957806329241502146102c45780633e413bee146102bf5780633f4ba83a146102ba5780634904ac5f146102b557806349160658146102b0578063545614cc146102ab578063554bab3c146102a657806358181a80146102a157806359ce62e91461029c5780635c60da1b146102975780635c975abb14610292578063656576361461028d5780636ccae05414610288578063710bf322146102835780637766d1ed1461027e57806377c790251461027957806379ba50971461027457806379ba68501461026f5780638291286c1461026a5780638456cb5914610265578063846a1bc614610260578063868a166d1461025b5780638da5cb5b146102565780639748cf7c146102515780639a7165e41461024c5780639ded06df146102475780639fd0506d14610242578063a3499c731461023d578063a376d15b14610238578063a9e756ce14610233578063b45e7ffb1461022e578063c3b3960d14610229578063c7e6a3cc14610224578063d9a004bb1461021f578063e30c39781461021a578063e4a974cc14610215578063e6778129146102105763f2fde38b1461020b57600080fd5b6130d1565b613097565b612ddb565b612d6a565b6129b4565b612918565b6127db565b61264e565b6125f5565b6125a7565b61205c565b611feb565b611ee2565b611e71565b611e02565b611d91565b611cc7565b611be8565b611b65565b611b0c565b611ab3565b611a12565b61198a565b61191b565b611824565b611766565b61162a565b6115cd565b61155c565b6114ed565b61134e565b6112aa565b61123b565b611118565b610fa2565b610efa565b610e8b565b610dd3565b610c80565b610a16565b6108c3565b610854565b6107e5565b61046f565b6102fc565b60009103126102f757565b600080fd5b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000b5fb4be02232b1bba4dc8f81dc24c26980de9e3c168152f35b9181601f840112156102f75782359167ffffffffffffffff83116102f7576020808501948460051b0101116102f757565b73ffffffffffffffffffffffffffffffffffffffff8116036102f757565b60a435906103c78261039c565b565b600435906103c78261039c565b60e435906103c78261039c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc60809101126102f757604490565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c60809101126102f757608490565b9181601f840112156102f75782359167ffffffffffffffff83116102f757602083818601950101116102f757565b60e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75767ffffffffffffffff600480358281116102f7576104ba903690830161036b565b9092602435906104c98261039c565b6104d2366103e3565b9060c4359081116102f7576104ea9036908601610441565b7fa42f2cf999e26109eb49cb7eef3654cc55b677b2db805f3eab8722cc5dd1af0c939193546107bc5773ffffffffffffffffffffffffffffffffffffffff93847f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3168015610793577f000000000000000000000000ad6cea45f98444a922a2b4fe96b8c90f0862d2f49461057c612443565b73ffffffffffffffffffffffffffffffffffffffff871681529260208201356020850152338887161460001461068357823b156102f757896105f06000968793604051998a98899788967f30f28b7a0000000000000000000000000000000000000000000000000000000088528701613433565b03925af1801561066b57610670575b505b16803b156102f75761064493600093604051958694859384937ff87ef800000000000000000000000000000000000000000000000000000000008552840161322c565b039134905af1801561066b5761065657005b8061066361066992612395565b806102ec565b005b613427565b8061066361067d92612395565b386105ff565b60405160208101816106968c8f8461322c565b03916106c87fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093848101835282612402565b51902090610719604051918261070d6020820195869190602060408401937f56b4cec75df39b61d8ed17899d3c73074060d969d0c9e51b342fa7afa2f3423b81520152565b03908101835282612402565b51902061072461248a565b90843b156102f75760009687938d9361076b936040519b8c9a8b998a987f137c29fe000000000000000000000000000000000000000000000000000000008a5289016133a5565b03925af1801561066b57610780575b50610601565b8061066361078d92612395565b3861077a565b876040517fdd2732e2000000000000000000000000000000000000000000000000000000008152fd5b856040517f6d39fcd0000000000000000000000000000000000000000000000000000000008152fd5b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e432150cce91c13a887f7d836923d5597add8e31168152f35b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3168152f35b346102f7576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261096b577fe330cfee289e568e8774e923acd6e2a00f84be86aa1d02356835d33dbb93970273ffffffffffffffffffffffffffffffffffffffff815416330361094157819061093d3361390f565b5580f35b60046040517f86291239000000000000000000000000000000000000000000000000000000008152fd5b80fd5b9060c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8301126102f7576004359167ffffffffffffffff906024358281116102f757816109be91600401610441565b939093926044358181116102f757836109d991600401610441565b939093926064358381116102f757826109f491600401610441565b939093926084359182116102f757610a0e91600401610441565b909160a43590565b346102f757610a243661096e565b829587839994988b949986859d899f8b819b3690610a419261349b565b80519060200120977f000000000000000000000000e432150cce91c13a887f7d836923d5597add8e3173ffffffffffffffffffffffffffffffffffffffff169e8f958a8a604051998a9889987f1876eed9000000000000000000000000000000000000000000000000000000008a5260048a0198610abe996134e7565b03815a602094600091f190811561066b57600091610c2c575b5015610c0257610aee8b8b8a8686868b8b8e613970565b9b73ffffffffffffffffffffffffffffffffffffffff8d16978815610bed575050938a93610b528b8a610b8a9f9d9b99967fdb3db9dfc9262f4fe09dbadef104f799d8181ec565e09275d80ed3355aab68d39660209e9c9a60405197889788613535565b0390a46040518097819482937f935b13f60000000000000000000000000000000000000000000000000000000084526004840161358a565b03915afa92831561066b576106699373ffffffffffffffffffffffffffffffffffffffff91600091610bbe575b5016613a4c565b610be0915060203d602011610be6575b610bd88183612402565b810190613575565b38610bb7565b503d610bce565b97509798505050505050506106699550613993565b60046040517f500c44b4000000000000000000000000000000000000000000000000000000008152fd5b610c4e915060203d602011610c54575b610c468183612402565b8101906134d2565b38610ad7565b503d610c3c565b801515036102f757565b60c435906103c782610c5b565b61010435906103c782610c5b565b60e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75767ffffffffffffffff6004358181116102f757610ccb903690600401610441565b906044358381116102f757610ce4903690600401610441565b906064358581116102f757610cfd903690600401610441565b906084359687116102f757610d19610669973690600401610441565b949093610d246103ba565b96610d2d610c65565b986024359161359b565b60e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126102f7576004359167ffffffffffffffff6024358181116102f75783610d8591600401610441565b939093926044358381116102f75782610da091600401610441565b939093926064359182116102f757610dba91600401610441565b90916084359060a435610dcc8161039c565b9060c43590565b346102f757610de136610d37565b9750955050925094505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000b5fb4be02232b1bba4dc8f81dc24c26980de9e3c163303610e5b57610e31936148ab565b60206040517fe84001f3dedacf7f9ddc370e9f09c26b37473e9e959ffdc4925f6fe33c9877e48152f35b60246040517f0d6c7be9000000000000000000000000000000000000000000000000000000008152336004820152fd5b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ceba9300f2b948710d2653dd7b07f33a8b32118c168152f35b346102f7576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261096b57610f32613fca565b807fa42f2cf999e26109eb49cb7eef3654cc55b677b2db805f3eab8722cc5dd1af0c557fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d169338180a180f35b6004359063ffffffff821682036102f757565b6024359063ffffffff821682036102f757565b60a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757610fd4610f7c565b5067ffffffffffffffff6024358181116102f757610ff6903690600401610441565b50506044359081116102f757611010903690600401610441565b9060643561101d8161039c565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633036110675761066992608435926142c1565b60046040517fdd86bb04000000000000000000000000000000000000000000000000000000008152fd5b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126102f7576004359167ffffffffffffffff6024358181116102f757836110df91600401610441565b939093926044358381116102f757826110fa91600401610441565b939093926064359182116102f75761111491600401610441565b9091565b346102f75761113561112936611091565b9691949296369161349b565b602081519101209473ffffffffffffffffffffffffffffffffffffffff83602084886111918b8a8860405197889687967f5f6970c300000000000000000000000000000000000000000000000000000000885260048801613690565b03816000867f000000000000000000000000e432150cce91c13a887f7d836923d5597add8e31165af190811561066b5760009161121c575b5015610c02576111dd87868487878b614460565b16958615610669577f8fe61b2d4701a29265508750790e322b2c214399abdf98472158b8908b660d419461121792604051958695866136c1565b0390a3005b611235915060203d602011610c5457610c468183612402565b386111c9565b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002d5d7d31f671f86c782533cc367f14109a082712168152f35b346102f75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75773ffffffffffffffffffffffffffffffffffffffff6004356112fa8161039c565b611302613fca565b807fe330cfee289e568e8774e923acd6e2a00f84be86aa1d02356835d33dbb9397025516337f3210edd3f0fc490ffc59a4adae6f48dbda2d8e89afe5b37a0145a54762f3ecf9600080a3005b600060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261096b576004356113868161039c565b60443567ffffffffffffffff8111611488576113a690369060040161036b565b7fa42f2cf999e26109eb49cb7eef3654cc55b677b2db805f3eab8722cc5dd1af0c929192546114c357839173ffffffffffffffffffffffffffffffffffffffff9073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8282160361148c575b507f000000000000000000000000ad6cea45f98444a922a2b4fe96b8c90f0862d2f416803b1561148857611468936040518095819482937ff87ef8000000000000000000000000000000000000000000000000000000000084526004840161322c565b039134905af1801561066b5761147c575080f35b61148590612395565b80f35b8280fd5b6114bd90602435907f000000000000000000000000ad6cea45f98444a922a2b4fe96b8c90f0862d2f4903390613ad8565b38611405565b60046040517f6d39fcd0000000000000000000000000000000000000000000000000000000008152fd5b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ad6cea45f98444a922a2b4fe96b8c90f0862d2f4168152f35b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760207f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760207fa42f2cf999e26109eb49cb7eef3654cc55b677b2db805f3eab8722cc5dd1af0c546040519015158152f35b61163336611091565b6040517fd26ff2100000000000000000000000000000000000000000000000000000000081526004810188905291969594929392916020816024817f000000000000000000000000e432150cce91c13a887f7d836923d5597add8e3173ffffffffffffffffffffffffffffffffffffffff165afa90811561066b5760009161173c575b5061171257610669966116ca91369161349b565b6020815191012093604051867f6e18757e81c44a367109cbaa499add16f2ae7168aab9715c3cdc36b0f7ccce923392806117088a8a8a8a8a866136c1565b0390a3339561446e565b60046040517f0dc10197000000000000000000000000000000000000000000000000000000008152fd5b611755915060203d602011610c5457610c468183612402565b386116b6565b35906103c78261039c565b346102f75760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f7576004356117a18161039c565b602435906117ae8261039c565b7f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c05473ffffffffffffffffffffffffffffffffffffffff339116036117fa5761066991604435916144c5565b60046040517f30cd7471000000000000000000000000000000000000000000000000000000008152fd5b346102f75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760043561185f8161039c565b7f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c05473ffffffffffffffffffffffffffffffffffffffff9081339116036117fa57811680156118f1577fd9be0e8e07417e00f2521db636cb53e316fd288f5051f16d2aa2bf0c3938a876600080a27f9855384122b55936fbfb8ca5120e63c6537a1ac40caf6ae33502b3c5da8c87d155005b60046040517fd924e5f4000000000000000000000000000000000000000000000000000000008152fd5b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102f75761199836610d37565b9750955050925094505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000b5fb4be02232b1bba4dc8f81dc24c26980de9e3c163303610e5b576119e8936148ab565b60206040517f692b2deb10f974787eb65450ba9a90dc0bb28141a633fa3fb556d5292fba42e18152f35b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f7577f9855384122b55936fbfb8ca5120e63c6537a1ac40caf6ae33502b3c5da8c87d1543373ffffffffffffffffffffffffffffffffffffffff821603611a89576106699061460d565b60046040517f49e27cff000000000000000000000000000000000000000000000000000000008152fd5b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760206040517fc12702232f029df5a278a7d28216e7b7292ca74f2638269ebed149478b3210178152f35b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760206040517fc097d45e5a99ca772ab5ec2e5457c2e249760944b95b0b97cbb6b03ec55bae848152f35b346102f7576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261096b57611b9d613fca565b60017fa42f2cf999e26109eb49cb7eef3654cc55b677b2db805f3eab8722cc5dd1af0c557f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e7528180a180f35b6101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757611c1b6103c9565b67ffffffffffffffff906044358281116102f757611c3d90369060040161036b565b6064358481116102f757611c55903690600401610441565b6084929192358681116102f757611c70903690600401610441565b60a4929192358881116102f757611c8b903690600401610441565b93909260c435998a116102f757611ca96106699a3690600401610441565b979096611cb46103d6565b99611cbd610c72565b9b602435906136eb565b346102f75760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75767ffffffffffffffff6024358181116102f757611d17903690600401610441565b6044929192358281116102f757611d32903690600401610441565b906084359384116102f757611d8d94611d52611d65953690600401610441565b93909260a4359560643593600435614697565b5460405173ffffffffffffffffffffffffffffffffffffffff90911681529081906020820190565b0390f35b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760207f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c05473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760207fe330cfee289e568e8774e923acd6e2a00f84be86aa1d02356835d33dbb9397025473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b346102f75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760043567ffffffffffffffff81116102f757611f31903690600401610441565b9073ffffffffffffffffffffffffffffffffffffffff9130837f000000000000000000000000f6b9d3c6f5c5e5a3a63b2a15b5362f99a51cf76d1614611fc15781602091810103126102f75735611f878161039c565b168015611f97576106699061390f565b60046040517f84744201000000000000000000000000000000000000000000000000000000008152fd5b60046040517fbf10dd3a000000000000000000000000000000000000000000000000000000008152fd5b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760207f23e06a2ed150be3aaebbce1156aecc5187e5e955ea717a17e165cca37ef8c3795473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b346102f75760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757600480356120988161039c565b60443567ffffffffffffffff81116102f7576120b79036908401610441565b7f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c09291925473ffffffffffffffffffffffffffffffffffffffff90813391160361233d578216916040938451937f8291286c000000000000000000000000000000000000000000000000000000009485815260209586828a81865afa91821561066b5760009261231e575b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc91876121a0612187855473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1690565b928b8b518095819382525afa91821561066b576000926122ef575b50036122c757833f6024350361229f578390558551907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a2836121fd57005b612265816122396000979688978301957f9ded06df0000000000000000000000000000000000000000000000000000000087526024840161358a565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282612402565b51915af46122716138bf565b501561227957005b517f97905dfb000000000000000000000000000000000000000000000000000000008152fd5b8787517f8f84fb24000000000000000000000000000000000000000000000000000000008152fd5b8787517f68155f9a000000000000000000000000000000000000000000000000000000008152fd5b612310919250883d8a11612317575b6123088183612402565b8101906138b0565b90386121bb565b503d6122fe565b612336919250873d8911612317576123088183612402565b9038612142565b846040517f30cd7471000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff81116123a957604052565b612366565b60a0810190811067ffffffffffffffff8211176123a957604052565b6040810190811067ffffffffffffffff8211176123a957604052565b6080810190811067ffffffffffffffff8211176123a957604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176123a957604052565b604051906103c7826123ca565b67ffffffffffffffff81116123a957601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60405190612497826123ae565b607a82527f7265737320746f6b656e2c75696e7432353620616d6f756e74290000000000006080837f46756e64416e6452756e4d756c746963616c6c44617461207769746e6573732960208201527f46756e64416e6452756e4d756c746963616c6c4461746128627974657333322060408201527f68617368656443616c6c7329546f6b656e5065726d697373696f6e732861646460608201520152565b919082519283825260005b84811061257f5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b602081830181015184830182015201612540565b9060206125a4928181520190612535565b90565b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757611d8d6125e161248a565b604051918291602083526020830190612535565b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760206040517f56b4cec75df39b61d8ed17899d3c73074060d969d0c9e51b342fa7afa2f3423b8152f35b346102f75760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757600435612688610f8f565b90606435917fa42f2cf999e26109eb49cb7eef3654cc55b677b2db805f3eab8722cc5dd1af0c546114c3577f00000000000000000000000000000000000000000000000000000000000000006126dd81614755565b8315611f9757602092600073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ceba9300f2b948710d2653dd7b07f33a8b32118c9461272b84303389613ad8565b6127a2604051988997889687947ff856ddb60000000000000000000000000000000000000000000000000000000086526044359160048701919360809363ffffffff73ffffffffffffffffffffffffffffffffffffffff9398979660a0860199865216602085015260408401521660608201520152565b0393165af1801561066b576127b357005b6106699060203d6020116127d4575b6127cc8183612402565b8101906138ef565b503d6127c2565b346102f7576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261096b577f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c05473ffffffffffffffffffffffffffffffffffffffff9081339116036117fa57602082916044604051809481937f095ea7b3000000000000000000000000000000000000000000000000000000008352807f00000000000000000000000000000000000000000000000000000000000000001660048401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248401527f000000000000000000000000ceba9300f2b948710d2653dd7b07f33a8b32118c165af1801561066b576128fc575080f35b6129149060203d602011610c5457610c468183612402565b5080f35b346102f75760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75767ffffffffffffffff6024358181116102f757612968903690600401610441565b91906044359182116102f757602092612988612995933690600401610441565b916064359360043561479c565b5473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b346102f7576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f7576129ec610f7c565b606435906044356024356129ff8461039c565b612a0836610412565b610104359367ffffffffffffffff85116102f757612a2b60049536908701610441565b96907fa42f2cf999e26109eb49cb7eef3654cc55b677b2db805f3eab8722cc5dd1af0c54612d415773ffffffffffffffffffffffffffffffffffffffff90817f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba316988915612d18577f000000000000000000000000000000000000000000000000000000000000000095612abe87614755565b8815612cef5760209a818c8093013594888b8d612ad9612443565b308152968981890152338b8d1614600014612c1a5750505050823b156102f7578c612b3660009687936040519b8c98899788967f30f28b7a0000000000000000000000000000000000000000000000000000000088528701613433565b03925af1801561066b578997600094612be092612c07575b505b604051998a98899788957ff856ddb60000000000000000000000000000000000000000000000000000000087527f000000000000000000000000ceba9300f2b948710d2653dd7b07f33a8b32118c938701919360809363ffffffff73ffffffffffffffffffffffffffffffffffffffff9398979660a0860199865216602085015260408401521660608201520152565b0393165af1801561066b57612bf157005b8161066992903d106127d4576127cc8183612402565b80610663612c1492612395565b38612b4e565b604080517fc12702232f029df5a278a7d28216e7b7292ca74f2638269ebed149478b32101792810192835263ffffffff9095166020830152810192909252606082015290612c6b8160808401612239565b519020612c76612f8f565b90843b156102f7576000968f92938894612cbe936040519d8e9a8b998a987f137c29fe000000000000000000000000000000000000000000000000000000008a5289016133a5565b03925af1801561066b578997600094612be092612cdc575b50612b50565b80610663612ce992612395565b38612cd6565b896040517f84744201000000000000000000000000000000000000000000000000000000008152fd5b886040517fdd2732e2000000000000000000000000000000000000000000000000000000008152fd5b866040517f6d39fcd0000000000000000000000000000000000000000000000000000000008152fd5b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760207f9855384122b55936fbfb8ca5120e63c6537a1ac40caf6ae33502b3c5da8c87d15473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b612de43661096e565b979195909698929473ffffffffffffffffffffffffffffffffffffffff91827f000000000000000000000000e432150cce91c13a887f7d836923d5597add8e3116946040517fd26ff21000000000000000000000000000000000000000000000000000000000815260208180612e6285600483019190602083019252565b03818a5afa90811561066b57600091612f70575b50611712576040517f935b13f60000000000000000000000000000000000000000000000000000000081529560209087908180612eb78f8f6004840161358a565b03915afa91821561066b578a8a8d976106699f9689948d988d612f429d60009a612f47575b50612eed90612f389a9b369161349b565b6020815191012093604051888a7f5844b8bbe3fd2b0354e73f27bfde28d2e6d991f14139c382876ec4360391a47b339380612f2e8d8d8d8d8d8d8d88613535565b0390a43398614832565b3091339116614843565b613993565b612f389a5090612f68612eed9260203d602011610be657610bd88183612402565b9a5090612edc565b612f89915060203d602011610c5457610c468183612402565b38612e76565b6040519060e0820182811067ffffffffffffffff8211176123a95760405260a282527f742900000000000000000000000000000000000000000000000000000000000060c0837f4343545042726964676544617461207769746e6573732943435450427269646760208201527f65446174612875696e7433322064657374696e6174696f6e446f6d61696e2c6260408201527f7974657333322064657374696e6174696f6e416464726573732c62797465733360608201527f322064657374696e6174696f6e43616c6c657229546f6b656e5065726d69737360808201527f696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e60a08201520152565b346102f75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f757611d8d6125e1612f8f565b346102f75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f75760043561310c8161039c565b7f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c05473ffffffffffffffffffffffffffffffffffffffff339116036117fa576106699061460d565b359060048210156102f757565b90600482101561316e5752565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1823603018112156102f757016020813591019167ffffffffffffffff82116102f75781360383136102f757565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0938186528686013760008582860101520116010190565b6020928084830185845252604093604083019260408360051b8201019585600080935b8685106132625750505050505050505090565b9091929394959697987fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc082820301895289357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff618536030181121561335f578761334e600193878394019061333060a06132e3836132de86613154565b613161565b73ffffffffffffffffffffffffffffffffffffffff868501356133058161039c565b16868401528b8401358c840152606090806133228387018761319d565b9290938601528401916131ed565b916133406080918281019061319d565b9290918185039101526131ed565b9b019901979695019392919061324f565b8380fd5b6060809173ffffffffffffffffffffffffffffffffffffffff81356133878161039c565b16845260208101356020850152604081013560408501520135910152565b959373ffffffffffffffffffffffffffffffffffffffff613418946133fe6125a49a98956133d68b61014097613363565b805173ffffffffffffffffffffffffffffffffffffffff1660808c01526020015160a08b0152565b1660c088015260e087015280610100870152850190612535565b926101208185039101526131ed565b6040513d6000823e3d90fd5b90916125a4959361348873ffffffffffffffffffffffffffffffffffffffff926134608561010097613363565b805173ffffffffffffffffffffffffffffffffffffffff1660808601526020015160a0850152565b1660c08201528160e082015201916131ed565b9291926134a782612450565b916134b56040519384612402565b8294818452818301116102f7578281602093846000960137010152565b908160209103126102f757516125a481610c5b565b99989793909461350f61351d9360a0999560c08e6135309b9a815281602082015201916131ed565b918b830360408d01526131ed565b92606089015287830360808901526131ed565b930152565b9290936135546125a498969795613562946080875260808701916131ed565b9184830360208601526131ed565b93604082015260608185039101526131ed565b908160209103126102f757516125a48161039c565b9160206125a49381815201916131ed565b999897969594939291907fa42f2cf999e26109eb49cb7eef3654cc55b677b2db805f3eab8722cc5dd1af0c546114c3576040519a7f935b13f6000000000000000000000000000000000000000000000000000000008c52602060048d015260208c8061360b6024820186866131ed565b038173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e432150cce91c13a887f7d836923d5597add8e31165afa92831561066b576103c79c60009461366b575b5061366690303386613ad8565b613d48565b6136669194506136899060203d602011610be657610bd88183612402565b9390613659565b9695949060609492613530946136b3928a52608060208b015260808a01916131ed565b9187830360408901526131ed565b9594936136dd604094926135309460608a5260608a01916131ed565b9187830360208901526131ed565b9c9b9a99989796959492907fa42f2cf999e26109eb49cb7eef3654cc55b677b2db805f3eab8722cc5dd1af0c546114c357600073ffffffffffffffffffffffffffffffffffffffff9e8f811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1460001461387b575050905b8d7f000000000000000000000000ad6cea45f98444a922a2b4fe96b8c90f0862d2f416803b156102f7576137be936000936040518096819582947ff87ef8000000000000000000000000000000000000000000000000000000000084526004840161322c565b03925af1801561066b57613868575b506020604051809c7f935b13f6000000000000000000000000000000000000000000000000000000008252818061380886886004840161358a565b03917f000000000000000000000000e432150cce91c13a887f7d836923d5597add8e31165afa91821561066b576103c79b600093613847575b50613d48565b61386191935060203d602011610be657610bd88183612402565b9138613841565b8061066361387592612395565b386137cd565b916138ab9193927f000000000000000000000000ad6cea45f98444a922a2b4fe96b8c90f0862d2f4903390613ad8565b613758565b908160209103126102f7575190565b3d156138ea573d906138d082612450565b916138de6040519384612402565b82523d6000602084013e565b606090565b908160209103126102f7575167ffffffffffffffff811681036102f75790565b73ffffffffffffffffffffffffffffffffffffffff90807f23e06a2ed150be3aaebbce1156aecc5187e5e955ea717a17e165cca37ef8c37955167fa4336c0cb1e245b95ad204faed7e940d6dc999684fd8b5e1ff597a0c4efca8ab600080a2565b906139819897969594939291614697565b908154918261398d5750565b60009055565b916020906139d7959460405196879283927f935b13f600000000000000000000000000000000000000000000000000000000845285600485015260248401916131ed565b038173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e432150cce91c13a887f7d836923d5597add8e31165afa91821561066b576103c794600093613a2b575b506148ab565b613a4591935060203d602011610be657610bd88183612402565b9138613a25565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000602082015273ffffffffffffffffffffffffffffffffffffffff909216602483015260448201929092526103c791613ad382606481015b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101845283612402565b6148f8565b9260405192613b5f6020808601957f23b872dd000000000000000000000000000000000000000000000000000000008752613b478161223987878a6024850160409194939294606082019573ffffffffffffffffffffffffffffffffffffffff80921683521660208201520152565b60009687915190828a5af185516001143d1517161590565b613b6b575b5050505050565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba316918215613c4c57613bb29061499f565b92823b15613c48576040517f36c7851600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152918116602483015292831660448201529390911660648401528290608490829084905af1801561066b57613c35575b80808080613b64565b80610663613c4292612395565b38613c2c565b8480fd5b60046040517f90b8ec18000000000000000000000000000000000000000000000000000000008152fd5b999b9a9796939298959491909873ffffffffffffffffffffffffffffffffffffffff809a168b5260208b0160e0905260e08b0190613cb3926131ed565b9089820360408b0152613cc5926131ed565b908782036060890152613cd7926131ed565b908582036080870152613ce9926131ed565b9460a0840152169060c00152565b99989793613d3a93613d2c91613d1e613530999460809b99968f60a09081815201916131ed565b8d810360208f0152916131ed565b918a830360408c01526131ed565b9187830360608901526131ed565b6040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152969a909995989297949692959394939073ffffffffffffffffffffffffffffffffffffffff90602085602481858e165afa94851561066b57600095613fa7575b5090849147613e51575b50613ded92507f000000000000000000000000e432150cce91c13a887f7d836923d5597add8e311680996149ea565b863b156102f7576000988995613e33946040519c8d9b8c9a8b997fb5417084000000000000000000000000000000000000000000000000000000008b5260048b01613cf7565b03925af1801561066b57613e445750565b806106636103c792612395565b90915015613f0157807f0000000000000000000000002d5d7d31f671f86c782533cc367f14109a082712169147833b156102f7578d938a8d928f613ed06000968b8f8f948f918e926040519e8f9c8d9b8c9a7f2e9b7470000000000000000000000000000000000000000000000000000000008c523060048d01613c76565b03925af190811561066b57613ded928592613eee575b505b38613dbe565b80610663613efb92612395565b38613ee6565b807f0000000000000000000000002d5d7d31f671f86c782533cc367f14109a082712169147833b156102f7578d938a8d928f613f786000968b8f8f948f918e926040519e8f9c8d9b8c9a7fc62c2002000000000000000000000000000000000000000000000000000000008c523060048d01613c76565b03925af190811561066b57613ded928592613f94575b50613ee8565b80610663613fa192612395565b38613f8e565b613fc29192955060203d602011612317576123088183612402565b939038613db4565b73ffffffffffffffffffffffffffffffffffffffff7f23e06a2ed150be3aaebbce1156aecc5187e5e955ea717a17e165cca37ef8c3795416330361400a57565b60046040517f75df51dc000000000000000000000000000000000000000000000000000000008152fd5b9080601f830112156102f7578160206125a49335910161349b565b906060828203126102f75781359067ffffffffffffffff82116102f75780601f8385010112156102f757818301359167ffffffffffffffff83116123a9578260051b91604051936140a36020850186612402565b84526020840190806020858589010101116102f757602083870101915b602085858901010183106140e85750505050509160406140e26020840161175b565b92013590565b823567ffffffffffffffff81116102f75760a0807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe083888c0101860301126102f7578592899161414a6020858760405196614142886123ae565b010101613154565b8352604084868d0101013561415e8161039c565b6020840152938a018301606081013560408401526080949067ffffffffffffffff90860135116102f75761419e86898d0186018088013501602001614034565b606084015283888c010101359167ffffffffffffffff83116102f7576020946141d387878097968f978d839901010101614034565b9082015281520193019290506140c0565b6020808201908083528351809252604092604081018260408560051b8401019601946000925b85841061421b575050505050505090565b9091929394959685806142b0837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030188528b5161429d60a0614263848451613161565b73ffffffffffffffffffffffffffffffffffffffff868401511686850152898301518a850152606090808285015192860152840190612535565b9160808092015191818403910152612535565b99019401940192959493919061420a565b929091926142d18382018261404f565b5093909273ffffffffffffffffffffffffffffffffffffffff9373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85881603614430575b847f000000000000000000000000ad6cea45f98444a922a2b4fe96b8c90f0862d2f416803b156102f75761436e9160009160405180809581947ff87ef800000000000000000000000000000000000000000000000000000000008352600483016141e4565b039134905af1908161441d575b506143df57916143c1916143ba7fdd7b1484db8d21f4fbda2407f2920037dc379dd66e18b0851aa9d6c14ef493b99594876143b46138bf565b996144c5565b369161349b565b60208151910120926143da604051928392169582612593565b0390a3565b506143ef9450369350915061349b565b602081519101207f7c3aa10c5d96985be6de7d2e6fa79bdef95a95a9cb272f4113b3fe1ca89fedae600080a2565b8061066361442a92612395565b3861437b565b61445b827f000000000000000000000000ad6cea45f98444a922a2b4fe96b8c90f0862d2f4896149ea565b614309565b90613981959493929161479c565b9061447c959493929161479c565b73ffffffffffffffffffffffffffffffffffffffff81541661449b5755565b60046040517f725f13f1000000000000000000000000000000000000000000000000000000008152fd5b90919073ffffffffffffffffffffffffffffffffffffffff90811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee810361460157508147106145a357600092839283928392165af16145176138bf565b501561451f57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152fd5b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152fd5b906103c7931690614b23565b73ffffffffffffffffffffffffffffffffffffffff811680156118f1577f04dba622d284ed0014ee4b9a6a68386be1a4c08a4913ae272de89199cc686163600080a27f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c05560007f9855384122b55936fbfb8ca5120e63c6537a1ac40caf6ae33502b3c5da8c87d155565b97939592969096949194604051978896602088019a7febf4535caee8019297b7be3ed867db0d00b69fedcdda98c5e2c41ea6e41a98d58c5260408901526060880160e090526101008801906146eb926131ed565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09788888303016080890152614720926131ed565b9160a0860152858583030160c0860152614739926131ed565b9060e083015203908101825261474f9082612402565b51902090565b73ffffffffffffffffffffffffffffffffffffffff161561477257565b60046040517fef2827d0000000000000000000000000000000000000000000000000000000008152fd5b9461482061474f949392956147ee604051978895602087019a7f2a41fec9a0df4e0996b975f71622c7164b0f652ea69d9dbcd6b24e81b20ab5e58c52604088015260a0606088015260c08701916131ed565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe095868684030160808701526131ed565b9060a083015203908101835282612402565b9061447c9897969594939291614697565b6040517f23b872dd00000000000000000000000000000000000000000000000000000000602082015273ffffffffffffffffffffffffffffffffffffffff928316602482015292909116604483015260648201929092526103c791613ad38260848101613aa7565b929190604081036148ef5783604091810103126102f7576103c792356148d08161039c565b73ffffffffffffffffffffffffffffffffffffffff8091169116614b23565b6103c7936142c1565b600073ffffffffffffffffffffffffffffffffffffffff8192169260208151910182855af16149256138bf565b81614970575b5015908115614966575b5061493c57565b60046040517f045c4b02000000000000000000000000000000000000000000000000000000008152fd5b90503b1538614935565b8051801592508215614985575b50503861492b565b61499892506020809183010191016134d2565b388061497d565b73ffffffffffffffffffffffffffffffffffffffff908181116149c0571690565b60046040517fc4bd89a9000000000000000000000000000000000000000000000000000000008152fd5b9173ffffffffffffffffffffffffffffffffffffffff90604051907fdd62ed3e0000000000000000000000000000000000000000000000000000000082523060048301526020826044818688169687602483015289165afa91821561066b57600092614b02575b508110614a5f575b50505050565b614a77575b50614a6e91614ccc565b38808080614a59565b6000809160405160208101917f095ea7b3000000000000000000000000000000000000000000000000000000008352602482015282604482015260448152614abe816123e6565b519082865af1614acc6138bf565b5015614ad85738614a64565b60046040517f8164f842000000000000000000000000000000000000000000000000000000008152fd5b614b1c91925060203d602011612317576123088183612402565b9038614a51565b614c179160008073ffffffffffffffffffffffffffffffffffffffff60405194614bcc86614ba060209a8b8301987fa9059cbb000000000000000000000000000000000000000000000000000000008a52602484016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101885287612402565b169260405194614bdb866123ca565b8786527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656488870152519082855af1614c116138bf565b91614d60565b805190828215928315614cb4575b50505015614c305750565b608490604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b614cc493508201810191016134d2565b388281614c25565b6000919082918260405173ffffffffffffffffffffffffffffffffffffffff60208201937f095ea7b30000000000000000000000000000000000000000000000000000000085521660248201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff604482015260448152614d4c816123e6565b51925af1614d586138bf565b5015614ad857565b91929015614ddb5750815115614d74575090565b3b15614d7d5790565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b825190915015614dee5750805190602001fd5b614e24906040519182917f08c379a000000000000000000000000000000000000000000000000000000000835260048301612593565b0390fdfea26469706673582212208a0262d645ddad635fe584dac63acd7e0fbf4f1c58aefc2da4cd8c019de4546264736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ad6cea45f98444a922a2b4fe96b8c90f0862d2f4000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3000000000000000000000000e432150cce91c13a887f7d836923d5597add8e31000000000000000000000000b5fb4be02232b1bba4dc8f81dc24c26980de9e3c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ceba9300f2b948710d2653dd7b07f33a8b32118c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000002d5d7d31f671f86c782533cc367f14109a082712
-----Decoded View---------------
Arg [0] : _squidMulticall (address): 0xaD6Cea45f98444a922a2b4fE96b8C90F0862D2F4
Arg [1] : _permit2 (address): 0x000000000022D473030F116dDEE9F6B43aC78BA3
Arg [2] : _axelarGateway (address): 0xe432150cce91c13a887f7D836923d5597adD8E31
Arg [3] : _interchainTokenService (address): 0xB5FB4BE02232B1bBA4dC8f81dc24C26980dE9e3C
Arg [4] : _chainflipVault (address): 0x0000000000000000000000000000000000000000
Arg [5] : _usdc (address): 0xcebA9300f2b948710d2653dD7B07f33A8B32118C
Arg [6] : _cctpTokenMessenger (address): 0x0000000000000000000000000000000000000000
Arg [7] : _axelarGasService (address): 0x2d5d7d31F671F86C782533cc367F14109a082712
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 000000000000000000000000ad6cea45f98444a922a2b4fe96b8c90f0862d2f4
Arg [1] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
Arg [2] : 000000000000000000000000e432150cce91c13a887f7d836923d5597add8e31
Arg [3] : 000000000000000000000000b5fb4be02232b1bba4dc8f81dc24c26980de9e3c
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 000000000000000000000000ceba9300f2b948710d2653dd7b07f33a8b32118c
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [7] : 0000000000000000000000002d5d7d31f671f86c782533cc367f14109a082712
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 29 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
[ 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.