Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Multichain Info
1 address found via
Latest 5 from a total of 5 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Send Message Pay... | 20713056 | 223 days ago | IN | 0.00027564 ETH | 0.00184528 | ||||
Send Message Pay... | 20713010 | 223 days ago | IN | 0.000012 ETH | 0.00110557 | ||||
Allowlist Sender | 20712968 | 223 days ago | IN | 0 ETH | 0.00017609 | ||||
Allowlist Source... | 20712964 | 223 days ago | IN | 0 ETH | 0.00018046 | ||||
Allowlist Destin... | 20712961 | 223 days ago | IN | 0 ETH | 0.00017381 |
Loading...
Loading
Contract Name:
CCIP
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 100 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import '@openzeppelin/contracts/access/Ownable2Step.sol'; import {IRouterClient} from '@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol'; import {Client} from '@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol'; import {CCIPReceiver} from '@chainlink/contracts-ccip/src/v0.8/ccip/applications/CCIPReceiver.sol'; import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; import '@openzeppelin/contracts/utils/structs/EnumerableMap.sol'; import '@openzeppelin/contracts/utils/ReentrancyGuard.sol'; interface IV3SwapRouter { struct ExactInputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; } function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); struct ExactInputParams { bytes path; address recipient; uint256 amountIn; uint256 amountOutMinimum; } function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); struct ExactOutputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 amountOut; uint256 amountInMaximum; uint160 sqrtPriceLimitX96; } function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn); struct ExactOutputParams { bytes path; address recipient; uint256 amountOut; uint256 amountInMaximum; } function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn); function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external; function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to ) external payable returns (uint256 amountOut); function swapTokensForExactTokens( uint256 amountOut, uint256 amountInMax, address[] calldata path, address to ) external payable returns (uint256 amountIn); function WETH9() external view returns (address); } interface IUniswapV2Router02 { function WETH() external pure returns (address); function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; function swapExactETHForTokensSupportingFeeOnTransferTokens( uint amountOutMin, address[] calldata path, address to, uint deadline ) external payable; function swapExactTokensForETHSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); } library Path { using BytesLib for bytes; /// @dev The length of the bytes encoded address uint256 private constant ADDR_SIZE = 20; /// @dev The length of the bytes encoded fee uint256 private constant FEE_SIZE = 3; /// @dev The offset of a single token address and pool fee uint256 private constant NEXT_OFFSET = ADDR_SIZE + FEE_SIZE; /// @dev The offset of an encoded pool key uint256 private constant POP_OFFSET = NEXT_OFFSET + ADDR_SIZE; /// @dev The minimum length of an encoding that contains 2 or more pools uint256 private constant MULTIPLE_POOLS_MIN_LENGTH = POP_OFFSET + NEXT_OFFSET; /// @notice Returns true iff the path contains two or more pools /// @param path The encoded swap path /// @return True if path contains two or more pools, otherwise false function hasMultiplePools(bytes memory path) internal pure returns (bool) { return path.length >= MULTIPLE_POOLS_MIN_LENGTH; } /// @notice Returns the number of pools in the path /// @param path The encoded swap path /// @return The number of pools in the path function numPools(bytes memory path) internal pure returns (uint256) { // Ignore the first token address. From then on every fee and token offset indicates a pool. return ((path.length - ADDR_SIZE) / NEXT_OFFSET); } /// @notice Decodes the first pool in path /// @param path The bytes encoded swap path /// @return tokenA The first token of the given pool /// @return tokenB The second token of the given pool /// @return fee The fee level of the pool function decodeFirstPool(bytes memory path) internal pure returns (address tokenA, address tokenB, uint24 fee) { tokenA = path.toAddress(0); fee = path.toUint24(ADDR_SIZE); tokenB = path.toAddress(NEXT_OFFSET); } /// @notice Gets the segment corresponding to the first pool in the path /// @param path The bytes encoded swap path /// @return The segment containing all data necessary to target the first pool in the path function getFirstPool(bytes memory path) internal pure returns (bytes memory) { return path.slice(0, POP_OFFSET); } /// @notice Skips a token + fee element from the buffer and returns the remainder /// @param path The swap path /// @return The remaining token + fee elements in the path function skipToken(bytes memory path) internal pure returns (bytes memory) { return path.slice(NEXT_OFFSET, path.length - NEXT_OFFSET); } } interface IWETH is IERC20 { function deposit() external payable; function withdraw(uint amount) external; } abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } } library BytesLib { function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) { require(_length + 31 >= _length, 'slice_overflow'); require(_start + _length >= _start, 'slice_overflow'); require(_bytes.length >= _start + _length, 'slice_outOfBounds'); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_start + 20 >= _start, 'toAddress_overflow'); require(_bytes.length >= _start + 20, 'toAddress_outOfBounds'); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint24(bytes memory _bytes, uint256 _start) internal pure returns (uint24) { require(_start + 3 >= _start, 'toUint24_overflow'); require(_bytes.length >= _start + 3, 'toUint24_outOfBounds'); uint24 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x3), _start)) } return tempUint; } } /// @title - A simple messenger contract for transferring/receiving tokens and data across chains. /// @dev - This example shows how to recover tokens in case of revert contract CCIP is CCIPReceiver, Ownable2Step, ReentrancyGuard { using EnumerableMap for EnumerableMap.Bytes32ToUintMap; using SafeERC20 for IERC20; using BytesLib for bytes; using Path for bytes; // Using Path library for bytes // Custom errors to provide more descriptive revert messages. error NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees); // Used to make sure contract has enough balance to cover the fees. error NothingToWithdraw(); // Used when trying to withdraw Ether but there's nothing to withdraw. error FailedToWithdrawEth(address owner, address target, uint256 value); // Used when the withdrawal of Ether fails. error DestinationChainNotAllowlisted(uint64 destinationChainSelector); // Used when the destination chain has not been allowlisted by the contract owner. error SourceChainNotAllowed(uint64 sourceChainSelector); // Used when the source chain has not been allowlisted by the contract owner. error SenderNotAllowed(address sender); // Used when the sender has not been allowlisted by the contract owner. error InvalidReceiverAddress(); // Used when the receiver address is 0. error OnlySelf(); // Used when a function is called outside of the contract itself. error MessageNotFailed(bytes32 messageId); error FailedCall(); // Used when transfer function is failed. error InvalidMessage(); // Example error code, could have many different error codes. enum ErrorCode { // RESOLVED is first so that the default value is resolved. RESOLVED, // Could have any number of error codes here. FAILED } struct FailedMessage { bytes32 messageId; ErrorCode errorCode; } struct FailedMessagesUsers { address token; address receiver; uint256 amount; bool isRedeemed; bytes32 messageId; } struct AddressNumber { address user; uint256 index; } // Event emitted when a message is sent to another chain. event MessageSent( bytes32 indexed messageId, // The unique ID of the CCIP message. uint64 indexed destinationChainSelector, // The chain selector of the destination chain. address receiver, // The address of the receiver on the destination chain. string text, // The text being sent. address token, // The token address that was transferred. uint256 tokenAmount, // The token amount that was transferred. address feeToken, // the token address used to pay CCIP fees. uint256 fees // The fees paid for sending the message. ); // Event emitted when a message is received from another chain. event MessageReceived( bytes32 indexed messageId, // The unique ID of the CCIP message. uint64 indexed sourceChainSelector, // The chain selector of the source chain. address finalToken, uint8 finalTokenDecimal, uint256 minAmountOut, bool withdrawETH, address sender, // The address of the sender from the source chain. address token, // The token address that was transferred. uint256 tokenAmount // The token amount that was transferred. ); event MessageFailed(bytes32 indexed messageId, bytes reason); event MessageRecovered(bytes32 indexed messageId); event TimeLockActivated(uint256 indexed time); event SwapFromUSDC( bytes32 indexed messageId, address indexed receiver, address indexed token, uint256 amountIn, uint256 time ); event ExecutorUpdated(address indexed oldExecutor, address indexed newExecutor); bytes32 private s_lastReceivedMessageId; // Store the last received messageId. address private s_lastReceivedTokenAddress; // Store the last received token address. uint256 private s_lastReceivedTokenAmount; // Store the last received amount. string private s_lastReceivedText; // Store the last received text. // Mapping to keep track of allowlisted destination chains. mapping(uint64 => bool) public allowlistedDestinationChains; // Mapping to keep track of allowlisted source chains. mapping(uint64 => bool) public allowlistedSourceChains; // Mapping to keep track of allowlisted senders. mapping(address => bool) public allowlistedSenders; IERC20 private immutable s_linkToken; address public immutable weth; address public immutable usdc; address public immutable paraRouter; // The message contents of failed messages are stored here. mapping(bytes32 messageId => SwapFromUSDCData contents) public s_messageContents; // User => FailedMessagesUsers[] mapping(address => FailedMessagesUsers[]) public failedMessagesUsers; // MessageId => (address, number) mapping(bytes32 => AddressNumber) public failedMessageByMessageId; // Contains failed messages and their state. EnumerableMap.Bytes32ToUintMap internal s_failedMessages; IV3SwapRouter public v3Router; IUniswapV2Router02 public v2Router; uint256 public swapFee; // Fee must be by 1000, so if you want 5% this will be 5000 address public feeReceiver; address public executor; uint256 public constant maxFee = 20000; // Max fee is 20% uint256 public constant feeBps = 1000; // 1000 is 1% so we can have many decimals uint256 public timeLockTime; /// @notice Constructor initializes the contract with the router address. /// @param _router The address of the router contract. /// @param _link The address of the link contract. constructor( address _router, address _link, address _usdc, address _weth, uint256 _swapFee, address _feeReceiver, address _owner, address _paraRouter, address _v2Router, address _v3Router, address _executor ) CCIPReceiver(_router) Ownable(_owner) { s_linkToken = IERC20(_link); usdc = _usdc; weth = _weth; swapFee = _swapFee; feeReceiver = _feeReceiver; paraRouter = _paraRouter; v2Router = IUniswapV2Router02(_v2Router); v3Router = IV3SwapRouter(_v3Router); executor = _executor; } modifier onlyExecutor() { require(msg.sender == executor, 'not executor'); _; } /// @dev Modifier that checks if the chain with the given destinationChainSelector is allowlisted. /// @param _destinationChainSelector The selector of the destination chain. modifier onlyAllowlistedDestinationChain(uint64 _destinationChainSelector) { if (!allowlistedDestinationChains[_destinationChainSelector]) revert DestinationChainNotAllowlisted(_destinationChainSelector); _; } /// @dev Modifier that checks if the chain with the given sourceChainSelector is allowlisted and if the sender is allowlisted. /// @param _sourceChainSelector The selector of the destination chain. /// @param _sender The address of the sender. modifier onlyAllowlisted(uint64 _sourceChainSelector, address _sender) { if (!allowlistedSourceChains[_sourceChainSelector]) revert SourceChainNotAllowed(_sourceChainSelector); if (!allowlistedSenders[_sender]) revert SenderNotAllowed(_sender); _; } /// @dev Modifier that checks the receiver address is not 0. /// @param _receiver The receiver address. modifier validateReceiver(address _receiver) { if (_receiver == address(0)) revert InvalidReceiverAddress(); _; } /// @dev Modifier to allow only the contract itself to execute a function. /// Throws an exception if called by any account other than the contract itself. modifier onlySelf() { if (msg.sender != address(this)) revert OnlySelf(); _; } function activateTimelock() external onlyOwner { timeLockTime = block.timestamp + 48 hours; emit TimeLockActivated(timeLockTime); } function transferOwnership(address newOwner) public override onlyOwner { require(timeLockTime > 0 && block.timestamp > timeLockTime, 'Timelocked'); timeLockTime = 0; // Reset it if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } function changeFeeAndAddress(uint256 _fee, address _feeReceiver) external onlyOwner { require(timeLockTime > 0 && block.timestamp > timeLockTime, 'Timelocked'); timeLockTime = 0; // Reset it require(_fee < maxFee, 'Max fee exceeded'); swapFee = _fee; feeReceiver = _feeReceiver; } function setExecutor(address _newExecutor) external onlyOwner { emit ExecutorUpdated(executor, _newExecutor); executor = _newExecutor; } function changeRouters(address _v2Router, address _v3Router) external onlyOwner { require(timeLockTime > 0 && block.timestamp > timeLockTime, 'Timelocked'); timeLockTime = 0; // Reset it v3Router = IV3SwapRouter(_v3Router); v2Router = IUniswapV2Router02(_v2Router); } /// @dev Updates the allowlist status of a destination chain for transactions. /// @notice This function can only be called by the owner. /// @param _destinationChainSelector The selector of the destination chain to be updated. /// @param allowed The allowlist status to be set for the destination chain. function allowlistDestinationChain(uint64 _destinationChainSelector, bool allowed) external onlyOwner { allowlistedDestinationChains[_destinationChainSelector] = allowed; } /// @dev Updates the allowlist status of a source chain /// @notice This function can only be called by the owner. /// @param _sourceChainSelector The selector of the source chain to be updated. /// @param allowed The allowlist status to be set for the source chain. function allowlistSourceChain(uint64 _sourceChainSelector, bool allowed) external onlyOwner { allowlistedSourceChains[_sourceChainSelector] = allowed; } /// @dev Updates the allowlist status of a sender for transactions. /// @notice This function can only be called by the owner. /// @param _sender The address of the sender to be updated. /// @param allowed The allowlist status to be set for the sender. function allowlistSender(address _sender, bool allowed) external onlyOwner { allowlistedSenders[_sender] = allowed; } /// @notice Refunds any excess LINK tokens to the sender. /// @dev This function calculates the difference between the remaining LINK balance and the fees, then transfers any excess back to the sender. /// @param fees The amount of LINK tokens used for the transaction fees. function refundExcessLink(uint256 fees) internal { uint256 remainingLinkBalance = s_linkToken.balanceOf(address(this)); uint256 excessLink = remainingLinkBalance - fees; if (excessLink > 0) { s_linkToken.transfer(msg.sender, excessLink); } } /// @notice Sends data and transfer tokens to receiver on the destination chain. /// @notice Pay for fees in native gas. /// @dev Assumes your contract has sufficient native gas like ETH on Ethereum or MATIC on Polygon. /// @param _destinationChainSelector The identifier (aka selector) for the destination blockchain. /// @param _receiver The address of the recipient on the destination blockchain. /// @param _text The string data to be sent. /// @param _token token address. /// @param _amount token amount. /// @return messageId The ID of the CCIP message that was sent. function sendMessagePayNative( uint64 _destinationChainSelector, address _receiver, string memory _text, address _token, uint256 _amount, uint256 _gasLimitReceiver ) internal onlyAllowlistedDestinationChain(_destinationChainSelector) validateReceiver(_receiver) returns (bytes32 messageId) { // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message // address(0) means fees are paid in native gas Client.EVM2AnyMessage memory evm2AnyMessage = _buildCCIPMessage( _receiver, _text, _token, _amount, address(0), _gasLimitReceiver ); // Initialize a router client instance to interact with cross-chain router IRouterClient router = IRouterClient(this.getRouter()); // Get the fee required to send the CCIP message uint256 fees = router.getFee(_destinationChainSelector, evm2AnyMessage); // Revert invalid message if the fee is zero if (fees == 0) revert InvalidMessage(); if (fees > address(this).balance) revert NotEnoughBalance(address(this).balance, fees); // approve the Router to spend tokens on contract's behalf. It will spend the amount of the given token checkAndApproveAll(_token, address(router), _amount); // Send the message through the router and store the returned message ID messageId = router.ccipSend{value: fees}(_destinationChainSelector, evm2AnyMessage); // payable(msg.sender).transfer(address(this).balance); // Refund the remaining msg.value (bool success, ) = msg.sender.call{value: address(this).balance}(''); if (!success) { revert FailedCall(); } // Emit an event with message details emit MessageSent(messageId, _destinationChainSelector, _receiver, _text, _token, _amount, address(0), fees); // Return the message ID return messageId; } /*** My functions ***/ struct ReceiverSwapData { address finalToken; uint8 finalTokenDecimal; uint256 minAmountOut; address userReceiver; bool withdrawETH; } struct InitialSwapData { bool srcTax; address tokenIn; // Token you're sending for a crosschain swap uint256 amountIn; // For the token you send uint256 minAmountOutV2Swap; uint256 minAmountOutV3Swap; bool swapTokenInV2First; bool withdrawWETH; // Users may want to use WETH directly instead of ETH bytes v3InitialSwap; bytes dataIn; } struct SwapFromUSDCData { bool isETH; bytes32 messageId; address outputToken; uint256 amountIn; uint256 minAmountOut; address to; bool withdrawETH; bytes dataOut; uint256 fee; } // All it does is encode the parameters and convert that bytes into string for the transfer and executes the right function /// swapTokenInV2First Is used to determine how we get USDC. USDC is always at V3, meaning we gotta go from token -v2 or v3-> ETH -v3-> USDC /* a. If the token is USDC we don't swap it at all and just send it b. If the token is a v2 token, swap it for weth first, then swap the weth for USDC (using _v3InitialSwap) c. If the token is a v3 token, swap it for weth and for USDC in the same router (using _v3InitialSwap) */ /** * @notice Extracts the last token address from a given Uniswap V3 path. * @param _path The bytes array representing the encoded Uniswap V3 swap path. * @return The address of the last token in the path. */ function getLastAddressPath(bytes memory _path) public pure returns (address) { // Get the number of pools in the path. Each pool represents a swap step. uint256 pools = _path.numPools(); // Declare a variable to store the last token address. address last; // Loop through each pool in the path to decode the tokens. for (uint256 i = 0; i < pools; i++) { // Decode the first pool in the path to get the output token of the pool. // The decodeFirstPool function returns the input token, fee, and output token. (, address tokenOut, ) = _path.decodeFirstPool(); // Update the last token address with the output token of the current pool. last = tokenOut; // Skip to the next pool in the path by removing the already decoded pool data. _path = _path.skipToken(); } // Return the last token address in the path. return last; } // Approves from this to the target contract unlimited tokens function checkAndApproveAll(address _token, address _target, uint256 _amountToCheck) internal { if (IERC20(_token).allowance(address(this), _target) < _amountToCheck) { IERC20(_token).forceApprove(_target, 0); IERC20(_token).forceApprove(_target, _amountToCheck); } } function swapInitialData(InitialSwapData memory _initialSwapData) internal returns (uint256 USDCOut) { if (_initialSwapData.tokenIn == usdc) { // Step a) USDCOut = _initialSwapData.amountIn; } else { if (_initialSwapData.srcTax) { // Step b) if (_initialSwapData.swapTokenInV2First) { require(_initialSwapData.tokenIn != weth, 'Token in must not be WETH'); checkAndApproveAll(_initialSwapData.tokenIn, address(v2Router), _initialSwapData.amountIn); // Swap ReceiverSwapData.finalToken to ETH via V2, then to USDC via uniswap V3 address[] memory path = new address[](2); path[0] = _initialSwapData.tokenIn; path[1] = weth; uint256 wethBalanceBefore = IERC20(weth).balanceOf(address(this)); v2Router.swapExactTokensForTokensSupportingFeeOnTransferTokens( _initialSwapData.amountIn, _initialSwapData.minAmountOutV2Swap, path, address(this), block.timestamp + 1 hours ); uint256 wethBalanceAfter = IERC20(weth).balanceOf(address(this)); uint256 wethOut = wethBalanceAfter - wethBalanceBefore; _initialSwapData.amountIn = wethOut; // This is updated for the next step checkAndApproveAll(weth, address(v3Router), wethOut); } else { checkAndApproveAll(_initialSwapData.tokenIn, address(v3Router), _initialSwapData.amountIn); } // Step c) uint256 beforeSendingUsdc = IERC20(usdc).balanceOf(address(this)); IV3SwapRouter.ExactInputParams memory params = IV3SwapRouter.ExactInputParams( _initialSwapData.v3InitialSwap, address(this), _initialSwapData.amountIn, _initialSwapData.minAmountOutV3Swap ); // Swap ReceiverSwapData.finalToken to ETH via V3, then to USDC via uniswap V3 USDCOut = v3Router.exactInput(params); uint256 afterSendingUsdc = IERC20(usdc).balanceOf(address(this)); require(afterSendingUsdc > beforeSendingUsdc, 'Must swap into USDC'); } else { checkAndApproveAll(_initialSwapData.tokenIn, paraRouter, _initialSwapData.amountIn); uint256 beforeUSDCBalance = IERC20(usdc).balanceOf(address(this)); (bool success, ) = paraRouter.call(_initialSwapData.dataIn); require(success, 'Call to paraswap router failed'); uint256 afterUSDCBalance = IERC20(usdc).balanceOf(address(this)); USDCOut = afterUSDCBalance - beforeUSDCBalance; } } // Send the fee uint256 feeAmount = (USDCOut * swapFee) / (feeBps * 100); IERC20(usdc).safeTransfer(feeReceiver, feeAmount); USDCOut = USDCOut - feeAmount; } // The token that will be crossed is always USDC function sendMessagePayFirstStep( uint64 _destinationChainSelector, address _receiverCCIPInOtherChain, uint256 _gasLimitReceiver, // How much gas the receiver will have to work with InitialSwapData calldata _initialSwapData, ReceiverSwapData calldata _receiverSwapData ) external payable returns (bytes32 messageId) { require(allowlistedSenders[_receiverCCIPInOtherChain], 'Must be a valid destination address'); // Create a memory copy of the InitialSwapData struct InitialSwapData memory initialSwapData = _initialSwapData; if (!_initialSwapData.withdrawWETH && _initialSwapData.tokenIn == weth) { IWETH(weth).deposit{value: msg.value - _initialSwapData.amountIn}(); // _initialSwapData.amountIn will be the CCIP fee when using eth initialSwapData.amountIn = msg.value - initialSwapData.amountIn; } else { // To take into consideration transfer fees uint256 beforeSending = IERC20(_initialSwapData.tokenIn).balanceOf(address(this)); IERC20(_initialSwapData.tokenIn).safeTransferFrom(msg.sender, address(this), _initialSwapData.amountIn); uint256 afterSending = IERC20(_initialSwapData.tokenIn).balanceOf(address(this)); initialSwapData.amountIn = afterSending - beforeSending; } if (initialSwapData.srcTax) { address outputToken = getLastAddressPath(initialSwapData.v3InitialSwap); require(outputToken == usdc, 'Must swap to USDC'); } uint256 USDCOut = swapInitialData(initialSwapData); return sendMessagePayNative( _destinationChainSelector, _receiverCCIPInOtherChain, string(abi.encode(_receiverSwapData)), usdc, USDCOut, _gasLimitReceiver ); } function calculateFeeGas( uint64 _destinationChainSelector, address _receiver, address _token, uint256 _amount, uint256 _gasLimitReceiver, bool _payInLINK, ReceiverSwapData memory _receiverSwapData ) external view returns (uint256 fees) { // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message // address(0) means fees are paid in native gas Client.EVM2AnyMessage memory evm2AnyMessage = _buildCCIPMessage( _receiver, string(abi.encode(_receiverSwapData)), _token, _amount, _payInLINK ? address(s_linkToken) : address(0), _gasLimitReceiver ); // Initialize a router client instance to interact with cross-chain router IRouterClient router = IRouterClient(this.getRouter()); // Get the fee required to send the CCIP message fees = router.getFee(_destinationChainSelector, evm2AnyMessage); } /*** My functions ***/ /** * @notice Returns the details of the last CCIP received message. * @dev This function retrieves the ID, text, token address, and token amount of the last received CCIP message. * @return messageId The ID of the last received CCIP message. * @return text The text of the last received CCIP message. * @return tokenAddress The address of the token in the last CCIP received message. * @return tokenAmount The amount of the token in the last CCIP received message. */ function getLastReceivedMessageDetails() public view returns (bytes32 messageId, string memory text, address tokenAddress, uint256 tokenAmount) { return (s_lastReceivedMessageId, s_lastReceivedText, s_lastReceivedTokenAddress, s_lastReceivedTokenAmount); } /** * @notice Retrieves a paginated list of failed messages. * @dev This function returns a subset of failed messages defined by `offset` and `limit` parameters. It ensures that the pagination parameters are within the bounds of the available data set. * @param offset The index of the first failed message to return, enabling pagination by skipping a specified number of messages from the start of the dataset. * @param limit The maximum number of failed messages to return, restricting the size of the returned array. * @return failedMessages An array of `FailedMessage` struct, each containing a `messageId` and an `errorCode` (RESOLVED or FAILED), representing the requested subset of failed messages. The length of the returned array is determined by the `limit` and the total number of failed messages. */ function getFailedMessages(uint256 offset, uint256 limit) external view returns (FailedMessage[] memory) { uint256 length = s_failedMessages.length(); // Calculate the actual number of items to return (can't exceed total length or requested limit) uint256 returnLength = (offset + limit > length) ? length - offset : limit; FailedMessage[] memory failedMessages = new FailedMessage[](returnLength); // Adjust loop to respect pagination (start at offset, end at offset + limit or total length) for (uint256 i = 0; i < returnLength; i++) { (bytes32 messageId, uint256 errorCode) = s_failedMessages.at(offset + i); failedMessages[i] = FailedMessage(messageId, ErrorCode(errorCode)); } return failedMessages; } /// @notice The entrypoint for the CCIP router to call. This function should /// never revert, all errors should be handled internally in this contract. /// @param any2EvmMessage The message to process. /// @dev Extremely important to ensure only router calls this. function ccipReceive( Client.Any2EVMMessage calldata any2EvmMessage ) external override onlyRouter onlyAllowlisted(any2EvmMessage.sourceChainSelector, abi.decode(any2EvmMessage.sender, (address))) // Make sure the source chain and sender are allowlisted { s_lastReceivedMessageId = any2EvmMessage.messageId; // fetch the messageId s_lastReceivedText = abi.decode(any2EvmMessage.data, (string)); // abi-decoding of the sent text // Expect one token to be transferred at once, but you can transfer several tokens. s_lastReceivedTokenAddress = any2EvmMessage.destTokenAmounts[0].token; s_lastReceivedTokenAmount = any2EvmMessage.destTokenAmounts[0].amount; ReceiverSwapData memory receiverData = abi.decode(bytes(s_lastReceivedText), (ReceiverSwapData)); emit MessageReceived( any2EvmMessage.messageId, any2EvmMessage.sourceChainSelector, receiverData.finalToken, receiverData.finalTokenDecimal, receiverData.minAmountOut, receiverData.withdrawETH, receiverData.userReceiver, any2EvmMessage.destTokenAmounts[0].token, any2EvmMessage.destTokenAmounts[0].amount ); } /// @notice Allows the owner to retry a failed message in order to unblock the associated tokens. /// @param messageId The unique identifier of the failed message. /// @param tokenReceiver The address to which the tokens will be sent. /// @dev This function is only callable by the contract owner. It changes the status of the message /// from 'failed' to 'resolved' to prevent reentry and multiple retries of the same message. function retryFailedMessage(bytes32 messageId, address tokenReceiver, uint256 index) external onlyOwner { // Check if the message has failed; if not, revert the transaction. if (s_failedMessages.get(messageId) != uint256(ErrorCode.FAILED)) revert MessageNotFailed(messageId); // Set the error code to RESOLVED to disallow reentry and multiple retries of the same failed message. s_failedMessages.set(messageId, uint256(ErrorCode.RESOLVED)); /*- My code -*/ require(!failedMessagesUsers[tokenReceiver][index].isRedeemed, 'Already redeemed'); failedMessagesUsers[tokenReceiver][index].isRedeemed = true; /*- My code -*/ // Retrieve the content of the failed message. SwapFromUSDCData storage message = s_messageContents[messageId]; // This example expects one token to have been sent, but you can handle multiple tokens. // Transfer the associated tokens to the specified receiver as an escape hatch. IERC20(usdc).safeTransfer(tokenReceiver, message.amountIn); // Emit an event indicating that the message has been recovered. emit MessageRecovered(messageId); } function _ccipReceive(Client.Any2EVMMessage memory any2EvmMessage) internal override {} function swapFromUSDC(SwapFromUSDCData calldata _swapFromUSDCData) public nonReentrant onlyExecutor { SwapFromUSDCData memory swapFromUSDCData = _swapFromUSDCData; try this.processSwapFromUSDC(swapFromUSDCData) {} catch (bytes memory err) { s_failedMessages.set(swapFromUSDCData.messageId, uint256(ErrorCode.FAILED)); s_messageContents[swapFromUSDCData.messageId] = swapFromUSDCData; failedMessagesUsers[swapFromUSDCData.to].push( FailedMessagesUsers( usdc, swapFromUSDCData.to, swapFromUSDCData.amountIn, false, swapFromUSDCData.messageId ) ); failedMessageByMessageId[swapFromUSDCData.messageId] = AddressNumber( swapFromUSDCData.to, failedMessagesUsers[swapFromUSDCData.to].length ); emit MessageFailed(swapFromUSDCData.messageId, err); return; } } function processSwapFromUSDC(SwapFromUSDCData calldata swapFromUSDCData) external onlySelf { _processSwapFromUSDC(swapFromUSDCData); } function _processSwapFromUSDC(SwapFromUSDCData memory _swapFromUSDCData) internal { SwapFromUSDCData memory swapFromUSDCData = _swapFromUSDCData; require(swapFromUSDCData.amountIn > swapFromUSDCData.fee, 'Not enough usdc balance to execute tx.'); if (swapFromUSDCData.isETH) { IERC20(swapFromUSDCData.outputToken).safeTransfer(executor, swapFromUSDCData.fee); } else { uint256 beforeWETHBalance = IERC20(weth).balanceOf(address(this)); address[] memory path = new address[](2); path[0] = usdc; path[1] = weth; v2Swap(path, swapFromUSDCData.fee, 0); uint256 afterWETHBalance = IERC20(weth).balanceOf(address(this)); uint256 amountWETHOut = afterWETHBalance - beforeWETHBalance; IWETH(weth).withdraw(amountWETHOut); payable(executor).transfer(amountWETHOut); } swapFromUSDCData.amountIn = swapFromUSDCData.amountIn - swapFromUSDCData.fee; // USDC -> Token if (swapFromUSDCData.outputToken == usdc) { IERC20(usdc).transfer(swapFromUSDCData.to, swapFromUSDCData.amountIn); emit SwapFromUSDC( swapFromUSDCData.messageId, swapFromUSDCData.to, usdc, swapFromUSDCData.amountIn, block.timestamp ); return; } IERC20(usdc).approve(address(paraRouter), swapFromUSDCData.amountIn); uint256 beforeBalance = IERC20(swapFromUSDCData.outputToken).balanceOf(address(this)); (bool success, ) = paraRouter.call(swapFromUSDCData.dataOut); require(success, 'Call to paraswap router failed'); uint256 afterBalance = IERC20(swapFromUSDCData.outputToken).balanceOf(address(this)); uint256 amountOut = afterBalance - beforeBalance; require(amountOut >= swapFromUSDCData.minAmountOut, 'Amountout is less than minAmountOut'); if (swapFromUSDCData.withdrawETH) { IWETH(weth).withdraw(amountOut); (bool success, ) = (swapFromUSDCData.to).call{value: address(this).balance}(''); if (!success) { revert FailedCall(); } } else { IERC20(swapFromUSDCData.outputToken).safeTransfer(swapFromUSDCData.to, amountOut); } emit SwapFromUSDC( swapFromUSDCData.messageId, swapFromUSDCData.to, swapFromUSDCData.outputToken, swapFromUSDCData.amountIn, block.timestamp ); } function v2Swap( address[] memory _path, uint256 _amountIn, uint256 _minAmountOut // Slippage in base of 1000 meaning 10 is 1% and 1 is 0.1% where 1000 is 1 ) internal returns (uint256) { address tokenOut = _path[_path.length - 1]; checkAndApproveAll(_path[0], address(v2Router), _amountIn); uint256 initial = IERC20(tokenOut).balanceOf(address(this)); v2Router.swapExactTokensForTokensSupportingFeeOnTransferTokens( _amountIn, _minAmountOut, _path, address(this), block.timestamp + 1 hours ); uint256 finalAmount = IERC20(tokenOut).balanceOf(address(this)); return finalAmount - initial; } /// @notice Construct a CCIP message. /// @dev This function will create an EVM2AnyMessage struct with all the necessary information for programmable tokens transfer. /// @param _receiver The address of the receiver. /// @param _text The string data to be sent. /// @param _token The token to be transferred. /// @param _amount The amount of the token to be transferred. /// @param _feeTokenAddress The address of the token used for fees. Set address(0) for native gas. /// @return Client.EVM2AnyMessage Returns an EVM2AnyMessage struct which contains information for sending a CCIP message. function _buildCCIPMessage( address _receiver, string memory _text, address _token, uint256 _amount, address _feeTokenAddress, uint256 _gasLimitReceiver ) internal pure returns (Client.EVM2AnyMessage memory) { // Set the token amounts Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1); Client.EVMTokenAmount memory tokenAmount = Client.EVMTokenAmount({token: _token, amount: _amount}); tokenAmounts[0] = tokenAmount; // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message Client.EVM2AnyMessage memory evm2AnyMessage = Client.EVM2AnyMessage({ receiver: abi.encode(_receiver), // ABI-encoded receiver address data: abi.encode(_text), // ABI-encoded string tokenAmounts: tokenAmounts, // The amount and type of token being transferred extraArgs: Client._argsToBytes( // Additional arguments, setting gas limit Client.EVMExtraArgsV1({gasLimit: _gasLimitReceiver}) ), // Set the feeToken to a feeTokenAddress, indicating specific asset will be used for fees feeToken: _feeTokenAddress }); return evm2AnyMessage; } /// @notice Fallback function to allow the contract to receive Ether. /// @dev This function has no function body, making it a default function for receiving Ether. /// It is automatically called when Ether is sent to the contract without any data. receive() external payable {} /// @notice Allows the contract owner to withdraw the entire balance of Ether from the contract. /// @dev This function reverts if there are no funds to withdraw or if the transfer fails. /// It should only be callable by the owner of the contract. /// @param _beneficiary The address to which the Ether should be sent. function withdraw(address _beneficiary) public onlyOwner { require(timeLockTime > 0 && block.timestamp > timeLockTime, 'Timelocked'); timeLockTime = 0; // Reset it // Retrieve the balance of this contract uint256 amount = address(this).balance; // Revert if there is nothing to withdraw if (amount == 0) revert NothingToWithdraw(); // Attempt to send the funds, capturing the success status and discarding any return data (bool sent, ) = _beneficiary.call{value: amount}(''); // Revert if the send failed, with information about the attempted transfer if (!sent) revert FailedToWithdrawEth(msg.sender, _beneficiary, amount); } /// @notice Allows the owner of the contract to withdraw all tokens of a specific ERC20 token. /// @dev This function reverts with a 'NothingToWithdraw' error if there are no tokens to withdraw. /// @param _beneficiary The address to which the tokens will be sent. /// @param _token The contract address of the ERC20 token to be withdrawn. function withdrawToken(address _beneficiary, address _token) public onlyOwner { require(timeLockTime > 0 && block.timestamp > timeLockTime, 'Timelocked'); timeLockTime = 0; // Reset the timelock time to ensure the mechanism is valid for future withdrawals // Retrieve the balance of this contract uint256 amount = IERC20(_token).balanceOf(address(this)); // Revert if there is nothing to withdraw if (amount == 0) revert NothingToWithdraw(); IERC20(_token).safeTransfer(_beneficiary, amount); } /*- My functions -*/ function recoverFailedTransfer(address tokenReceiver, uint256 index) external { FailedMessagesUsers storage f = failedMessagesUsers[tokenReceiver][index]; require(!f.isRedeemed, 'Already redeemed'); f.isRedeemed = true; require(msg.sender == f.receiver, 'Must be executed by the receiver'); // Check if the message has failed; if not, revert the transaction. if (s_failedMessages.get(f.messageId) != uint256(ErrorCode.FAILED)) revert MessageNotFailed(f.messageId); // Set the error code to RESOLVED to disallow reentry and multiple retries of the same failed message. s_failedMessages.set(f.messageId, uint256(ErrorCode.RESOLVED)); // This example expects one token to have been sent, but you can handle multiple tokens. // Transfer the associated tokens to the specified receiver as an escape hatch. IERC20(f.token).safeTransfer(tokenReceiver, f.amount); // Emit an event indicating that the message has been recovered. emit MessageRecovered(f.messageId); } function getFailedMessagesUser( address _user, uint256 _offset, uint256 _limit ) external view returns (FailedMessagesUsers[] memory) { FailedMessagesUsers[] memory results = new FailedMessagesUsers[](_limit); for (uint256 i = 0; i < _limit; i++) { results[i] = failedMessagesUsers[_user][_offset + i]; } return results; } function getLengthFailedMessagesUser(address _user) external view returns (uint256) { uint256 size = failedMessagesUsers[_user].length; return size; } function getFailedMessageByMessageId(bytes32 _messageId) external view returns (FailedMessagesUsers memory) { AddressNumber storage an = failedMessageByMessageId[_messageId]; return failedMessagesUsers[an.user][an.index]; } /*- My functions -*/ }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IAny2EVMMessageReceiver} from "../interfaces/IAny2EVMMessageReceiver.sol"; import {Client} from "../libraries/Client.sol"; import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol"; /// @title CCIPReceiver - Base contract for CCIP applications that can receive messages. abstract contract CCIPReceiver is IAny2EVMMessageReceiver, IERC165 { address internal immutable i_ccipRouter; constructor(address router) { if (router == address(0)) revert InvalidRouter(address(0)); i_ccipRouter = router; } /// @notice IERC165 supports an interfaceId /// @param interfaceId The interfaceId to check /// @return true if the interfaceId is supported /// @dev Should indicate whether the contract implements IAny2EVMMessageReceiver /// e.g. return interfaceId == type(IAny2EVMMessageReceiver).interfaceId || interfaceId == type(IERC165).interfaceId /// This allows CCIP to check if ccipReceive is available before calling it. /// If this returns false or reverts, only tokens are transferred to the receiver. /// If this returns true, tokens are transferred and ccipReceive is called atomically. /// Additionally, if the receiver address does not have code associated with /// it at the time of execution (EXTCODESIZE returns 0), only tokens will be transferred. function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) { return interfaceId == type(IAny2EVMMessageReceiver).interfaceId || interfaceId == type(IERC165).interfaceId; } /// @inheritdoc IAny2EVMMessageReceiver function ccipReceive(Client.Any2EVMMessage calldata message) external virtual override onlyRouter { _ccipReceive(message); } /// @notice Override this function in your implementation. /// @param message Any2EVMMessage function _ccipReceive(Client.Any2EVMMessage memory message) internal virtual; ///////////////////////////////////////////////////////////////////// // Plumbing ///////////////////////////////////////////////////////////////////// /// @notice Return the current router /// @return CCIP router address function getRouter() public view returns (address) { return address(i_ccipRouter); } error InvalidRouter(address router); /// @dev only calls from the set router are accepted. modifier onlyRouter() { if (msg.sender != address(i_ccipRouter)) revert InvalidRouter(msg.sender); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Client} from "../libraries/Client.sol"; /// @notice Application contracts that intend to receive messages from /// the router should implement this interface. interface IAny2EVMMessageReceiver { /// @notice Called by the Router to deliver a message. /// If this reverts, any token transfers also revert. The message /// will move to a FAILED state and become available for manual execution. /// @param message CCIP Message /// @dev Note ensure you check the msg.sender is the OffRampRouter function ccipReceive(Client.Any2EVMMessage calldata message) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Client} from "../libraries/Client.sol"; interface IRouterClient { error UnsupportedDestinationChain(uint64 destChainSelector); error InsufficientFeeTokenAmount(); error InvalidMsgValue(); /// @notice Checks if the given chain ID is supported for sending/receiving. /// @param chainSelector The chain to check. /// @return supported is true if it is supported, false if not. function isChainSupported(uint64 chainSelector) external view returns (bool supported); /// @notice Gets a list of all supported tokens which can be sent or received /// to/from a given chain id. /// @param chainSelector The chainSelector. /// @return tokens The addresses of all tokens that are supported. function getSupportedTokens(uint64 chainSelector) external view returns (address[] memory tokens); /// @param destinationChainSelector The destination chainSelector /// @param message The cross-chain CCIP message including data and/or tokens /// @return fee returns execution fee for the message /// delivery to destination chain, denominated in the feeToken specified in the message. /// @dev Reverts with appropriate reason upon invalid message. function getFee( uint64 destinationChainSelector, Client.EVM2AnyMessage memory message ) external view returns (uint256 fee); /// @notice Request a message to be sent to the destination chain /// @param destinationChainSelector The destination chain ID /// @param message The cross-chain CCIP message including data and/or tokens /// @return messageId The message ID /// @dev Note if msg.value is larger than the required fee (from getFee) we accept /// the overpayment with no refund. /// @dev Reverts with appropriate reason upon invalid message. function ccipSend( uint64 destinationChainSelector, Client.EVM2AnyMessage calldata message ) external payable returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // End consumer library. library Client { /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers. struct EVMTokenAmount { address token; // token address on the local chain. uint256 amount; // Amount of tokens. } struct Any2EVMMessage { bytes32 messageId; // MessageId corresponding to ccipSend on source. uint64 sourceChainSelector; // Source chain selector. bytes sender; // abi.decode(sender) if coming from an EVM chain. bytes data; // payload sent in original message. EVMTokenAmount[] destTokenAmounts; // Tokens and their amounts in their destination chain representation. } // If extraArgs is empty bytes, the default is 200k gas limit. struct EVM2AnyMessage { bytes receiver; // abi.encode(receiver address) for dest EVM chains bytes data; // Data payload EVMTokenAmount[] tokenAmounts; // Token transfers address feeToken; // Address of feeToken. address(0) means you will send msg.value. bytes extraArgs; // Populate this with _argsToBytes(EVMExtraArgsV1) } // bytes4(keccak256("CCIP EVMExtraArgsV1")); bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9; struct EVMExtraArgsV1 { uint256 gasLimit; } function _argsToBytes(EVMExtraArgsV1 memory extraArgs) internal pure returns (bytes memory bts) { return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev 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 initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol) pragma solidity ^0.8.20; import {Ownable} from "./Ownable.sol"; /** * @dev Contract module which provides access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is specified at deployment time in the constructor for `Ownable`. This * can later be changed with {transferOwnership} and {acceptOwnership}. * * This module is used through inheritance. It will make available all functions * from parent (Ownable). */ abstract contract Ownable2Step is Ownable { address private _pendingOwner; event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); /** * @dev Returns the address of the pending owner. */ function pendingOwner() public view virtual returns (address) { return _pendingOwner; } /** * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual override onlyOwner { _pendingOwner = newOwner; emit OwnershipTransferStarted(owner(), newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual override { delete _pendingOwner; super._transferOwnership(newOwner); } /** * @dev The new owner accepts the ownership transfer. */ function acceptOwnership() public virtual { address sender = _msgSender(); if (pendingOwner() != sender) { revert OwnableUnauthorizedAccount(sender); } _transferOwnership(sender); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @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. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ 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]. * * CAUTION: See Security Considerations above. */ 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 v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @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 value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` 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 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC20Permit} from "../extensions/IERC20Permit.sol"; import {Address} from "../../../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 An operation with an ERC20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @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.encodeCall(token.transfer, (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.encodeCall(token.transferFrom, (from, to, 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); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @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.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @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); if (returndata.length != 0 && !abi.decode(returndata, (bool))) { revert SafeERC20FailedOperation(address(token)); } } /** * @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(token).code.length > 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert AddressInsufficientBalance(address(this)); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert FailedInnerCall(); } } /** * @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 or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * 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. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @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`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert AddressInsufficientBalance(address(this)); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) 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 FailedInnerCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; uint256 private _status; /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); constructor() { _status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be NOT_ENTERED if (_status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail _status = ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableMap.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableMap.js. pragma solidity ^0.8.20; import {EnumerableSet} from "./EnumerableSet.sol"; /** * @dev Library for managing an enumerable variant of Solidity's * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] * type. * * Maps have the following properties: * * - Entries are added, removed, and checked for existence in constant time * (O(1)). * - Entries are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableMap for EnumerableMap.UintToAddressMap; * * // Declare a set state variable * EnumerableMap.UintToAddressMap private myMap; * } * ``` * * The following map types are supported: * * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0 * - `address -> uint256` (`AddressToUintMap`) since v4.6.0 * - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0 * - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0 * - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0 * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableMap. * ==== */ library EnumerableMap { using EnumerableSet for EnumerableSet.Bytes32Set; // To implement this library for multiple types with as little code repetition as possible, we write it in // terms of a generic Map type with bytes32 keys and values. The Map implementation uses private functions, // and user-facing implementations such as `UintToAddressMap` are just wrappers around the underlying Map. // This means that we can only create new EnumerableMaps for types that fit in bytes32. /** * @dev Query for a nonexistent map key. */ error EnumerableMapNonexistentKey(bytes32 key); struct Bytes32ToBytes32Map { // Storage of keys EnumerableSet.Bytes32Set _keys; mapping(bytes32 key => bytes32) _values; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) { map._values[key] = value; return map._keys.add(key); } /** * @dev Removes a key-value pair from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) { delete map._values[key]; return map._keys.remove(key); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) { return map._keys.contains(key); } /** * @dev Returns the number of key-value pairs in the map. O(1). */ function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) { return map._keys.length(); } /** * @dev Returns the key-value pair stored at position `index` in the map. O(1). * * Note that there are no guarantees on the ordering of entries inside the * array, and it may change when more entries are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) { bytes32 key = map._keys.at(index); return (key, map._values[key]); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) { bytes32 value = map._values[key]; if (value == bytes32(0)) { return (contains(map, key), bytes32(0)); } else { return (true, value); } } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) { bytes32 value = map._values[key]; if (value == 0 && !contains(map, key)) { revert EnumerableMapNonexistentKey(key); } return value; } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) { return map._keys.values(); } // UintToUintMap struct UintToUintMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) { return set(map._inner, bytes32(key), bytes32(value)); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(UintToUintMap storage map, uint256 key) internal returns (bool) { return remove(map._inner, bytes32(key)); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) { return contains(map._inner, bytes32(key)); } /** * @dev Returns the number of elements in the map. O(1). */ function length(UintToUintMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) { (bytes32 key, bytes32 value) = at(map._inner, index); return (uint256(key), uint256(value)); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) { (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); return (success, uint256(value)); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) { return uint256(get(map._inner, bytes32(key))); } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(UintToUintMap storage map) internal view returns (uint256[] memory) { bytes32[] memory store = keys(map._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintToAddressMap struct UintToAddressMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) { return set(map._inner, bytes32(key), bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) { return remove(map._inner, bytes32(key)); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) { return contains(map._inner, bytes32(key)); } /** * @dev Returns the number of elements in the map. O(1). */ function length(UintToAddressMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) { (bytes32 key, bytes32 value) = at(map._inner, index); return (uint256(key), address(uint160(uint256(value)))); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) { (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); return (success, address(uint160(uint256(value)))); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(UintToAddressMap storage map, uint256 key) internal view returns (address) { return address(uint160(uint256(get(map._inner, bytes32(key))))); } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) { bytes32[] memory store = keys(map._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressToUintMap struct AddressToUintMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) { return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value)); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(AddressToUintMap storage map, address key) internal returns (bool) { return remove(map._inner, bytes32(uint256(uint160(key)))); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(AddressToUintMap storage map, address key) internal view returns (bool) { return contains(map._inner, bytes32(uint256(uint160(key)))); } /** * @dev Returns the number of elements in the map. O(1). */ function length(AddressToUintMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) { (bytes32 key, bytes32 value) = at(map._inner, index); return (address(uint160(uint256(key))), uint256(value)); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) { (bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key)))); return (success, uint256(value)); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(AddressToUintMap storage map, address key) internal view returns (uint256) { return uint256(get(map._inner, bytes32(uint256(uint160(key))))); } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(AddressToUintMap storage map) internal view returns (address[] memory) { bytes32[] memory store = keys(map._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // Bytes32ToUintMap struct Bytes32ToUintMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) { return set(map._inner, key, bytes32(value)); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) { return remove(map._inner, key); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) { return contains(map._inner, key); } /** * @dev Returns the number of elements in the map. O(1). */ function length(Bytes32ToUintMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) { (bytes32 key, bytes32 value) = at(map._inner, index); return (key, uint256(value)); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) { (bool success, bytes32 value) = tryGet(map._inner, key); return (success, uint256(value)); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) { return uint256(get(map._inner, key)); } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) { bytes32[] memory store = keys(map._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.20; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position is the index of the value in the `values` array plus 1. // Position 0 is used to mean a value is not in the set. mapping(bytes32 value => uint256) _positions; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._positions[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We cache the value's position to prevent multiple reads from the same storage slot uint256 position = set._positions[value]; if (position != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 valueIndex = position - 1; uint256 lastIndex = set._values.length - 1; if (valueIndex != lastIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the lastValue to the index where the value to delete is set._values[valueIndex] = lastValue; // Update the tracked position of the lastValue (that was just moved) set._positions[lastValue] = position; } // Delete the slot where the moved value was stored set._values.pop(); // Delete the tracked position for the deleted slot delete set._positions[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._positions[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
{ "optimizer": { "enabled": true, "runs": 100 }, "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
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_router","type":"address"},{"internalType":"address","name":"_link","type":"address"},{"internalType":"address","name":"_usdc","type":"address"},{"internalType":"address","name":"_weth","type":"address"},{"internalType":"uint256","name":"_swapFee","type":"uint256"},{"internalType":"address","name":"_feeReceiver","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_paraRouter","type":"address"},{"internalType":"address","name":"_v2Router","type":"address"},{"internalType":"address","name":"_v3Router","type":"address"},{"internalType":"address","name":"_executor","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[{"internalType":"uint64","name":"destinationChainSelector","type":"uint64"}],"name":"DestinationChainNotAllowlisted","type":"error"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"EnumerableMapNonexistentKey","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"FailedToWithdrawEth","type":"error"},{"inputs":[],"name":"InvalidMessage","type":"error"},{"inputs":[],"name":"InvalidReceiverAddress","type":"error"},{"inputs":[{"internalType":"address","name":"router","type":"address"}],"name":"InvalidRouter","type":"error"},{"inputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"name":"MessageNotFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentBalance","type":"uint256"},{"internalType":"uint256","name":"calculatedFees","type":"uint256"}],"name":"NotEnoughBalance","type":"error"},{"inputs":[],"name":"NothingToWithdraw","type":"error"},{"inputs":[],"name":"OnlySelf","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"SenderNotAllowed","type":"error"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"}],"name":"SourceChainNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldExecutor","type":"address"},{"indexed":true,"internalType":"address","name":"newExecutor","type":"address"}],"name":"ExecutorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"reason","type":"bytes"}],"name":"MessageFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"},{"indexed":true,"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"indexed":false,"internalType":"address","name":"finalToken","type":"address"},{"indexed":false,"internalType":"uint8","name":"finalTokenDecimal","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"indexed":false,"internalType":"bool","name":"withdrawETH","type":"bool"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"MessageReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"}],"name":"MessageRecovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"},{"indexed":true,"internalType":"uint64","name":"destinationChainSelector","type":"uint64"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"string","name":"text","type":"string"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"feeToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"fees","type":"uint256"}],"name":"MessageSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"SwapFromUSDC","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"time","type":"uint256"}],"name":"TimeLockActivated","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"activateTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_destinationChainSelector","type":"uint64"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"allowlistDestinationChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"allowlistSender","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_sourceChainSelector","type":"uint64"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"allowlistSourceChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"allowlistedDestinationChains","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allowlistedSenders","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"allowlistedSourceChains","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"_destinationChainSelector","type":"uint64"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_gasLimitReceiver","type":"uint256"},{"internalType":"bool","name":"_payInLINK","type":"bool"},{"components":[{"internalType":"address","name":"finalToken","type":"address"},{"internalType":"uint8","name":"finalTokenDecimal","type":"uint8"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"userReceiver","type":"address"},{"internalType":"bool","name":"withdrawETH","type":"bool"}],"internalType":"struct CCIP.ReceiverSwapData","name":"_receiverSwapData","type":"tuple"}],"name":"calculateFeeGas","outputs":[{"internalType":"uint256","name":"fees","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"bytes","name":"sender","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Client.EVMTokenAmount[]","name":"destTokenAmounts","type":"tuple[]"}],"internalType":"struct Client.Any2EVMMessage","name":"any2EvmMessage","type":"tuple"}],"name":"ccipReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"address","name":"_feeReceiver","type":"address"}],"name":"changeFeeAndAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_v2Router","type":"address"},{"internalType":"address","name":"_v3Router","type":"address"}],"name":"changeRouters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"executor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"failedMessageByMessageId","outputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"failedMessagesUsers","outputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"isRedeemed","type":"bool"},{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_messageId","type":"bytes32"}],"name":"getFailedMessageByMessageId","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"isRedeemed","type":"bool"},{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"internalType":"struct CCIP.FailedMessagesUsers","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"getFailedMessages","outputs":[{"components":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"enum CCIP.ErrorCode","name":"errorCode","type":"uint8"}],"internalType":"struct CCIP.FailedMessage[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_offset","type":"uint256"},{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"getFailedMessagesUser","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"isRedeemed","type":"bool"},{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"internalType":"struct CCIP.FailedMessagesUsers[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_path","type":"bytes"}],"name":"getLastAddressPath","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getLastReceivedMessageDetails","outputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"string","name":"text","type":"string"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getLengthFailedMessagesUser","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paraRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isETH","type":"bool"},{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"withdrawETH","type":"bool"},{"internalType":"bytes","name":"dataOut","type":"bytes"},{"internalType":"uint256","name":"fee","type":"uint256"}],"internalType":"struct CCIP.SwapFromUSDCData","name":"swapFromUSDCData","type":"tuple"}],"name":"processSwapFromUSDC","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenReceiver","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"recoverFailedTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"address","name":"tokenReceiver","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"retryFailedMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"name":"s_messageContents","outputs":[{"internalType":"bool","name":"isETH","type":"bool"},{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"withdrawETH","type":"bool"},{"internalType":"bytes","name":"dataOut","type":"bytes"},{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"_destinationChainSelector","type":"uint64"},{"internalType":"address","name":"_receiverCCIPInOtherChain","type":"address"},{"internalType":"uint256","name":"_gasLimitReceiver","type":"uint256"},{"components":[{"internalType":"bool","name":"srcTax","type":"bool"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOutV2Swap","type":"uint256"},{"internalType":"uint256","name":"minAmountOutV3Swap","type":"uint256"},{"internalType":"bool","name":"swapTokenInV2First","type":"bool"},{"internalType":"bool","name":"withdrawWETH","type":"bool"},{"internalType":"bytes","name":"v3InitialSwap","type":"bytes"},{"internalType":"bytes","name":"dataIn","type":"bytes"}],"internalType":"struct CCIP.InitialSwapData","name":"_initialSwapData","type":"tuple"},{"components":[{"internalType":"address","name":"finalToken","type":"address"},{"internalType":"uint8","name":"finalTokenDecimal","type":"uint8"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"userReceiver","type":"address"},{"internalType":"bool","name":"withdrawETH","type":"bool"}],"internalType":"struct CCIP.ReceiverSwapData","name":"_receiverSwapData","type":"tuple"}],"name":"sendMessagePayFirstStep","outputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_newExecutor","type":"address"}],"name":"setExecutor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"swapFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isETH","type":"bool"},{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"withdrawETH","type":"bool"},{"internalType":"bytes","name":"dataOut","type":"bytes"},{"internalType":"uint256","name":"fee","type":"uint256"}],"internalType":"struct CCIP.SwapFromUSDCData","name":"_swapFromUSDCData","type":"tuple"}],"name":"swapFromUSDC","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"timeLockTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usdc","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"v2Router","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"v3Router","outputs":[{"internalType":"contract IV3SwapRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_beneficiary","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_beneficiary","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"withdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
610120346200029857601f62004d2838819003918201601f19168301916001600160401b038311848410176200029d578084926101609460405283398101031262000298576200004f81620002b3565b6200005d60208301620002b3565b906200006c60408401620002b3565b926200007b60608201620002b3565b926080820151936200009060a08401620002b3565b6200009e60c08501620002b3565b95620000ad60e08601620002b3565b9261010098620000bf8a8801620002b3565b95620000de610140620000d66101208b01620002b3565b9901620002b3565b986001600160a01b038116156200027f576080526001600160a01b038a16156200026657600180546001600160a01b0319908116909155600080546001600160a01b039c8d16928116831782556040519c16907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a360016002556001600160a01b0390811660a05260e09190915260c091909152601291909155601380549282166001600160a01b03199384161790559187526011805493831693821693909317909255601080549382169383169390931790925560148054939092169216919091179055614a5f9182620002c9833960805182818161147e0152611b13015260a051826132b2015260c0518281816104cc0152818161076201528181610ced01528181612dd9015281816141d40152614455015260e051828181610583015281816105ce01528181610c62015281816111f401528181612d4601528181613e770152818161407301526144b10152518181816103990152818161313201526140af0152f35b604051631e4fbdf760e01b815260006004820152602490fd5b6040516335fdcccd60e21b815260006004820152602490fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b0382168203620002985756fe6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c806301f59d16146102fb57806301ffc9a7146102f6578063046d293c146102f157806309abd96e146102ec5780630dc91306146102e757806319db9cd9146102e25780631c3c0ea8146102dd5780631f0e7bf8146102d857806320446c0b146102d357806324a9d853146102ce578063263596a5146102c95780632c94785a146102c45780633aeac4e1146102bf5780633e413bee146102ba5780633e957731146102b55780633fc8cef3146102b05780634030d521146102ab5780634b127efd146102a65780634dd31560146102a157806351cff8d91461029c57806354cf2aeb146102975780635aacd56a146102925780636122750f1461028d5780636159ada11461028857806363a5d29814610283578063715018a61461027e57806375c67c661461027957806379ba50971461027457806380665c2a1461026f57806382b55c7b1461026a57806385572ffb146102655780638d9d89fe146102605780638da5cb5b1461025b57806393b8cb441461025657806396d3b83d14610251578063988950951461024c578063a05bdb5b14610247578063b0f479a114610242578063b3f006741461023d578063c34c08e514610238578063d0d1fc3d14610233578063db04fa491461022e578063deadbc1414610229578063e30c397814610224578063eab5b02c1461021f5763f2fde38b0361000e57611e30565b611dd5565b611dac565b611d83565b611d41565b611cb9565b611b6b565b611b42565b611afd565b611ab1565b61199b565b611959565b611877565b611716565b611622565b611444565b611407565b6113e9565b6113a3565b611360565b6112fa565b6112a3565b611261565b611128565b61104d565b610fe7565b610f4e565b610e33565b610d96565b610d1c565b610cd7565b610c91565b610c4c565b610b9d565b610b35565b610a03565b6109a6565b61093c565b6108dd565b610870565b6107ea565b610794565b610425565b610383565b61032d565b610310565b600091031261030b57565b600080fd5b3461030b57600036600319011261030b576020604051614e208152f35b3461030b57602036600319011261030b5760043563ffffffff60e01b811680910361030b576020906385572ffb60e01b8114908115610372575b506040519015158152f35b6301ffc9a760e01b14905038610367565b3461030b57600036600319011261030b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b6001600160401b0381160361030b57565b6001600160a01b0381160361030b57565b35906103f5826103d9565b565b908161012091031261030b5790565b60a090608319011261030b57608490565b908160a091031261030b5790565b61012036600319011261030b5760043561043e816103c8565b6024359061044b826103d9565b6064356001600160401b03811161030b5761046a9036906004016103f7565b9161047436610406565b6001600160a01b03821660009081526009602052604090206104a19061049c905b5460ff1690565b6121e0565b6104ab3685612238565b926104bf6104bb60c087016122ef565b1590565b80610753575b15610623577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169461050390604001353461204a565b94803b1561030b57600090600460405180988193630d0e30db60e41b83525af193841561061e5761057d61055f61056f926105b8986105a898610605575b506040810161055181513461204a565b90525b80516105bc57612d35565b936040519283916020830161235e565b03601f1981018352826117d3565b604435937f000000000000000000000000000000000000000000000000000000000000000092612532565b6040519081529081906020820190565b0390f35b6106006105cc60e0830151611f98565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161461231e565b612d35565b806106126106189261176a565b80610300565b38610541565b612312565b60209493949384810161064761063b61063b836122f9565b6001600160a01b031690565b6040516370a0823160e01b8082523060048301529290918890839060249082905afa93841561061e578892600095610722575b5061063b826106a461063b93604061069761063b6106a9986122f9565b91013590309033906123c7565b6122f9565b604051928352306004840152829060249082905afa90811561061e576105b8976106eb61056f9461057d9461055f946105a89b6000926106f5575b505061204a565b6040820152610554565b6107149250803d1061071b575b61070c81836117d3565b810190612303565b38806106e4565b503d610702565b61063b9195506106a9926106a461074861063b93873d891161071b5761070c81836117d3565b97935050925061067a565b50610760602086016122f9565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169116146104c5565b3461030b57600036600319011261030b576010546040516001600160a01b039091168152602090f35b602060031982011261030b57600435906001600160401b03821161030b576107e7916004016103f7565b90565b3461030b576107f8366107bd565b600280541461085e57600280556014546001600160a01b0316330361082a5761082090613d88565b6100196001600255565b60405162461bcd60e51b815260206004820152600c60248201526b3737ba1032bc32b1baba37b960a11b6044820152606490fd5b604051633ee5aeb560e01b8152600490fd5b3461030b57602036600319011261030b5760043561088d816103d9565b610895611ea0565b6014546001600160a01b0391821691829082167f0ef3c7eb9dbcf33ddf032f4cce366a07eda85eed03e3172e4a90c4cc16d57886600080a36001600160a01b03191617601455005b3461030b576108eb366107bd565b303303610905576109006100199136906139fa565b613ffb565b60405163029a949d60e31b8152600490fd5b604090600319011261030b5760043561092f816103d9565b906024356107e7816103d9565b3461030b5761094a36610917565b90610953611ea0565b610969601554801515908161099c575b50611f50565b6000601555601080546001600160a01b039384166001600160a01b03199182161790915560118054929093169116179055005b9050421138610963565b3461030b57600036600319011261030b5760206040516103e88152f35b919082519283825260005b8481106109ef575050826000602080949584010152601f8019910116010190565b6020818301810151848301820152016109ce565b3461030b57600080600319360112610af95760035460018060a01b0360045416600554604051938481600654610a3881611b94565b80845290600190818116908115610ad65750600114610a8b575b5050610a60925003856117d3565b610a7c60405194859485526080602086015260808501906109c3565b91604084015260608301520390f35b60068552600080516020614a0a833981519152946020935091905b818310610abe575050610a6093508201013880610a52565b85548a84018501529485019489945091830191610aa6565b915050610a6094506020925060ff191682840152151560051b8201013880610a52565b80fd5b6080809160018060a01b038082511685526020820151166020850152604081015160408501526060810151151560608501520151910152565b3461030b57602036600319011261030b57610b4e614971565b50600435600052600c60205260a0610b8e610b886040600020600180851b03815416600052600b6020526001604060002091015490610d75565b5061499c565b610b9b6040518092610afc565bf35b3461030b57610bab36610917565b610bb3611ea0565b610bc8601554801515908161099c5750611f50565b610bd26000601555565b6040516370a0823160e01b81523060048201526001600160a01b039190911691602082602481865afa91821561061e57600092610c2c575b508115610c1a5761001992613211565b604051630686827b60e51b8152600490fd5b610c4591925060203d811161071b5761070c81836117d3565b9038610c0a565b3461030b57600036600319011261030b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461030b57602036600319011261030b576004356000908152600c6020908152604091829020805460019091015483516001600160a01b03909216825291810191909152f35b3461030b57600036600319011261030b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461030b57602036600319011261030b576001600160401b03600435610d41816103c8565b166000526008602052602060ff604060002054166040519015158152f35b634e487b7160e01b600052603260045260246000fd5b8054821015610d91576000526005602060002091020190600090565b610d5f565b3461030b57604036600319011261030b57600435610db3816103d9565b6001600160a01b039081166000908152600b6020526040902080546024359081101561030b57610de291610d75565b508054600182015460028301546003840154600490940154604080516001600160a01b03958816861681529690931690931660208601529084015260ff90911615156060830152608082015260a090f35b3461030b57604036600319011261030b57600435610e50816103d9565b6001600160a01b0381166000908152600b60205260409020610e7a9060243590610d75565b610d75565b50610ea560038201610e98610e936104bb835460ff1690565b6138cb565b805460ff19166001179055565b6001810154610ec790610ec0906001600160a01b031661063b565b3314614926565b60048101908154926001610eda8561393d565b03610f3557610eec610f0d939461390a565b508154600290610f04906001600160a01b031661063b565b92015491613211565b547fef3bf8c64bc480286c4f3503b870ceb23e648d2d902e31fb7bb46680da6de8ad600080a2005b6040516305b73c1360e51b815260048101859052602490fd5b3461030b57602036600319011261030b57600435610f6b816103d9565b610f73611ea0565b610f88601554801515908161099c5750611f50565b610f926000601555565b478015610c1a576000918280808085855af1610fac61249f565b5015610fb6578280f35b604051639d11f56360e01b81523360048201526001600160a01b039190911660248201526044810191909152606490fd5b3461030b57600036600319011261030b576020601254604051908152f35b6020908160408183019282815285518094520193019160005b82811061102c575050505090565b909192938260a0826110416001948951610afc565b0195019392910161101e565b3461030b57606036600319011261030b5760043561106a816103d9565b60443560243561107982612b64565b9261108760405194856117d3565b828452601f1961109684612b64565b0160005b81811061111157505060005b8381106110bb57604051806105b88782611005565b61110c906110f1610b886110e18560018060a01b0316600052600b602052604060002090565b6110eb8488611f43565b90610d75565b6110fb8288612bb3565b526111068187612bb3565b50611f89565b6110a6565b60209061111c614971565b8282890101520161109a565b3461030b57606036600319011261030b57600435602435611148816103d9565b604435611153611ea0565b600161115e8461393d565b0361124857906111d960036111ca611221946111798761390a565b506111ad610e936104bb856111a485610e758b60018060a01b0316600052600b602052604060002090565b50015460ff1690565b6001600160a01b0385166000908152600b60205260409020610d75565b5001805460ff19166001179055565b60036111ef84600052600a602052604060002090565b0154907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316613211565b7fef3bf8c64bc480286c4f3503b870ceb23e648d2d902e31fb7bb46680da6de8ad600080a2005b6040516305b73c1360e51b815260048101849052602490fd5b3461030b57602036600319011261030b5760043561127e816103d9565b60018060a01b03166000526009602052602060ff604060002054166040519015158152f35b3461030b57600080600319360112610af9576112bd611ea0565b6202a30042018042116112f557806015557f7c907b8735e3b64d39d41766c0e80d8acd40b0a9fd407745b5d0b396488a4b488280a280f35b611f02565b3461030b57600080600319360112610af957611314611ea0565b600180546001600160a01b03199081169091558154908116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b3461030b57602036600319011261030b576001600160401b03600435611385816103c8565b166000526007602052602060ff604060002054166040519015158152f35b3461030b57600036600319011261030b57600154336001600160a01b03909116036113d15761001933611eb4565b60405163118cdaa760e01b8152336004820152602490fd5b3461030b57600036600319011261030b576020601554604051908152f35b3461030b57602036600319011261030b57600435611424816103d9565b60018060a01b0316600052600b6020526020604060002054604051908152f35b3461030b57602036600319011261030b576004356001600160401b03811161030b57611474903690600401610417565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116330361157b576020820135906114b4826103c8565b60206114c36040850185613401565b908092918101031261030b57356114d9816103d9565b16906114fe6104bb610495836001600160401b03166000526008602052604060002090565b61155857506001600160a01b0381166000908152600960205260409020611528906104bb90610495565b6115355761001982613736565b6040516368692cbb60e11b81526001600160a01b03919091166004820152602490fd5b60405163042784cf60e31b81526001600160401b03919091166004820152602490fd5b6040516335fdcccd60e21b8152336004820152602490fd5b6002111561159d57565b634e487b7160e01b600052602160045260246000fd5b602090818101828252835180915282604080930194019260009283905b8382106115e05750505050505090565b909192939495838751805183520151600281101561160e5784820152810195830194939291600101906115d0565b634e487b7160e01b87526021600452602487fd5b3461030b57604036600319011261030b57600435602435600d54908083018084116112f55782101561170f57508181039081116112f5575b61166381612b64565b9161167160405193846117d3565b818352601f1961168083612b64565b0160005b8181106116f857505060005b8281106116a557604051806105b886826115b3565b806116de6116be6116b96116f39486611f43565b6133b7565b6116ca81939293611593565b6116d26117f4565b928352602083016133ab565b6116e88287612bb3565b526111068186612bb3565b611690565b602090611703613382565b82828801015201611684565b905061165a565b3461030b57600036600319011261030b576000546040516001600160a01b039091168152602090f35b8015150361030b57565b35906103f58261173f565b634e487b7160e01b600052604160045260246000fd5b6001600160401b03811161177d57604052565b611754565b60a081019081106001600160401b0382111761177d57604052565b604081019081106001600160401b0382111761177d57604052565b606081019081106001600160401b0382111761177d57604052565b90601f801991011681019081106001600160401b0382111761177d57604052565b604051906103f58261179d565b6040519061012082018281106001600160401b0382111761177d57604052565b60405190608082018281106001600160401b0382111761177d57604052565b604051906103f582611782565b60405190602082018281106001600160401b0382111761177d57604052565b60ff81160361030b57565b3461030b5761016036600319011261030b57600435611895816103c8565b602435906118a2826103d9565b6044356118ae816103d9565b60a4356118ba8161173f565b60a03660c319011261030b576105b8936105a893604051936118db85611782565b60c4356118e7816103d9565b855260e4356118f58161186c565b602086015261010435604086015261012435611910816103d9565b6060860152610144356119228161173f565b6080860152608435926064359261324a565b604090600319011261030b5760043561194c816103c8565b906024356107e78161173f565b3461030b576100196001600160401b0361197236611934565b919061197c611ea0565b16600052600760205260406000209060ff801983541691151516179055565b3461030b57604036600319011261030b576024356004356119bb826103d9565b6119c3611ea0565b6119d8601554801515908161099c5750611f50565b6000601555614e20811015611a0c57601255601380546001600160a01b0319166001600160a01b0392909216919091179055005b60405162461bcd60e51b815260206004820152601060248201526f13585e0819995948195e18d95959195960821b6044820152606490fd5b6001600160401b03811161177d57601f01601f191660200190565b929192611a6b82611a44565b91611a7960405193846117d3565b82948184528183011161030b578281602093846000960137010152565b9080601f8301121561030b578160206107e793359101611a5f565b3461030b57602036600319011261030b576004356001600160401b03811161030b57611aeb611ae66020923690600401611a96565b611f98565b6040516001600160a01b039091168152f35b3461030b57600036600319011261030b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461030b57600036600319011261030b576013546040516001600160a01b039091168152602090f35b3461030b57600036600319011261030b576014546040516001600160a01b039091168152602090f35b90600182811c92168015611bc4575b6020831014611bae57565b634e487b7160e01b600052602260045260246000fd5b91607f1691611ba3565b9060009291805491611bdf83611b94565b918282526001938481169081600014611c415750600114611c01575b50505050565b90919394506000526020928360002092846000945b838610611c2d575050505001019038808080611bfb565b805485870183015294019385908201611c16565b9294505050602093945060ff191683830152151560051b01019038808080611bfb565b999897949093611cb49692610100989515158c5260208c015260018060a01b0380941660408c015260608b015260808a01521660a0880152151560c08701526101208060e08801528601906109c3565b930152565b3461030b57602036600319011261030b57600435600052600a602052604060002060ff815416906105b860018201549260018060a01b039283600282015416916003820154906004830154600584015492600760405195611d2887611d218160068501611bce565b03886117d3565b015495604051998a9960ff8760a01c169616948a611c64565b3461030b576100196001600160401b03611d5a36611934565b9190611d64611ea0565b16600052600860205260406000209060ff801983541691151516179055565b3461030b57600036600319011261030b576011546040516001600160a01b039091168152602090f35b3461030b57600036600319011261030b576001546040516001600160a01b039091168152602090f35b3461030b57604036600319011261030b57610019600435611df5816103d9565b60243590611e028261173f565b611e0a611ea0565b60018060a01b0316600052600960205260406000209060ff801983541691151516179055565b3461030b57602036600319011261030b57600435611e4d816103d9565b611e55611ea0565b611e6a601554801515908161099c5750611f50565b60006015556001600160a01b03811615611e875761001990611eb4565b604051631e4fbdf760e01b815260006004820152602490fd5b6000546001600160a01b031633036113d157565b60018060a01b031990816001541660015560005460018060a01b038092168093821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b634e487b7160e01b600052601160045260246000fd5b90601f82018092116112f557565b90610e1082018092116112f557565b60170190816017116112f557565b919082018092116112f557565b15611f5757565b60405162461bcd60e51b815260206004820152600a602482015269151a5b595b1bd8dad95960b21b6044820152606490fd5b60001981146112f55760010190565b80516013198101919082116112f55760178092049160009283915b818310611fc1575050505090565b90919293506014611fd58186511015612183565b818551106120005750611ff9611ff3611fed866121c7565b95612057565b93611f89565b9190611fb3565b6064906040519062461bcd60e51b825260206004830152602482015273746f55696e7432345f6f75744f66426f756e647360601b6044820152fd5b6000198101919082116112f557565b919082039182116112f557565b805160161991828201908282116112f55761207c8261207581611f18565b1015612106565b61208a601761207584611f35565b61209f815161209884611f35565b1115612143565b601783036120bc5750505050604051600081526020810160405290565b601760405194601f8416801560051b9182828901019687010193010101905b8084106120f35750508252601f01601f191660405290565b90928351815260208091019301906120db565b1561210d57565b60405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606490fd5b1561214a57565b60405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606490fd5b1561218a57565b60405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b6044820152606490fd5b6037906121d8602b82511015612183565b015160601c90565b156121e757565b60405162461bcd60e51b815260206004820152602360248201527f4d75737420626520612076616c69642064657374696e6174696f6e206164647260448201526265737360e81b6064820152608490fd5b91906101208382031261030b5761224d611801565b9261225781611749565b8452612265602082016103ea565b602085015260408101356040850152606081013560608501526080810135608085015261229460a08201611749565b60a08501526122a560c08201611749565b60c08501526001600160401b039160e082013583811161030b57816122cb918401611a96565b60e0860152610100928383013590811161030b576122e99201611a96565b90830152565b356107e78161173f565b356107e7816103d9565b9081602091031261030b575190565b6040513d6000823e3d90fd5b1561232557565b60405162461bcd60e51b81526020600482015260116024820152704d757374207377617020746f205553444360781b6044820152606490fd5b91909160808060a08301948035612374816103d9565b6001600160a01b03908116855260ff60208301356123918161186c565b1660208601526040820135604086015260608201356123af816103d9565b16606085015201356123c08161173f565b1515910152565b6040516323b872dd60e01b60208201526001600160a01b03928316602482015292909116604483015260648201929092526103f59161241382608481015b03601f1981018452836117d3565b61242d565b9081602091031261030b57516107e78161173f565b6000806124569260018060a01b03169360208151910182865af161244f61249f565b90836124cf565b8051908115159182612484575b505061246c5750565b60249060405190635274afe760e01b82526004820152fd5b6124979250602080918301019101612418565b153880612463565b3d156124ca573d906124b082611a44565b916124be60405193846117d3565b82523d6000602084013e565b606090565b906124f657508051156124e457805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580612529575b612507575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156124ff565b909192936001600160401b0382169460008681526020976007895260409160ff83822054161561272f576001600160a01b03918783161561271e5761257a9086868b8b61473d565b835163b0f479a160e01b8152600493908c818681305afa90811561061e5784916126f1575b50168451976320487ded60e01b89528c89806125be86858a840161275c565b0381855afa98891561061e5784996126d2575b5088156126c25747891161269f57918161260d936125f28f948b908b612867565b8a88518096819582946396f4e9f960e01b84528b840161275c565b03925af19a8b1561061e57829b612680575b505080808047335af161263061249f565b50156126725750927f437cb3c5ba4364504dda6ba3c906ffb0897c7beeb1675f3aaf22a1b9a99b3994949261266c928997955195869586612828565b0390a390565b905163d6bda27560e01b8152fd5b612697929b50803d1061071b5761070c81836117d3565b98388061261f565b8551634787a10360e11b815247818701908152602081018b905281906040010390fd5b8551636eca2e4b60e01b81528590fd5b6126ea9199508d803d1061071b5761070c81836117d3565b97386125d1565b61271191508d803d10612717575b61270981836117d3565b810190612747565b3861259f565b503d6126ff565b835163502ffa3f60e11b8152600490fd5b8251630a503cdb60e01b8152600481018a9052602490fd5b9081602091031261030b57516107e7816103d9565b906001600160401b03909392931681526040602091818382015261278b855160a08484015260e08301906109c3565b916127a78487015193603f1994858583030160608601526109c3565b8187015194848483030160808501528080875193848152019601926000905b8382106127ff5750505060608701516001600160a01b031660a08401525093946107e7945060c0906080015192828503019101526109c3565b845180516001600160a01b031689528301518884015296870196938201936001909101906127c6565b919061285060a09497969592600180871b03809316855260c0602086015260c08501906109c3565b961660408301526060820152600060808201520152565b604051636eb1769f60e11b81523060048201526001600160a01b038084166024830152602094939216908481604481855afa801561061e5784916000916129bd575b50106128b55750505050565b60405163095ea7b360e01b8582018181526001600160a01b038516602484015260006044808501829052845261292797929392601f199290919081906128fc6064876117d3565b85519082895af161290b61249f565b8161298d575b5080612983575b15612930575b505050506129da565b38808080611bfb565b604051908101939093526001600160a01b03851660248401526000604484015261297a926129749161296e9082606481015b039081018352826117d3565b8461242d565b8261242d565b3880808061291e565b50843b1515612918565b805180159250839083156129a5575b50505038612911565b6129b59350820181019101612418565b38828161299c565b6129d49150863d881161071b5761070c81836117d3565b386128a9565b60405163095ea7b360e01b602082018181526001600160a01b0385166024840152604480840196909652948252939092601f1991612a196064866117d3565b84516001600160a01b03851691600091829182855af190612a3861249f565b82612a9e575b5081612a93575b5015612a53575b5050505050565b60405160208101959095526001600160a01b0316602485015260006044850152612a899361241391612974908260648101612962565b3880808080612a4c565b90503b151538612a45565b80519192508115918215612ab6575b50509038612a3e565b612ac99250602080918301019101612418565b3880612aad565b15612ad757565b60405162461bcd60e51b815260206004820152601e60248201527f43616c6c20746f20706172617377617020726f75746572206661696c656400006044820152606490fd5b15612b2357565b60405162461bcd60e51b81526020600482015260196024820152780a8ded6cadc40d2dc40daeae6e840dcdee840c4ca40ae8aa89603b1b6044820152606490fd5b6001600160401b03811161177d5760051b60200190565b60405190612b88826117b8565b600282526040366020840137565b805115610d915760200190565b805160011015610d915760400190565b8051821015610d915760209160051b010190565b91909493929460a0830190835260209060008285015260a0604085015282518091528160c0850193019160005b828110612c155750505050906080919460018060a01b031660608201520152565b83516001600160a01b031685529381019392810192600101612bf4565b9291909594939560a084019084526020918285015260a0604085015282518091528160c0850193019160005b828110612c7f5750505050906080919460018060a01b031660608201520152565b83516001600160a01b031685529381019392810192600101612c5e565b6020815260806060612cb9845183602086015260a08501906109c3565b60208501516001600160a01b03166040858101919091528501518285015293015191015290565b15612ce757565b60405162461bcd60e51b81526020600482015260136024820152724d757374207377617020696e746f205553444360681b6044820152606490fd5b818102929181159184041417156112f557565b602081810180516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169392918116808503612db7575050505060406107e79201515b612db2612d9b612d9260125484612d22565b620186a0900490565b601354909384916001600160a01b03165b90613211565b61204a565b85511561312a575060a0850151156130f65781516001600160a01b0316612e077f000000000000000000000000000000000000000000000000000000000000000091838316938491161415612b1c565b82516001600160a01b0316601154909290612e3c90612e2e906001600160a01b031661063b565b936040890194855191612867565b612e70612e58612e4a612b7b565b95516001600160a01b031690565b612e6186612b96565b6001600160a01b039091169052565b612e7d82612e6186612ba3565b6040516370a0823160e01b8082523060048301529094908686602481865afa95861561061e576000966130d7575b50601154612ec1906001600160a01b031661063b565b855160608b015191612ed242611f26565b94813b1561030b5760008094612f0060405198899687958694635c11d79560e01b8652309260048701612c32565b03925af191821561061e5787926130c4575b5060405190815230600482015291829060249082905afa93841561061e57612f6594612f46926000916130a7575b5061204a565b91829052601054612f5f906001600160a01b031661063b565b90612867565b6040516370a0823160e01b808252306004830152939091908183602481875afa92831561061e5760009361307f575b5081612ff98260e06000940151906080604082015191015190612fb5611821565b928352308584015260408301526060820152601054612fdc906001600160a01b031661063b565b9060405194858094819363b858183f60e01b835260048301612c9c565b03925af190811561061e57600091613062575b50604051948552306004860152918185602481875afa801561061e576107e79561304093600092613045575b505011612ce0565b612d80565b61305b9250803d1061071b5761070c81836117d3565b3880613038565b6130799150823d841161071b5761070c81836117d3565b3861300c565b6000919350612ff961309e8492833d851161071b5761070c81836117d3565b94925050612f94565b6130be9150873d891161071b5761070c81836117d3565b38612f40565b806106126130d19261176a565b38612f12565b6130ef919650873d891161071b5761070c81836117d3565b9438612eab565b5051613125906001600160a01b031660105461311a906001600160a01b031661063b565b604086015191612867565b612f65565b91505061315e7f00000000000000000000000000000000000000000000000000000000000000009182604087015191612867565b6040516370a0823160e01b808252306004830152949091908383602481885afa92831561061e576000936131e3575b5060006131b3926101008293015190828783519301915af16131ad61249f565b50612ad0565b6040519384523060048501528184602481865afa801561061e576107e794613040936000926106f557505061204a565b60009193506131b3926101006132068493883d8a1161071b5761070c81836117d3565b95935050925061318d565b60405163a9059cbb60e01b60208201526001600160a01b03909216602483015260448201929092526103f5916124138260648101612405565b94916132e094939192604051906132a78261240560209b8c830191909160808060a083019460018060a01b0380825116855260ff602083015116602086015260408201516040860152606082015116606085015201511515910152565b6000901561337c57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031693614823565b60405163b0f479a160e01b8152908382600481305afa801561061e5761332793859360009261335d575b506040518095819482936320487ded60e01b84526004840161275c565b03916001600160a01b03165afa91821561061e5760009261334757505090565b6107e79250803d1061071b5761070c81836117d3565b613375919250843d86116127175761270981836117d3565b903861330a565b93614823565b60405190604082018281106001600160401b0382111761177d5760405260006020838281520152565b600282101561159d5752565b600d54811015610d91577fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb501546000818152600f60205260409020549091565b356107e7816103c8565b903590601e198136030182121561030b57018035906001600160401b03821161030b5760200191813603831361030b57565b60208183031261030b578035906001600160401b03821161030b57019080601f8301121561030b578160206107e793359101611a5f565b601f8111613476575050565b6000906006825260208220906020601f850160051c830194106134b4575b601f0160051c01915b8281106134a957505050565b81815560010161349d565b9092508290613494565b90601f81116134cc57505050565b600091825260208220906020601f850160051c83019410613508575b601f0160051c01915b8281106134fd57505050565b8181556001016134f1565b90925082906134e8565b9081516001600160401b03811161177d5761353781613532600654611b94565b61346a565b602080601f83116001146135735750819293600092613568575b50508160011b916000199060031b1c191617600655565b015190503880613551565b6006600052601f19831694909190600080516020614a0a833981519152926000905b8782106135cd5750508360019596106135b4575b505050811b01600655565b015160001960f88460031b161c191690553880806135a9565b80600185968294968601518155019501930190613595565b903590601e198136030182121561030b57018035906001600160401b03821161030b57602001918160061b3603831361030b57565b9015610d915790565b604051906000826006549161363783611b94565b8083526001938085169081156136ab575060011461365d575b506103f5925003836117d3565b60066000908152600080516020614a0a83398151915294602093509091905b8183106136935750506103f5935082010138613650565b8554888401850152948501948794509183019161367c565b90506103f594506020925060ff191682840152151560051b82010138613650565b908160a091031261030b576080604051916136e683611782565b80516136f1816103d9565b835260208101516137018161186c565b602084015260408101516040840152606081015161371e816103d9565b6060840152015161372e8161173f565b608082015290565b803561374181600355565b61376161375c6137546060850185613401565b810190613433565b613512565b7f08350cd303c5b1734ccfe940e7d673b1a422b168e8e01ac78412a965c64c56666001600160401b03608084016137c96137a76106a46137a184896135e5565b9061361a565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b6138c66137ef6137d983886135e5565b91906137e8602093849261361a565b0135600555565b6138086137fa613623565b8280825183010191016136cc565b966138148282016133f7565b88519094906001600160a01b0316986138308482015160ff1690565b936040820151906138756137a161385e606061384f6080880151151590565b9601516001600160a01b031690565b9561386f6106a46137a1838b6135e5565b976135e5565b604080516001600160a01b039e8f16815260ff90981660208901528701929092529115156060860152918a1660808501529890911660a0830152969096013560c087015291169390819060e0820190565b0390a3565b156138d257565b60405162461bcd60e51b815260206004820152601060248201526f105b1c9958591e481c995919595b595960821b6044820152606490fd5b6107e79080600052600f60205260006040812055613987565b6107e79080600052600f6020526001604060002055613987565b80600052600f60205260406000205490811580613975575b61395d575090565b6024906040519063015ab34360e11b82526004820152fd5b50600e60205260406000205415613955565b6000818152600e60205260408120546139f557600d5490600160401b82101561177d576001820180600d55821015610d91577fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5909101829055600d54918152600e6020526040902055600190565b905090565b9190916101208184031261030b57613a10611801565b92613a1a82611749565b845260208201356020850152613a32604083016103ea565b60408501526060820135606085015260808201356080850152613a5760a083016103ea565b60a0850152613a6860c08301611749565b60c085015260e0820135906001600160401b03821161030b57613a8c918301611a96565b60e08401526101008091013590830152565b60208152613ab160208201835115159052565b60208201516040828101919091528201516001600160a01b0316606082015260608201516080820152608082015160a0820152613afd60a083015160c083019060018060a01b03169052565b60c0820151151560e082015260e082015161012090613b296101009183838601526101408501906109c3565b93015191015290565b91909182516001600160401b03811161177d57613b5981613b538454611b94565b846134be565b602080601f8311600114613b95575081929394600092613b8a575b50508160011b916000199060031b1c1916179055565b015190503880613b74565b90601f19831695613bab85600052602060002090565b926000905b888210613be857505083600195969710613bcf575b505050811b019055565b015160001960f88460031b161c19169055388080613bc5565b80600185968294968601518155019501930190613bb0565b90610100600791613c26613c148251151590565b859060ff801983541691151516179055565b6020810151600185015560408101516002850180546001600160a01b0319166001600160a01b03928316179055606082015160038601556080820151600486015560a08083015160058701805460c0860151929094166001600160a81b03199094169390931790151590911b60ff60a01b16179055613cac60e082015160068601613b32565b0151910155565b8054600160401b81101561177d57613cd091600182018155610d75565b919091613d3857805182546001600160a01b039182166001600160a01b0319918216178455602083015160018501805491909316911617905560049060809060408101516002850155613cac60608201511515600386019060ff801983541691151516179055565b634e487b7160e01b600052600060045260246000fd5b815181546001600160a01b0319166001600160a01b039190911617815590600190602090613cac565b9060206107e79281815201906109c3565b613d939036906139fa565b303b1561030b576040516303e1cf7f60e31b815260008180613db88560048301613a9e565b038183305af19081613f35575b50613f32577f55bc02a9ef6f146737edeeb425738006f67f077e7138de3bf84a15bde1a5b56f613f2d613df661249f565b92613f1f613ecd6020830192613e0c8451613923565b50613e2b81613e268651600052600a602052604060002090565b613c00565b60a0810180516001600160a01b03166000908152600b602052604090209091613ec09183516060906001600160a01b0316920151875190613eaa613e6d611840565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152946001600160a01b03166020860152565b6040840152600060608401526080830152613cb3565b516001600160a01b031690565b6001600160a01b0381166000908152600b6020526040902054613f00613ef16117f4565b6001600160a01b039093168352565b6020820152613f1a8351600052600c602052604060002090565b613d4e565b519260405191829182613d77565b0390a2565b50565b80610612613f429261176a565b38613dc5565b15613f4f57565b60405162461bcd60e51b815260206004820152602660248201527f4e6f7420656e6f75676820757364632062616c616e636520746f2065786563756044820152653a32903a3c1760d11b6064820152608490fd5b15613faa57565b60405162461bcd60e51b815260206004820152602360248201527f416d6f756e746f7574206973206c657373207468616e206d696e416d6f756e7460448201526213dd5d60ea1b6064820152608490fd5b60608101908151614013610100830191825110613f48565b81511561443f576040820151614058919061404e9061403a906001600160a01b031661063b565b6014546001600160a01b0316835191613211565b835190519061204a565b8083526040828101805190949193926001600160a01b0392917f0000000000000000000000000000000000000000000000000000000000000000841691908416821461439357508151855163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038116600483015260248201929092526020929190838180604481010381600080975af1801561061e57614366575b50875161411b9061063b906001600160a01b031681565b87516370a0823160e01b80825230600483015292918590829060249082905afa90811561061e5784908192614343575b5080614169929360e08b015190828983519301915af16131ad61249f565b885184906141819061063b906001600160a01b031681565b8951938452306004850152839060249082905afa801561061e576141ab92849161432c575061204a565b6141bb6080870151821015613fa3565b85886141ca60c0830151151590565b156142dc575050847f00000000000000000000000000000000000000000000000000000000000000001690813b156142d8578751632e1a7d4d60e01b815260048101919091529082908290602490829084905af1801561061e576142c5575b5060a08501518190819081906001600160a01b031647905af161424a61249f565b50156142b457906142af8361428f61428160a06000805160206149ea83398151915297965b8901519801516001600160a01b031690565b98516001600160a01b031690565b925196519384931697169542908360209093929193604081019481520152565b0390a4565b845163d6bda27560e01b8152600490fd5b806106126142d29261176a565b38614229565b8280fd5b6142af935060a08796956143276000805160206149ea833981519152999561428f95612dac8561431861063b614281995160018060a01b031690565b9201516001600160a01b031690565b61426f565b6130be9150853d871161071b5761070c81836117d3565b614169925061435f8291883d8a1161071b5761070c81836117d3565b925061414b565b61438590843d861161438c575b61437d81836117d3565b810190612418565b5038614104565b503d614373565b60a085018051875163a9059cbb60e01b81526001600160a01b039091166004820152602481019290925291965090939092919060208460448160008b5af193841561061e5760206142af92614408926000805160206149ea83398151915297614422575b50015195516001600160a01b031690565b915195519586524260208701529116939081906040820190565b61443890833d811161438c5761437d81836117d3565b50386143f7565b6040516370a0823160e01b8082523060048301527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0381169260209290918383602481885afa92831561061e576000936145a2575b506144ea906144e26144ab612b7b565b916144d97f0000000000000000000000000000000000000000000000000000000000000000612e6185612b96565b612e6183612ba3565b8651906145c5565b506040519081523060048201528281602481875afa90811561061e57614518936000926106f557505061204a565b813b1561030b57604051632e1a7d4d60e01b815260048101829052916000908390602490829084905af191821561061e5760009283928392839261458f575b5060145461456f9061063b906001600160a01b031681565b828215614586575bf11561061e576140589061404e565b506108fc614577565b8061061261459c9261176a565b38614557565b6144ea9193506145be90853d871161071b5761070c81836117d3565b929061449b565b906145dc613ec06145d6845161203b565b84612bb3565b614601826145ec613ec086612b96565b601154612f5f906001600160a01b031661063b565b6040516370a0823160e01b80825230600483015260209491936001600160a01b039390931692918585602481875afa94851561061e576000956146e2575b50601154614655906001600160a01b031661063b565b61465e42611f26565b90803b1561030b5761468d946000809460405197889586948593635c11d79560e01b8552309160048601612bc7565b03925af191821561061e5785926146cf575b5060405190815230600482015291829060249082905afa90811561061e576107e7936000926106f557505061204a565b806106126146dc9261176a565b3861469f565b6146fa919550863d881161071b5761070c81836117d3565b933861463f565b6040519061470e8261179d565b600182528160005b602090818110156147385760209161472c613382565b90828501015201614716565b505050565b926148026147c3956147f26080946147e69760009760405161475e81611782565b606098818a8093528260208201528260408201528b838201520152614781614701565b9661478d613ef16117f4565b602082015261479b87612b96565b526147a586612b96565b50604080516001600160a01b03909216602083015290998a91820190565b03906147d7601f19928381018c528b6117d3565b60405198899160208301613d77565b039081018852876117d3565b6147fa61184d565b908152614902565b9361480b611840565b95865260208601526040850152830152608082015290565b926148db6148ac966147f260809461372e976148cf999760405161484681611782565b606098818a809352826020820152826040820152600083820152015261486a614701565b96614876613ef16117f4565b602082015261488487612b96565b5261488e86612b96565b50604080516001600160a01b039092166020830152909a8b91820190565b03906148c0601f19928381018d528c6117d3565b604051998a9160208301613d77565b039081018952886117d3565b946148e4611840565b968752602087015260408601526001600160a01b0390911690840152565b604051906397a657c960e01b6020830152516024820152602481526107e7816117b8565b1561492d57565b606460405162461bcd60e51b815260206004820152602060248201527f4d757374206265206578656375746564206279207468652072656365697665726044820152fd5b6040519061497e82611782565b60006080838281528260208201528260408201528260608201520152565b906040516149a981611782565b82546001600160a01b039081168252600184015416602082015260028301546040820152600383015460ff1615156060820152600490920154608083015256feb6a94e758a1d7c9bf7c5bb12f10aa442af232ce353d686ae30a2c0935dfe34a0f652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3fa2646970667358221220cc48d35e498458d0503857f92b2844496e7661e5cd39c7a5cb6217382574b8fd64736f6c6343000814003300000000000000000000000080226fc0ee2b096224eeac085bb9a8cba1146f7d000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000e1ff5a4c489b11e094bfbb5d23c6d4597a3a79ad000000000000000000000000a24e8ce77d4a7ce869da3730e6560bfb66553f940000000000000000000000006a000f20005980200259b80c51020030400010680000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45000000000000000000000000a24e8ce77d4a7ce869da3730e6560bfb66553f94
Deployed Bytecode
0x6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c806301f59d16146102fb57806301ffc9a7146102f6578063046d293c146102f157806309abd96e146102ec5780630dc91306146102e757806319db9cd9146102e25780631c3c0ea8146102dd5780631f0e7bf8146102d857806320446c0b146102d357806324a9d853146102ce578063263596a5146102c95780632c94785a146102c45780633aeac4e1146102bf5780633e413bee146102ba5780633e957731146102b55780633fc8cef3146102b05780634030d521146102ab5780634b127efd146102a65780634dd31560146102a157806351cff8d91461029c57806354cf2aeb146102975780635aacd56a146102925780636122750f1461028d5780636159ada11461028857806363a5d29814610283578063715018a61461027e57806375c67c661461027957806379ba50971461027457806380665c2a1461026f57806382b55c7b1461026a57806385572ffb146102655780638d9d89fe146102605780638da5cb5b1461025b57806393b8cb441461025657806396d3b83d14610251578063988950951461024c578063a05bdb5b14610247578063b0f479a114610242578063b3f006741461023d578063c34c08e514610238578063d0d1fc3d14610233578063db04fa491461022e578063deadbc1414610229578063e30c397814610224578063eab5b02c1461021f5763f2fde38b0361000e57611e30565b611dd5565b611dac565b611d83565b611d41565b611cb9565b611b6b565b611b42565b611afd565b611ab1565b61199b565b611959565b611877565b611716565b611622565b611444565b611407565b6113e9565b6113a3565b611360565b6112fa565b6112a3565b611261565b611128565b61104d565b610fe7565b610f4e565b610e33565b610d96565b610d1c565b610cd7565b610c91565b610c4c565b610b9d565b610b35565b610a03565b6109a6565b61093c565b6108dd565b610870565b6107ea565b610794565b610425565b610383565b61032d565b610310565b600091031261030b57565b600080fd5b3461030b57600036600319011261030b576020604051614e208152f35b3461030b57602036600319011261030b5760043563ffffffff60e01b811680910361030b576020906385572ffb60e01b8114908115610372575b506040519015158152f35b6301ffc9a760e01b14905038610367565b3461030b57600036600319011261030b576040517f0000000000000000000000006a000f20005980200259b80c51020030400010686001600160a01b03168152602090f35b6001600160401b0381160361030b57565b6001600160a01b0381160361030b57565b35906103f5826103d9565b565b908161012091031261030b5790565b60a090608319011261030b57608490565b908160a091031261030b5790565b61012036600319011261030b5760043561043e816103c8565b6024359061044b826103d9565b6064356001600160401b03811161030b5761046a9036906004016103f7565b9161047436610406565b6001600160a01b03821660009081526009602052604090206104a19061049c905b5460ff1690565b6121e0565b6104ab3685612238565b926104bf6104bb60c087016122ef565b1590565b80610753575b15610623577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03169461050390604001353461204a565b94803b1561030b57600090600460405180988193630d0e30db60e41b83525af193841561061e5761057d61055f61056f926105b8986105a898610605575b506040810161055181513461204a565b90525b80516105bc57612d35565b936040519283916020830161235e565b03601f1981018352826117d3565b604435937f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4892612532565b6040519081529081906020820190565b0390f35b6106006105cc60e0830151611f98565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0390811691161461231e565b612d35565b806106126106189261176a565b80610300565b38610541565b612312565b60209493949384810161064761063b61063b836122f9565b6001600160a01b031690565b6040516370a0823160e01b8082523060048301529290918890839060249082905afa93841561061e578892600095610722575b5061063b826106a461063b93604061069761063b6106a9986122f9565b91013590309033906123c7565b6122f9565b604051928352306004840152829060249082905afa90811561061e576105b8976106eb61056f9461057d9461055f946105a89b6000926106f5575b505061204a565b6040820152610554565b6107149250803d1061071b575b61070c81836117d3565b810190612303565b38806106e4565b503d610702565b61063b9195506106a9926106a461074861063b93873d891161071b5761070c81836117d3565b97935050925061067a565b50610760602086016122f9565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b039081169116146104c5565b3461030b57600036600319011261030b576010546040516001600160a01b039091168152602090f35b602060031982011261030b57600435906001600160401b03821161030b576107e7916004016103f7565b90565b3461030b576107f8366107bd565b600280541461085e57600280556014546001600160a01b0316330361082a5761082090613d88565b6100196001600255565b60405162461bcd60e51b815260206004820152600c60248201526b3737ba1032bc32b1baba37b960a11b6044820152606490fd5b604051633ee5aeb560e01b8152600490fd5b3461030b57602036600319011261030b5760043561088d816103d9565b610895611ea0565b6014546001600160a01b0391821691829082167f0ef3c7eb9dbcf33ddf032f4cce366a07eda85eed03e3172e4a90c4cc16d57886600080a36001600160a01b03191617601455005b3461030b576108eb366107bd565b303303610905576109006100199136906139fa565b613ffb565b60405163029a949d60e31b8152600490fd5b604090600319011261030b5760043561092f816103d9565b906024356107e7816103d9565b3461030b5761094a36610917565b90610953611ea0565b610969601554801515908161099c575b50611f50565b6000601555601080546001600160a01b039384166001600160a01b03199182161790915560118054929093169116179055005b9050421138610963565b3461030b57600036600319011261030b5760206040516103e88152f35b919082519283825260005b8481106109ef575050826000602080949584010152601f8019910116010190565b6020818301810151848301820152016109ce565b3461030b57600080600319360112610af95760035460018060a01b0360045416600554604051938481600654610a3881611b94565b80845290600190818116908115610ad65750600114610a8b575b5050610a60925003856117d3565b610a7c60405194859485526080602086015260808501906109c3565b91604084015260608301520390f35b60068552600080516020614a0a833981519152946020935091905b818310610abe575050610a6093508201013880610a52565b85548a84018501529485019489945091830191610aa6565b915050610a6094506020925060ff191682840152151560051b8201013880610a52565b80fd5b6080809160018060a01b038082511685526020820151166020850152604081015160408501526060810151151560608501520151910152565b3461030b57602036600319011261030b57610b4e614971565b50600435600052600c60205260a0610b8e610b886040600020600180851b03815416600052600b6020526001604060002091015490610d75565b5061499c565b610b9b6040518092610afc565bf35b3461030b57610bab36610917565b610bb3611ea0565b610bc8601554801515908161099c5750611f50565b610bd26000601555565b6040516370a0823160e01b81523060048201526001600160a01b039190911691602082602481865afa91821561061e57600092610c2c575b508115610c1a5761001992613211565b604051630686827b60e51b8152600490fd5b610c4591925060203d811161071b5761070c81836117d3565b9038610c0a565b3461030b57600036600319011261030b576040517f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b03168152602090f35b3461030b57602036600319011261030b576004356000908152600c6020908152604091829020805460019091015483516001600160a01b03909216825291810191909152f35b3461030b57600036600319011261030b576040517f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168152602090f35b3461030b57602036600319011261030b576001600160401b03600435610d41816103c8565b166000526008602052602060ff604060002054166040519015158152f35b634e487b7160e01b600052603260045260246000fd5b8054821015610d91576000526005602060002091020190600090565b610d5f565b3461030b57604036600319011261030b57600435610db3816103d9565b6001600160a01b039081166000908152600b6020526040902080546024359081101561030b57610de291610d75565b508054600182015460028301546003840154600490940154604080516001600160a01b03958816861681529690931690931660208601529084015260ff90911615156060830152608082015260a090f35b3461030b57604036600319011261030b57600435610e50816103d9565b6001600160a01b0381166000908152600b60205260409020610e7a9060243590610d75565b610d75565b50610ea560038201610e98610e936104bb835460ff1690565b6138cb565b805460ff19166001179055565b6001810154610ec790610ec0906001600160a01b031661063b565b3314614926565b60048101908154926001610eda8561393d565b03610f3557610eec610f0d939461390a565b508154600290610f04906001600160a01b031661063b565b92015491613211565b547fef3bf8c64bc480286c4f3503b870ceb23e648d2d902e31fb7bb46680da6de8ad600080a2005b6040516305b73c1360e51b815260048101859052602490fd5b3461030b57602036600319011261030b57600435610f6b816103d9565b610f73611ea0565b610f88601554801515908161099c5750611f50565b610f926000601555565b478015610c1a576000918280808085855af1610fac61249f565b5015610fb6578280f35b604051639d11f56360e01b81523360048201526001600160a01b039190911660248201526044810191909152606490fd5b3461030b57600036600319011261030b576020601254604051908152f35b6020908160408183019282815285518094520193019160005b82811061102c575050505090565b909192938260a0826110416001948951610afc565b0195019392910161101e565b3461030b57606036600319011261030b5760043561106a816103d9565b60443560243561107982612b64565b9261108760405194856117d3565b828452601f1961109684612b64565b0160005b81811061111157505060005b8381106110bb57604051806105b88782611005565b61110c906110f1610b886110e18560018060a01b0316600052600b602052604060002090565b6110eb8488611f43565b90610d75565b6110fb8288612bb3565b526111068187612bb3565b50611f89565b6110a6565b60209061111c614971565b8282890101520161109a565b3461030b57606036600319011261030b57600435602435611148816103d9565b604435611153611ea0565b600161115e8461393d565b0361124857906111d960036111ca611221946111798761390a565b506111ad610e936104bb856111a485610e758b60018060a01b0316600052600b602052604060002090565b50015460ff1690565b6001600160a01b0385166000908152600b60205260409020610d75565b5001805460ff19166001179055565b60036111ef84600052600a602052604060002090565b0154907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316613211565b7fef3bf8c64bc480286c4f3503b870ceb23e648d2d902e31fb7bb46680da6de8ad600080a2005b6040516305b73c1360e51b815260048101849052602490fd5b3461030b57602036600319011261030b5760043561127e816103d9565b60018060a01b03166000526009602052602060ff604060002054166040519015158152f35b3461030b57600080600319360112610af9576112bd611ea0565b6202a30042018042116112f557806015557f7c907b8735e3b64d39d41766c0e80d8acd40b0a9fd407745b5d0b396488a4b488280a280f35b611f02565b3461030b57600080600319360112610af957611314611ea0565b600180546001600160a01b03199081169091558154908116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b3461030b57602036600319011261030b576001600160401b03600435611385816103c8565b166000526007602052602060ff604060002054166040519015158152f35b3461030b57600036600319011261030b57600154336001600160a01b03909116036113d15761001933611eb4565b60405163118cdaa760e01b8152336004820152602490fd5b3461030b57600036600319011261030b576020601554604051908152f35b3461030b57602036600319011261030b57600435611424816103d9565b60018060a01b0316600052600b6020526020604060002054604051908152f35b3461030b57602036600319011261030b576004356001600160401b03811161030b57611474903690600401610417565b6001600160a01b037f00000000000000000000000080226fc0ee2b096224eeac085bb9a8cba1146f7d8116330361157b576020820135906114b4826103c8565b60206114c36040850185613401565b908092918101031261030b57356114d9816103d9565b16906114fe6104bb610495836001600160401b03166000526008602052604060002090565b61155857506001600160a01b0381166000908152600960205260409020611528906104bb90610495565b6115355761001982613736565b6040516368692cbb60e11b81526001600160a01b03919091166004820152602490fd5b60405163042784cf60e31b81526001600160401b03919091166004820152602490fd5b6040516335fdcccd60e21b8152336004820152602490fd5b6002111561159d57565b634e487b7160e01b600052602160045260246000fd5b602090818101828252835180915282604080930194019260009283905b8382106115e05750505050505090565b909192939495838751805183520151600281101561160e5784820152810195830194939291600101906115d0565b634e487b7160e01b87526021600452602487fd5b3461030b57604036600319011261030b57600435602435600d54908083018084116112f55782101561170f57508181039081116112f5575b61166381612b64565b9161167160405193846117d3565b818352601f1961168083612b64565b0160005b8181106116f857505060005b8281106116a557604051806105b886826115b3565b806116de6116be6116b96116f39486611f43565b6133b7565b6116ca81939293611593565b6116d26117f4565b928352602083016133ab565b6116e88287612bb3565b526111068186612bb3565b611690565b602090611703613382565b82828801015201611684565b905061165a565b3461030b57600036600319011261030b576000546040516001600160a01b039091168152602090f35b8015150361030b57565b35906103f58261173f565b634e487b7160e01b600052604160045260246000fd5b6001600160401b03811161177d57604052565b611754565b60a081019081106001600160401b0382111761177d57604052565b604081019081106001600160401b0382111761177d57604052565b606081019081106001600160401b0382111761177d57604052565b90601f801991011681019081106001600160401b0382111761177d57604052565b604051906103f58261179d565b6040519061012082018281106001600160401b0382111761177d57604052565b60405190608082018281106001600160401b0382111761177d57604052565b604051906103f582611782565b60405190602082018281106001600160401b0382111761177d57604052565b60ff81160361030b57565b3461030b5761016036600319011261030b57600435611895816103c8565b602435906118a2826103d9565b6044356118ae816103d9565b60a4356118ba8161173f565b60a03660c319011261030b576105b8936105a893604051936118db85611782565b60c4356118e7816103d9565b855260e4356118f58161186c565b602086015261010435604086015261012435611910816103d9565b6060860152610144356119228161173f565b6080860152608435926064359261324a565b604090600319011261030b5760043561194c816103c8565b906024356107e78161173f565b3461030b576100196001600160401b0361197236611934565b919061197c611ea0565b16600052600760205260406000209060ff801983541691151516179055565b3461030b57604036600319011261030b576024356004356119bb826103d9565b6119c3611ea0565b6119d8601554801515908161099c5750611f50565b6000601555614e20811015611a0c57601255601380546001600160a01b0319166001600160a01b0392909216919091179055005b60405162461bcd60e51b815260206004820152601060248201526f13585e0819995948195e18d95959195960821b6044820152606490fd5b6001600160401b03811161177d57601f01601f191660200190565b929192611a6b82611a44565b91611a7960405193846117d3565b82948184528183011161030b578281602093846000960137010152565b9080601f8301121561030b578160206107e793359101611a5f565b3461030b57602036600319011261030b576004356001600160401b03811161030b57611aeb611ae66020923690600401611a96565b611f98565b6040516001600160a01b039091168152f35b3461030b57600036600319011261030b576040517f00000000000000000000000080226fc0ee2b096224eeac085bb9a8cba1146f7d6001600160a01b03168152602090f35b3461030b57600036600319011261030b576013546040516001600160a01b039091168152602090f35b3461030b57600036600319011261030b576014546040516001600160a01b039091168152602090f35b90600182811c92168015611bc4575b6020831014611bae57565b634e487b7160e01b600052602260045260246000fd5b91607f1691611ba3565b9060009291805491611bdf83611b94565b918282526001938481169081600014611c415750600114611c01575b50505050565b90919394506000526020928360002092846000945b838610611c2d575050505001019038808080611bfb565b805485870183015294019385908201611c16565b9294505050602093945060ff191683830152151560051b01019038808080611bfb565b999897949093611cb49692610100989515158c5260208c015260018060a01b0380941660408c015260608b015260808a01521660a0880152151560c08701526101208060e08801528601906109c3565b930152565b3461030b57602036600319011261030b57600435600052600a602052604060002060ff815416906105b860018201549260018060a01b039283600282015416916003820154906004830154600584015492600760405195611d2887611d218160068501611bce565b03886117d3565b015495604051998a9960ff8760a01c169616948a611c64565b3461030b576100196001600160401b03611d5a36611934565b9190611d64611ea0565b16600052600860205260406000209060ff801983541691151516179055565b3461030b57600036600319011261030b576011546040516001600160a01b039091168152602090f35b3461030b57600036600319011261030b576001546040516001600160a01b039091168152602090f35b3461030b57604036600319011261030b57610019600435611df5816103d9565b60243590611e028261173f565b611e0a611ea0565b60018060a01b0316600052600960205260406000209060ff801983541691151516179055565b3461030b57602036600319011261030b57600435611e4d816103d9565b611e55611ea0565b611e6a601554801515908161099c5750611f50565b60006015556001600160a01b03811615611e875761001990611eb4565b604051631e4fbdf760e01b815260006004820152602490fd5b6000546001600160a01b031633036113d157565b60018060a01b031990816001541660015560005460018060a01b038092168093821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b634e487b7160e01b600052601160045260246000fd5b90601f82018092116112f557565b90610e1082018092116112f557565b60170190816017116112f557565b919082018092116112f557565b15611f5757565b60405162461bcd60e51b815260206004820152600a602482015269151a5b595b1bd8dad95960b21b6044820152606490fd5b60001981146112f55760010190565b80516013198101919082116112f55760178092049160009283915b818310611fc1575050505090565b90919293506014611fd58186511015612183565b818551106120005750611ff9611ff3611fed866121c7565b95612057565b93611f89565b9190611fb3565b6064906040519062461bcd60e51b825260206004830152602482015273746f55696e7432345f6f75744f66426f756e647360601b6044820152fd5b6000198101919082116112f557565b919082039182116112f557565b805160161991828201908282116112f55761207c8261207581611f18565b1015612106565b61208a601761207584611f35565b61209f815161209884611f35565b1115612143565b601783036120bc5750505050604051600081526020810160405290565b601760405194601f8416801560051b9182828901019687010193010101905b8084106120f35750508252601f01601f191660405290565b90928351815260208091019301906120db565b1561210d57565b60405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606490fd5b1561214a57565b60405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606490fd5b1561218a57565b60405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b6044820152606490fd5b6037906121d8602b82511015612183565b015160601c90565b156121e757565b60405162461bcd60e51b815260206004820152602360248201527f4d75737420626520612076616c69642064657374696e6174696f6e206164647260448201526265737360e81b6064820152608490fd5b91906101208382031261030b5761224d611801565b9261225781611749565b8452612265602082016103ea565b602085015260408101356040850152606081013560608501526080810135608085015261229460a08201611749565b60a08501526122a560c08201611749565b60c08501526001600160401b039160e082013583811161030b57816122cb918401611a96565b60e0860152610100928383013590811161030b576122e99201611a96565b90830152565b356107e78161173f565b356107e7816103d9565b9081602091031261030b575190565b6040513d6000823e3d90fd5b1561232557565b60405162461bcd60e51b81526020600482015260116024820152704d757374207377617020746f205553444360781b6044820152606490fd5b91909160808060a08301948035612374816103d9565b6001600160a01b03908116855260ff60208301356123918161186c565b1660208601526040820135604086015260608201356123af816103d9565b16606085015201356123c08161173f565b1515910152565b6040516323b872dd60e01b60208201526001600160a01b03928316602482015292909116604483015260648201929092526103f59161241382608481015b03601f1981018452836117d3565b61242d565b9081602091031261030b57516107e78161173f565b6000806124569260018060a01b03169360208151910182865af161244f61249f565b90836124cf565b8051908115159182612484575b505061246c5750565b60249060405190635274afe760e01b82526004820152fd5b6124979250602080918301019101612418565b153880612463565b3d156124ca573d906124b082611a44565b916124be60405193846117d3565b82523d6000602084013e565b606090565b906124f657508051156124e457805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580612529575b612507575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156124ff565b909192936001600160401b0382169460008681526020976007895260409160ff83822054161561272f576001600160a01b03918783161561271e5761257a9086868b8b61473d565b835163b0f479a160e01b8152600493908c818681305afa90811561061e5784916126f1575b50168451976320487ded60e01b89528c89806125be86858a840161275c565b0381855afa98891561061e5784996126d2575b5088156126c25747891161269f57918161260d936125f28f948b908b612867565b8a88518096819582946396f4e9f960e01b84528b840161275c565b03925af19a8b1561061e57829b612680575b505080808047335af161263061249f565b50156126725750927f437cb3c5ba4364504dda6ba3c906ffb0897c7beeb1675f3aaf22a1b9a99b3994949261266c928997955195869586612828565b0390a390565b905163d6bda27560e01b8152fd5b612697929b50803d1061071b5761070c81836117d3565b98388061261f565b8551634787a10360e11b815247818701908152602081018b905281906040010390fd5b8551636eca2e4b60e01b81528590fd5b6126ea9199508d803d1061071b5761070c81836117d3565b97386125d1565b61271191508d803d10612717575b61270981836117d3565b810190612747565b3861259f565b503d6126ff565b835163502ffa3f60e11b8152600490fd5b8251630a503cdb60e01b8152600481018a9052602490fd5b9081602091031261030b57516107e7816103d9565b906001600160401b03909392931681526040602091818382015261278b855160a08484015260e08301906109c3565b916127a78487015193603f1994858583030160608601526109c3565b8187015194848483030160808501528080875193848152019601926000905b8382106127ff5750505060608701516001600160a01b031660a08401525093946107e7945060c0906080015192828503019101526109c3565b845180516001600160a01b031689528301518884015296870196938201936001909101906127c6565b919061285060a09497969592600180871b03809316855260c0602086015260c08501906109c3565b961660408301526060820152600060808201520152565b604051636eb1769f60e11b81523060048201526001600160a01b038084166024830152602094939216908481604481855afa801561061e5784916000916129bd575b50106128b55750505050565b60405163095ea7b360e01b8582018181526001600160a01b038516602484015260006044808501829052845261292797929392601f199290919081906128fc6064876117d3565b85519082895af161290b61249f565b8161298d575b5080612983575b15612930575b505050506129da565b38808080611bfb565b604051908101939093526001600160a01b03851660248401526000604484015261297a926129749161296e9082606481015b039081018352826117d3565b8461242d565b8261242d565b3880808061291e565b50843b1515612918565b805180159250839083156129a5575b50505038612911565b6129b59350820181019101612418565b38828161299c565b6129d49150863d881161071b5761070c81836117d3565b386128a9565b60405163095ea7b360e01b602082018181526001600160a01b0385166024840152604480840196909652948252939092601f1991612a196064866117d3565b84516001600160a01b03851691600091829182855af190612a3861249f565b82612a9e575b5081612a93575b5015612a53575b5050505050565b60405160208101959095526001600160a01b0316602485015260006044850152612a899361241391612974908260648101612962565b3880808080612a4c565b90503b151538612a45565b80519192508115918215612ab6575b50509038612a3e565b612ac99250602080918301019101612418565b3880612aad565b15612ad757565b60405162461bcd60e51b815260206004820152601e60248201527f43616c6c20746f20706172617377617020726f75746572206661696c656400006044820152606490fd5b15612b2357565b60405162461bcd60e51b81526020600482015260196024820152780a8ded6cadc40d2dc40daeae6e840dcdee840c4ca40ae8aa89603b1b6044820152606490fd5b6001600160401b03811161177d5760051b60200190565b60405190612b88826117b8565b600282526040366020840137565b805115610d915760200190565b805160011015610d915760400190565b8051821015610d915760209160051b010190565b91909493929460a0830190835260209060008285015260a0604085015282518091528160c0850193019160005b828110612c155750505050906080919460018060a01b031660608201520152565b83516001600160a01b031685529381019392810192600101612bf4565b9291909594939560a084019084526020918285015260a0604085015282518091528160c0850193019160005b828110612c7f5750505050906080919460018060a01b031660608201520152565b83516001600160a01b031685529381019392810192600101612c5e565b6020815260806060612cb9845183602086015260a08501906109c3565b60208501516001600160a01b03166040858101919091528501518285015293015191015290565b15612ce757565b60405162461bcd60e51b81526020600482015260136024820152724d757374207377617020696e746f205553444360681b6044820152606490fd5b818102929181159184041417156112f557565b602081810180516001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881169392918116808503612db7575050505060406107e79201515b612db2612d9b612d9260125484612d22565b620186a0900490565b601354909384916001600160a01b03165b90613211565b61204a565b85511561312a575060a0850151156130f65781516001600160a01b0316612e077f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291838316938491161415612b1c565b82516001600160a01b0316601154909290612e3c90612e2e906001600160a01b031661063b565b936040890194855191612867565b612e70612e58612e4a612b7b565b95516001600160a01b031690565b612e6186612b96565b6001600160a01b039091169052565b612e7d82612e6186612ba3565b6040516370a0823160e01b8082523060048301529094908686602481865afa95861561061e576000966130d7575b50601154612ec1906001600160a01b031661063b565b855160608b015191612ed242611f26565b94813b1561030b5760008094612f0060405198899687958694635c11d79560e01b8652309260048701612c32565b03925af191821561061e5787926130c4575b5060405190815230600482015291829060249082905afa93841561061e57612f6594612f46926000916130a7575b5061204a565b91829052601054612f5f906001600160a01b031661063b565b90612867565b6040516370a0823160e01b808252306004830152939091908183602481875afa92831561061e5760009361307f575b5081612ff98260e06000940151906080604082015191015190612fb5611821565b928352308584015260408301526060820152601054612fdc906001600160a01b031661063b565b9060405194858094819363b858183f60e01b835260048301612c9c565b03925af190811561061e57600091613062575b50604051948552306004860152918185602481875afa801561061e576107e79561304093600092613045575b505011612ce0565b612d80565b61305b9250803d1061071b5761070c81836117d3565b3880613038565b6130799150823d841161071b5761070c81836117d3565b3861300c565b6000919350612ff961309e8492833d851161071b5761070c81836117d3565b94925050612f94565b6130be9150873d891161071b5761070c81836117d3565b38612f40565b806106126130d19261176a565b38612f12565b6130ef919650873d891161071b5761070c81836117d3565b9438612eab565b5051613125906001600160a01b031660105461311a906001600160a01b031661063b565b604086015191612867565b612f65565b91505061315e7f0000000000000000000000006a000f20005980200259b80c51020030400010689182604087015191612867565b6040516370a0823160e01b808252306004830152949091908383602481885afa92831561061e576000936131e3575b5060006131b3926101008293015190828783519301915af16131ad61249f565b50612ad0565b6040519384523060048501528184602481865afa801561061e576107e794613040936000926106f557505061204a565b60009193506131b3926101006132068493883d8a1161071b5761070c81836117d3565b95935050925061318d565b60405163a9059cbb60e01b60208201526001600160a01b03909216602483015260448201929092526103f5916124138260648101612405565b94916132e094939192604051906132a78261240560209b8c830191909160808060a083019460018060a01b0380825116855260ff602083015116602086015260408201516040860152606082015116606085015201511515910152565b6000901561337c57507f000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca6001600160a01b031693614823565b60405163b0f479a160e01b8152908382600481305afa801561061e5761332793859360009261335d575b506040518095819482936320487ded60e01b84526004840161275c565b03916001600160a01b03165afa91821561061e5760009261334757505090565b6107e79250803d1061071b5761070c81836117d3565b613375919250843d86116127175761270981836117d3565b903861330a565b93614823565b60405190604082018281106001600160401b0382111761177d5760405260006020838281520152565b600282101561159d5752565b600d54811015610d91577fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb501546000818152600f60205260409020549091565b356107e7816103c8565b903590601e198136030182121561030b57018035906001600160401b03821161030b5760200191813603831361030b57565b60208183031261030b578035906001600160401b03821161030b57019080601f8301121561030b578160206107e793359101611a5f565b601f8111613476575050565b6000906006825260208220906020601f850160051c830194106134b4575b601f0160051c01915b8281106134a957505050565b81815560010161349d565b9092508290613494565b90601f81116134cc57505050565b600091825260208220906020601f850160051c83019410613508575b601f0160051c01915b8281106134fd57505050565b8181556001016134f1565b90925082906134e8565b9081516001600160401b03811161177d5761353781613532600654611b94565b61346a565b602080601f83116001146135735750819293600092613568575b50508160011b916000199060031b1c191617600655565b015190503880613551565b6006600052601f19831694909190600080516020614a0a833981519152926000905b8782106135cd5750508360019596106135b4575b505050811b01600655565b015160001960f88460031b161c191690553880806135a9565b80600185968294968601518155019501930190613595565b903590601e198136030182121561030b57018035906001600160401b03821161030b57602001918160061b3603831361030b57565b9015610d915790565b604051906000826006549161363783611b94565b8083526001938085169081156136ab575060011461365d575b506103f5925003836117d3565b60066000908152600080516020614a0a83398151915294602093509091905b8183106136935750506103f5935082010138613650565b8554888401850152948501948794509183019161367c565b90506103f594506020925060ff191682840152151560051b82010138613650565b908160a091031261030b576080604051916136e683611782565b80516136f1816103d9565b835260208101516137018161186c565b602084015260408101516040840152606081015161371e816103d9565b6060840152015161372e8161173f565b608082015290565b803561374181600355565b61376161375c6137546060850185613401565b810190613433565b613512565b7f08350cd303c5b1734ccfe940e7d673b1a422b168e8e01ac78412a965c64c56666001600160401b03608084016137c96137a76106a46137a184896135e5565b9061361a565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b6138c66137ef6137d983886135e5565b91906137e8602093849261361a565b0135600555565b6138086137fa613623565b8280825183010191016136cc565b966138148282016133f7565b88519094906001600160a01b0316986138308482015160ff1690565b936040820151906138756137a161385e606061384f6080880151151590565b9601516001600160a01b031690565b9561386f6106a46137a1838b6135e5565b976135e5565b604080516001600160a01b039e8f16815260ff90981660208901528701929092529115156060860152918a1660808501529890911660a0830152969096013560c087015291169390819060e0820190565b0390a3565b156138d257565b60405162461bcd60e51b815260206004820152601060248201526f105b1c9958591e481c995919595b595960821b6044820152606490fd5b6107e79080600052600f60205260006040812055613987565b6107e79080600052600f6020526001604060002055613987565b80600052600f60205260406000205490811580613975575b61395d575090565b6024906040519063015ab34360e11b82526004820152fd5b50600e60205260406000205415613955565b6000818152600e60205260408120546139f557600d5490600160401b82101561177d576001820180600d55821015610d91577fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5909101829055600d54918152600e6020526040902055600190565b905090565b9190916101208184031261030b57613a10611801565b92613a1a82611749565b845260208201356020850152613a32604083016103ea565b60408501526060820135606085015260808201356080850152613a5760a083016103ea565b60a0850152613a6860c08301611749565b60c085015260e0820135906001600160401b03821161030b57613a8c918301611a96565b60e08401526101008091013590830152565b60208152613ab160208201835115159052565b60208201516040828101919091528201516001600160a01b0316606082015260608201516080820152608082015160a0820152613afd60a083015160c083019060018060a01b03169052565b60c0820151151560e082015260e082015161012090613b296101009183838601526101408501906109c3565b93015191015290565b91909182516001600160401b03811161177d57613b5981613b538454611b94565b846134be565b602080601f8311600114613b95575081929394600092613b8a575b50508160011b916000199060031b1c1916179055565b015190503880613b74565b90601f19831695613bab85600052602060002090565b926000905b888210613be857505083600195969710613bcf575b505050811b019055565b015160001960f88460031b161c19169055388080613bc5565b80600185968294968601518155019501930190613bb0565b90610100600791613c26613c148251151590565b859060ff801983541691151516179055565b6020810151600185015560408101516002850180546001600160a01b0319166001600160a01b03928316179055606082015160038601556080820151600486015560a08083015160058701805460c0860151929094166001600160a81b03199094169390931790151590911b60ff60a01b16179055613cac60e082015160068601613b32565b0151910155565b8054600160401b81101561177d57613cd091600182018155610d75565b919091613d3857805182546001600160a01b039182166001600160a01b0319918216178455602083015160018501805491909316911617905560049060809060408101516002850155613cac60608201511515600386019060ff801983541691151516179055565b634e487b7160e01b600052600060045260246000fd5b815181546001600160a01b0319166001600160a01b039190911617815590600190602090613cac565b9060206107e79281815201906109c3565b613d939036906139fa565b303b1561030b576040516303e1cf7f60e31b815260008180613db88560048301613a9e565b038183305af19081613f35575b50613f32577f55bc02a9ef6f146737edeeb425738006f67f077e7138de3bf84a15bde1a5b56f613f2d613df661249f565b92613f1f613ecd6020830192613e0c8451613923565b50613e2b81613e268651600052600a602052604060002090565b613c00565b60a0810180516001600160a01b03166000908152600b602052604090209091613ec09183516060906001600160a01b0316920151875190613eaa613e6d611840565b6001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48168152946001600160a01b03166020860152565b6040840152600060608401526080830152613cb3565b516001600160a01b031690565b6001600160a01b0381166000908152600b6020526040902054613f00613ef16117f4565b6001600160a01b039093168352565b6020820152613f1a8351600052600c602052604060002090565b613d4e565b519260405191829182613d77565b0390a2565b50565b80610612613f429261176a565b38613dc5565b15613f4f57565b60405162461bcd60e51b815260206004820152602660248201527f4e6f7420656e6f75676820757364632062616c616e636520746f2065786563756044820152653a32903a3c1760d11b6064820152608490fd5b15613faa57565b60405162461bcd60e51b815260206004820152602360248201527f416d6f756e746f7574206973206c657373207468616e206d696e416d6f756e7460448201526213dd5d60ea1b6064820152608490fd5b60608101908151614013610100830191825110613f48565b81511561443f576040820151614058919061404e9061403a906001600160a01b031661063b565b6014546001600160a01b0316835191613211565b835190519061204a565b8083526040828101805190949193926001600160a01b0392917f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48841691908416821461439357508151855163095ea7b360e01b81527f0000000000000000000000006a000f20005980200259b80c51020030400010686001600160a01b038116600483015260248201929092526020929190838180604481010381600080975af1801561061e57614366575b50875161411b9061063b906001600160a01b031681565b87516370a0823160e01b80825230600483015292918590829060249082905afa90811561061e5784908192614343575b5080614169929360e08b015190828983519301915af16131ad61249f565b885184906141819061063b906001600160a01b031681565b8951938452306004850152839060249082905afa801561061e576141ab92849161432c575061204a565b6141bb6080870151821015613fa3565b85886141ca60c0830151151590565b156142dc575050847f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21690813b156142d8578751632e1a7d4d60e01b815260048101919091529082908290602490829084905af1801561061e576142c5575b5060a08501518190819081906001600160a01b031647905af161424a61249f565b50156142b457906142af8361428f61428160a06000805160206149ea83398151915297965b8901519801516001600160a01b031690565b98516001600160a01b031690565b925196519384931697169542908360209093929193604081019481520152565b0390a4565b845163d6bda27560e01b8152600490fd5b806106126142d29261176a565b38614229565b8280fd5b6142af935060a08796956143276000805160206149ea833981519152999561428f95612dac8561431861063b614281995160018060a01b031690565b9201516001600160a01b031690565b61426f565b6130be9150853d871161071b5761070c81836117d3565b614169925061435f8291883d8a1161071b5761070c81836117d3565b925061414b565b61438590843d861161438c575b61437d81836117d3565b810190612418565b5038614104565b503d614373565b60a085018051875163a9059cbb60e01b81526001600160a01b039091166004820152602481019290925291965090939092919060208460448160008b5af193841561061e5760206142af92614408926000805160206149ea83398151915297614422575b50015195516001600160a01b031690565b915195519586524260208701529116939081906040820190565b61443890833d811161438c5761437d81836117d3565b50386143f7565b6040516370a0823160e01b8082523060048301527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0381169260209290918383602481885afa92831561061e576000936145a2575b506144ea906144e26144ab612b7b565b916144d97f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48612e6185612b96565b612e6183612ba3565b8651906145c5565b506040519081523060048201528281602481875afa90811561061e57614518936000926106f557505061204a565b813b1561030b57604051632e1a7d4d60e01b815260048101829052916000908390602490829084905af191821561061e5760009283928392839261458f575b5060145461456f9061063b906001600160a01b031681565b828215614586575bf11561061e576140589061404e565b506108fc614577565b8061061261459c9261176a565b38614557565b6144ea9193506145be90853d871161071b5761070c81836117d3565b929061449b565b906145dc613ec06145d6845161203b565b84612bb3565b614601826145ec613ec086612b96565b601154612f5f906001600160a01b031661063b565b6040516370a0823160e01b80825230600483015260209491936001600160a01b039390931692918585602481875afa94851561061e576000956146e2575b50601154614655906001600160a01b031661063b565b61465e42611f26565b90803b1561030b5761468d946000809460405197889586948593635c11d79560e01b8552309160048601612bc7565b03925af191821561061e5785926146cf575b5060405190815230600482015291829060249082905afa90811561061e576107e7936000926106f557505061204a565b806106126146dc9261176a565b3861469f565b6146fa919550863d881161071b5761070c81836117d3565b933861463f565b6040519061470e8261179d565b600182528160005b602090818110156147385760209161472c613382565b90828501015201614716565b505050565b926148026147c3956147f26080946147e69760009760405161475e81611782565b606098818a8093528260208201528260408201528b838201520152614781614701565b9661478d613ef16117f4565b602082015261479b87612b96565b526147a586612b96565b50604080516001600160a01b03909216602083015290998a91820190565b03906147d7601f19928381018c528b6117d3565b60405198899160208301613d77565b039081018852876117d3565b6147fa61184d565b908152614902565b9361480b611840565b95865260208601526040850152830152608082015290565b926148db6148ac966147f260809461372e976148cf999760405161484681611782565b606098818a809352826020820152826040820152600083820152015261486a614701565b96614876613ef16117f4565b602082015261488487612b96565b5261488e86612b96565b50604080516001600160a01b039092166020830152909a8b91820190565b03906148c0601f19928381018d528c6117d3565b604051998a9160208301613d77565b039081018952886117d3565b946148e4611840565b968752602087015260408601526001600160a01b0390911690840152565b604051906397a657c960e01b6020830152516024820152602481526107e7816117b8565b1561492d57565b606460405162461bcd60e51b815260206004820152602060248201527f4d757374206265206578656375746564206279207468652072656365697665726044820152fd5b6040519061497e82611782565b60006080838281528260208201528260408201528260608201520152565b906040516149a981611782565b82546001600160a01b039081168252600184015416602082015260028301546040820152600383015460ff1615156060820152600490920154608083015256feb6a94e758a1d7c9bf7c5bb12f10aa442af232ce353d686ae30a2c0935dfe34a0f652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3fa2646970667358221220cc48d35e498458d0503857f92b2844496e7661e5cd39c7a5cb6217382574b8fd64736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000080226fc0ee2b096224eeac085bb9a8cba1146f7d000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000e1ff5a4c489b11e094bfbb5d23c6d4597a3a79ad000000000000000000000000a24e8ce77d4a7ce869da3730e6560bfb66553f940000000000000000000000006a000f20005980200259b80c51020030400010680000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45000000000000000000000000a24e8ce77d4a7ce869da3730e6560bfb66553f94
-----Decoded View---------------
Arg [0] : _router (address): 0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D
Arg [1] : _link (address): 0x514910771AF9Ca656af840dff83E8264EcF986CA
Arg [2] : _usdc (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [3] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [4] : _swapFee (uint256): 300
Arg [5] : _feeReceiver (address): 0xe1Ff5a4C489B11E094BFBB5d23c6d4597a3a79AD
Arg [6] : _owner (address): 0xa24e8cE77D4A7Ce869DA3730e6560BfB66553F94
Arg [7] : _paraRouter (address): 0x6A000F20005980200259B80c5102003040001068
Arg [8] : _v2Router (address): 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
Arg [9] : _v3Router (address): 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45
Arg [10] : _executor (address): 0xa24e8cE77D4A7Ce869DA3730e6560BfB66553F94
-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 00000000000000000000000080226fc0ee2b096224eeac085bb9a8cba1146f7d
Arg [1] : 000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca
Arg [2] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [3] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [4] : 000000000000000000000000000000000000000000000000000000000000012c
Arg [5] : 000000000000000000000000e1ff5a4c489b11e094bfbb5d23c6d4597a3a79ad
Arg [6] : 000000000000000000000000a24e8ce77d4a7ce869da3730e6560bfb66553f94
Arg [7] : 0000000000000000000000006a000f20005980200259b80c5102003040001068
Arg [8] : 0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d
Arg [9] : 00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45
Arg [10] : 000000000000000000000000a24e8ce77d4a7ce869da3730e6560bfb66553f94
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.