Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
UniswapBridge
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
Yes with 100000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec pragma solidity >=0.8.4; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {AztecTypes} from "../../aztec/libraries/AztecTypes.sol"; import {IRollupProcessor} from "../../aztec/interfaces/IRollupProcessor.sol"; import {ErrorLib} from "../base/ErrorLib.sol"; import {BridgeBase} from "../base/BridgeBase.sol"; import {ISwapRouter} from "../../interfaces/uniswapv3/ISwapRouter.sol"; import {IWETH} from "../../interfaces/IWETH.sol"; import {IQuoter} from "../../interfaces/uniswapv3/IQuoter.sol"; /** * @title Aztec Connect Bridge for swapping on Uniswap v3 * @author Jan Benes (@benesjan on Github and Telegram) * @notice You can use this contract to swap tokens on Uniswap v3 along complex paths. * @dev Encoding of a path allows for up to 2 split paths (see the definition bellow) and up to 3 pools (2 middle * tokens) in each split path. A path is encoded in _auxData parameter passed to the convert method. _auxData * carry 64 bits of information. Along with split paths there is a minimum price encoded in auxData. * * Each split path takes 19 bits. Minimum price is encoded in 26 bits. Values are placed in the data as follows: * |26 bits minimum price| |19 bits split path 2| |19 bits split path 1| * * Encoding of a split path is: * |7 bits percentage| |2 bits fee| |3 bits middle token| |2 bits fee| |3 bits middle token| |2 bits fee| * The meaning of percentage is how much of input amount will be routed through the corresponding split path. * Fee bits are mapped to specific fee tiers as follows: * 00 is 0.01%, 01 is 0.05%, 10 is 0.3%, 11 is 1% * Middle tokens use the following mapping: * 001 is ETH, 010 is USDC, 011 is USDT, 100 is DAI, 101 is WBTC, 110 is FRAX, 111 is BUSD. * 000 means the middle token is unused. * * Min price is encoded as a floating point number. First 21 bits are used for significand, last 5 bits for * exponent: |21 bits significand| |5 bits exponent| * To convert minimum price to this format call encodeMinPrice(...) function on this contract. * Minimum amount out is computed with the following formula: * (inputValue * (significand * 10**exponent)) / (10 ** inputAssetDecimals) * Here are 2 examples. * 1) If I want to receive 10k Dai for 1 ETH I would set significand to 1 and exponent to 22. * _totalInputValue = 1e18, asset = ETH (18 decimals), outputAssetA: Dai (18 decimals) * (1e18 * (1 * 10**22)) / (10**18) = 1e22 --> 10k Dai * 2) If I want to receive 2000 USDC for 1 ETH, I set significand to 2 and exponent to 9. * _totalInputValue = 1e18, asset = ETH (18 decimals), outputAssetA: USDC (6 decimals) * (1e18 * (2 * 10**9)) / (10**18) = 2e9 --> 2000 USDC * * Definition of split path: Split path is a term we use when there are multiple (in this case 2) paths between * which the input amount of tokens is split. As an example we can consider swapping 100 ETH to DAI. In this case * there could be 2 split paths. 1st split path going through ETH-USDC 500 bps fee pool and USDC-DAI 100 bps fee * pool and 2nd split path going directly to DAI using the ETH-DAI 500 bps pool. First split path could for * example consume 80% of input (80 ETH) and the second split path the remaining 20% (20 ETH). */ contract UniswapBridge is BridgeBase { using SafeERC20 for IERC20; error InvalidFeeTierEncoding(); error InvalidFeeTier(); error InvalidTokenEncoding(); error InvalidToken(); error InvalidPercentageAmounts(); error InsufficientAmountOut(); error Overflow(); // @notice A struct representing a path with 2 split paths. struct Path { uint256 percentage1; // Percentage of input to swap through splitPath1 bytes splitPath1; // A path encoded in a format used by Uniswap's v3 router uint256 percentage2; // Percentage of input to swap through splitPath2 bytes splitPath2; // A path encoded in a format used by Uniswap's v3 router uint256 minPrice; // Minimum acceptable price } struct SplitPath { uint256 percentage; // Percentage of swap amount to send through this split path uint256 fee1; // 1st pool fee address token1; // Address of the 1st pool's output token uint256 fee2; // 2nd pool fee address token2; // Address of the 2nd pool's output token uint256 fee3; // 3rd pool fee } // @dev Event which is emitted when the output token doesn't implement decimals(). event DefaultDecimalsWarning(); ISwapRouter public constant ROUTER = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564); IQuoter public constant QUOTER = IQuoter(0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6); // Addresses of middle tokens address public constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; address public constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; address public constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; address public constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; address public constant WBTC = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599; address public constant FRAX = 0x853d955aCEf822Db058eb8505911ED77F175b99e; address public constant BUSD = 0x4Fabb145d64652a948d72533023f6E7A623C7C53; uint64 public constant SPLIT_PATH_BIT_LENGTH = 19; uint64 public constant SPLIT_PATHS_BIT_LENGTH = 38; // SPLIT_PATH_BIT_LENGTH * 2 uint64 public constant PRICE_BIT_LENGTH = 26; // 64 - SPLIT_PATHS_BIT_LENGTH // @dev The following masks are used to decode 2 split paths and minimum acceptable price from 1 uint64. // Binary number 0000000000000000000000000000000000000000000001111111111111111111 (last 19 bits) uint64 public constant SPLIT_PATH_MASK = 0x7FFFF; // Binary number 0000000000000000000000000000000000000011111111111111111111111111 (last 26 bits) uint64 public constant PRICE_MASK = 0x3FFFFFF; // Binary number 0000000000000000000000000000000000000000000000000000000000011111 (last 5 bits) uint64 public constant EXPONENT_MASK = 0x1F; // Binary number 11 uint64 public constant FEE_MASK = 0x3; // Binary number 111 uint64 public constant TOKEN_MASK = 0x7; /** * @notice Set the address of rollup processor. * @param _rollupProcessor Address of rollup processor */ constructor(address _rollupProcessor) BridgeBase(_rollupProcessor) {} // @dev Empty method which is present here in order to be able to receive ETH when unwrapping WETH. receive() external payable {} /** * @notice Sets all the important approvals. * @param _tokensIn - An array of address of input tokens (tokens to later swap in the convert(...) function) * @param _tokensOut - An array of address of output tokens (tokens to later return to rollup processor) * @dev SwapBridge never holds any ERC20 tokens after or before an invocation of any of its functions. For this * reason the following is not a security risk and makes convert(...) function more gas efficient. */ function preApproveTokens(address[] calldata _tokensIn, address[] calldata _tokensOut) external { uint256 tokensLength = _tokensIn.length; for (uint256 i; i < tokensLength; ) { address tokenIn = _tokensIn[i]; // Using safeApprove(...) instead of approve(...) and first setting the allowance to 0 because underlying // can be Tether IERC20(tokenIn).safeApprove(address(ROUTER), 0); IERC20(tokenIn).safeApprove(address(ROUTER), type(uint256).max); unchecked { ++i; } } tokensLength = _tokensOut.length; for (uint256 i; i < tokensLength; ) { address tokenOut = _tokensOut[i]; // Using safeApprove(...) instead of approve(...) and first setting the allowance to 0 because underlying // can be Tether IERC20(tokenOut).safeApprove(address(ROLLUP_PROCESSOR), 0); IERC20(tokenOut).safeApprove(address(ROLLUP_PROCESSOR), type(uint256).max); unchecked { ++i; } } } /** * @notice A function which swaps input token for output token along the path encoded in _auxData. * @param _inputAssetA - Input ERC20 token * @param _outputAssetA - Output ERC20 token * @param _totalInputValue - Amount of input token to swap * @param _interactionNonce - Interaction nonce * @param _auxData - Encoded path (gets decoded to Path struct) * @return outputValueA - The amount of output token received */ function convert( AztecTypes.AztecAsset calldata _inputAssetA, AztecTypes.AztecAsset calldata, AztecTypes.AztecAsset calldata _outputAssetA, AztecTypes.AztecAsset calldata, uint256 _totalInputValue, uint256 _interactionNonce, uint64 _auxData, address ) external payable override(BridgeBase) onlyRollup returns ( uint256 outputValueA, uint256, bool ) { bool inputIsEth = _inputAssetA.assetType == AztecTypes.AztecAssetType.ETH; bool outputIsEth = _outputAssetA.assetType == AztecTypes.AztecAssetType.ETH; if (_inputAssetA.assetType != AztecTypes.AztecAssetType.ERC20 && !inputIsEth) { revert ErrorLib.InvalidInputA(); } if (_outputAssetA.assetType != AztecTypes.AztecAssetType.ERC20 && !outputIsEth) { revert ErrorLib.InvalidOutputA(); } Path memory path = _decodePath( inputIsEth ? WETH : _inputAssetA.erc20Address, _auxData, outputIsEth ? WETH : _outputAssetA.erc20Address ); uint256 inputValueSplitPath1 = (_totalInputValue * path.percentage1) / 100; if (path.percentage1 != 0) { // Swap using the first swap path outputValueA = ROUTER.exactInput{value: inputIsEth ? inputValueSplitPath1 : 0}( ISwapRouter.ExactInputParams({ path: path.splitPath1, recipient: address(this), deadline: block.timestamp, amountIn: inputValueSplitPath1, amountOutMinimum: 0 }) ); } if (path.percentage2 != 0) { // Swap using the second swap path uint256 inputValueSplitPath2 = _totalInputValue - inputValueSplitPath1; outputValueA += ROUTER.exactInput{value: inputIsEth ? inputValueSplitPath2 : 0}( ISwapRouter.ExactInputParams({ path: path.splitPath2, recipient: address(this), deadline: block.timestamp, amountIn: inputValueSplitPath2, amountOutMinimum: 0 }) ); } uint256 tokenInDecimals = 18; if (!inputIsEth) { try IERC20Metadata(_inputAssetA.erc20Address).decimals() returns (uint8 decimals) { tokenInDecimals = decimals; } catch (bytes memory) { emit DefaultDecimalsWarning(); } } uint256 amountOutMinimum = (_totalInputValue * path.minPrice) / 10**tokenInDecimals; if (outputValueA < amountOutMinimum) revert InsufficientAmountOut(); if (outputIsEth) { IWETH(WETH).withdraw(outputValueA); IRollupProcessor(ROLLUP_PROCESSOR).receiveEthFromBridge{value: outputValueA}(_interactionNonce); } } /** * @notice A function which encodes path to a format expected in _auxData of this.convert(...) * @param _amountIn - Amount of tokenIn to swap * @param _minAmountOut - Amount of tokenOut to receive * @param _tokenIn - Address of _tokenIn (@dev used only to fetch decimals) * @param _splitPath1 - Split path to encode * @param _splitPath2 - Split path to encode * @return Path encoded in a format expected in _auxData of this.convert(...) * @dev This function is not optimized and is expected to be used on frontend and in tests. * @dev Reverts when min price is bigger than max encodeable value. */ function encodePath( uint256 _amountIn, uint256 _minAmountOut, address _tokenIn, SplitPath calldata _splitPath1, SplitPath calldata _splitPath2 ) external view returns (uint64) { if (_splitPath1.percentage + _splitPath2.percentage != 100) revert InvalidPercentageAmounts(); return uint64( (_computeEncodedMinPrice(_amountIn, _minAmountOut, IERC20Metadata(_tokenIn).decimals()) << SPLIT_PATHS_BIT_LENGTH) + (_encodeSplitPath(_splitPath1) << SPLIT_PATH_BIT_LENGTH) + _encodeSplitPath(_splitPath2) ); } /** * @notice A function which encodes path to a format expected in _auxData of this.convert(...) * @param _amountIn - Amount of tokenIn to swap * @param _tokenIn - Address of _tokenIn (@dev used only to fetch decimals) * @param _path - Split path to encode * @param _tokenOut - Address of _tokenIn (@dev used only to fetch decimals) * @return amountOut - */ function quote( uint256 _amountIn, address _tokenIn, uint64 _path, address _tokenOut ) external returns (uint256 amountOut) { Path memory path = _decodePath(_tokenIn, _path, _tokenOut); uint256 inputValueSplitPath1 = (_amountIn * path.percentage1) / 100; if (path.percentage1 != 0) { // Swap using the first swap path amountOut += QUOTER.quoteExactInput(path.splitPath1, inputValueSplitPath1); } if (path.percentage2 != 0) { // Swap using the second swap path amountOut += QUOTER.quoteExactInput(path.splitPath2, _amountIn - inputValueSplitPath1); } } /** * @notice A function which computes min price and encodes it in the format used in this bridge. * @param _amountIn - Amount of tokenIn to swap * @param _minAmountOut - Amount of tokenOut to receive * @param _tokenInDecimals - Number of decimals of tokenIn * @return encodedMinPrice - Min acceptable encoded in a format used in this bridge. * @dev This function is not optimized and is expected to be used on frontend and in tests. * @dev Reverts when min price is bigger than max encodeable value. */ function _computeEncodedMinPrice( uint256 _amountIn, uint256 _minAmountOut, uint256 _tokenInDecimals ) internal pure returns (uint256 encodedMinPrice) { uint256 minPrice = (_minAmountOut * 10**_tokenInDecimals) / _amountIn; // 2097151 = 2**21 - 1 --> this number and its multiples of 10 can be encoded without precision loss if (minPrice <= 2097151) { // minPrice is smaller than the boundary of significand --> significand = _x, exponent = 0 encodedMinPrice = minPrice << 5; } else { uint256 exponent = 0; while (minPrice > 2097151) { minPrice /= 10; ++exponent; // 31 = 2**5 - 1 --> max exponent if (exponent > 31) revert Overflow(); } encodedMinPrice = (minPrice << 5) + exponent; } } /** * @notice A function which encodes a split path. * @param _path - Split path to encode * @return Encoded split path (in the last 19 bits of uint) * @dev In place of unused middle tokens and address(0). When fee tier is unused place there any valid value. This * value gets ignored. */ function _encodeSplitPath(SplitPath calldata _path) internal pure returns (uint256) { if (_path.percentage == 0) return 0; return (_path.percentage << 12) + (_encodeFeeTier(_path.fee1) << 10) + (_encodeMiddleToken(_path.token1) << 7) + (_encodeFeeTier(_path.fee2) << 5) + (_encodeMiddleToken(_path.token2) << 2) + (_encodeFeeTier(_path.fee3)); } /** * @notice A function which encodes fee tier. * @param _feeTier - Fee tier in bps * @return Encoded fee tier (in the last 2 bits of uint) */ function _encodeFeeTier(uint256 _feeTier) internal pure returns (uint256) { if (_feeTier == 100) { // Binary number 00 return 0; } if (_feeTier == 500) { // Binary number 01 return 1; } if (_feeTier == 3000) { // Binary number 10 return 2; } if (_feeTier == 10000) { // Binary number 11 return 3; } revert InvalidFeeTier(); } /** * @notice A function which returns token encoding for a given token address. * @param _token - Token address * @return encodedToken - Encoded token (in the last 3 bits of uint256) */ function _encodeMiddleToken(address _token) internal pure returns (uint256 encodedToken) { if (_token == address(0)) { // unused token return 0; } if (_token == WETH) { // binary number 001 return 1; } if (_token == USDC) { // binary number 010 return 2; } if (_token == USDT) { // binary number 011 return 3; } if (_token == DAI) { // binary number 100 return 4; } if (_token == WBTC) { // binary number 101 return 5; } if (_token == FRAX) { // binary number 110 return 6; } if (_token == BUSD) { // binary number 111 return 7; } revert InvalidToken(); } /** * @notice A function which deserializes encoded path to Path struct. * @param _tokenIn - Input ERC20 token * @param _encodedPath - Encoded path * @param _tokenOut - Output ERC20 token * @return path - Decoded/deserialized path struct */ function _decodePath( address _tokenIn, uint256 _encodedPath, address _tokenOut ) internal pure returns (Path memory path) { (uint256 percentage1, bytes memory splitPath1) = _decodeSplitPath( _tokenIn, _encodedPath & SPLIT_PATH_MASK, _tokenOut ); path.percentage1 = percentage1; path.splitPath1 = splitPath1; (uint256 percentage2, bytes memory splitPath2) = _decodeSplitPath( _tokenIn, (_encodedPath >> SPLIT_PATH_BIT_LENGTH) & SPLIT_PATH_MASK, _tokenOut ); if (percentage1 + percentage2 != 100) revert InvalidPercentageAmounts(); path.percentage2 = percentage2; path.splitPath2 = splitPath2; path.minPrice = _decodeMinPrice(_encodedPath >> SPLIT_PATHS_BIT_LENGTH); } /** * @notice A function which returns a percentage of input going through the split path and the split path encoded * in a format compatible with Uniswap router. * @param _tokenIn - Input ERC20 token * @param _encodedSplitPath - Encoded split path (in the last 19 bits of uint256) * @param _tokenOut - Output ERC20 token * @return percentage - A percentage of input going through the corresponding split path * @return splitPath - A split path encoded in a format compatible with Uniswap router */ function _decodeSplitPath( address _tokenIn, uint256 _encodedSplitPath, address _tokenOut ) internal pure returns (uint256 percentage, bytes memory splitPath) { uint256 fee3 = _encodedSplitPath & FEE_MASK; uint256 middleToken2 = (_encodedSplitPath >> 2) & TOKEN_MASK; uint256 fee2 = (_encodedSplitPath >> 5) & FEE_MASK; uint256 middleToken1 = (_encodedSplitPath >> 7) & TOKEN_MASK; uint256 fee1 = (_encodedSplitPath >> 10) & FEE_MASK; percentage = _encodedSplitPath >> 12; if (middleToken1 != 0 && middleToken2 != 0) { splitPath = abi.encodePacked( _tokenIn, _decodeFeeTier(fee1), _decodeMiddleToken(middleToken1), _decodeFeeTier(fee2), _decodeMiddleToken(middleToken2), _decodeFeeTier(fee3), _tokenOut ); } else if (middleToken1 != 0) { splitPath = abi.encodePacked( _tokenIn, _decodeFeeTier(fee1), _decodeMiddleToken(middleToken1), _decodeFeeTier(fee3), _tokenOut ); } else if (middleToken2 != 0) { splitPath = abi.encodePacked( _tokenIn, _decodeFeeTier(fee2), _decodeMiddleToken(middleToken2), _decodeFeeTier(fee3), _tokenOut ); } else { splitPath = abi.encodePacked(_tokenIn, _decodeFeeTier(fee3), _tokenOut); } } /** * @notice A function which converts minimum price in a floating point format to integer. * @param _encodedMinPrice - Encoded minimum price (in the last 26 bits of uint256) * @return minPrice - Minimum acceptable price represented as an integer */ function _decodeMinPrice(uint256 _encodedMinPrice) internal pure returns (uint256 minPrice) { // 21 bits significand, 5 bits exponent uint256 significand = _encodedMinPrice >> 5; uint256 exponent = _encodedMinPrice & EXPONENT_MASK; minPrice = significand * 10**exponent; } /** * @notice A function which converts encoded fee tier to a fee tier in an integer format. * @param _encodedFeeTier - Encoded fee tier (in the last 2 bits of uint256) * @return feeTier - Decoded fee tier in an integer format */ function _decodeFeeTier(uint256 _encodedFeeTier) internal pure returns (uint24 feeTier) { if (_encodedFeeTier == 0) { // Binary number 00 return uint24(100); } if (_encodedFeeTier == 1) { // Binary number 01 return uint24(500); } if (_encodedFeeTier == 2) { // Binary number 10 return uint24(3000); } if (_encodedFeeTier == 3) { // Binary number 11 return uint24(10000); } revert InvalidFeeTierEncoding(); } /** * @notice A function which returns token address for an encoded token. * @param _encodedToken - Encoded token (in the last 3 bits of uint256) * @return token - Token address */ function _decodeMiddleToken(uint256 _encodedToken) internal pure returns (address token) { if (_encodedToken == 1) { // binary number 001 return WETH; } if (_encodedToken == 2) { // binary number 010 return USDC; } if (_encodedToken == 3) { // binary number 011 return USDT; } if (_encodedToken == 4) { // binary number 100 return DAI; } if (_encodedToken == 5) { // binary number 101 return WBTC; } if (_encodedToken == 6) { // binary number 110 return FRAX; } if (_encodedToken == 7) { // binary number 111 return BUSD; } revert InvalidTokenEncoding(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec pragma solidity >=0.8.4; import {AztecTypes} from "../libraries/AztecTypes.sol"; interface IDefiBridge { /** * @notice A function which converts input assets to output assets. * @param _inputAssetA A struct detailing the first input asset * @param _inputAssetB A struct detailing the second input asset * @param _outputAssetA A struct detailing the first output asset * @param _outputAssetB A struct detailing the second output asset * @param _totalInputValue An amount of input assets transferred to the bridge (Note: "total" is in the name * because the value can represent summed/aggregated token amounts of users actions on L2) * @param _interactionNonce A globally unique identifier of this interaction/`convert(...)` call. * @param _auxData Bridge specific data to be passed into the bridge contract (e.g. slippage, nftID etc.) * @return outputValueA An amount of `_outputAssetA` returned from this interaction. * @return outputValueB An amount of `_outputAssetB` returned from this interaction. * @return isAsync A flag indicating if the interaction is async. * @dev This function is called from the RollupProcessor contract via the DefiBridgeProxy. Before this function is * called _RollupProcessor_ contract will have sent you all the assets defined by the input params. This * function is expected to convert input assets to output assets (e.g. on Uniswap) and return the amounts * of output assets to be received by the _RollupProcessor_. If output assets are ERC20 tokens the bridge has * to _RollupProcessor_ as a spender before the interaction is finished. If some of the output assets is ETH * it has to be sent to _RollupProcessor_ via the `receiveEthFromBridge(uint256 _interactionNonce)` method * inside before the `convert(...)` function call finishes. * @dev If there are two input assets, equal amounts of both assets will be transferred to the bridge before this * method is called. * @dev **BOTH** output assets could be virtual but since their `assetId` is currently assigned as * `_interactionNonce` it would simply mean that more of the same virtual asset is minted. * @dev If this interaction is async the function has to return `(0,0 true)`. Async interaction will be finalised at * a later time and its output assets will be returned in a `IDefiBridge.finalise(...)` call. **/ function convert( AztecTypes.AztecAsset calldata _inputAssetA, AztecTypes.AztecAsset calldata _inputAssetB, AztecTypes.AztecAsset calldata _outputAssetA, AztecTypes.AztecAsset calldata _outputAssetB, uint256 _totalInputValue, uint256 _interactionNonce, uint64 _auxData, address _rollupBeneficiary ) external payable returns ( uint256 outputValueA, uint256 outputValueB, bool isAsync ); /** * @notice A function that finalises asynchronous interaction. * @param _inputAssetA A struct detailing the first input asset * @param _inputAssetB A struct detailing the second input asset * @param _outputAssetA A struct detailing the first output asset * @param _outputAssetB A struct detailing the second output asset * @param _interactionNonce A globally unique identifier of this interaction/`convert(...)` call. * @param _auxData Bridge specific data to be passed into the bridge contract (e.g. slippage, nftID etc.) * @return outputValueA An amount of `_outputAssetA` returned from this interaction. * @return outputValueB An amount of `_outputAssetB` returned from this interaction. * @dev This function should use the `BridgeBase.onlyRollup()` modifier to ensure it can only be called from * the `RollupProcessor.processAsyncDefiInteraction(uint256 _interactionNonce)` method. **/ function finalise( AztecTypes.AztecAsset calldata _inputAssetA, AztecTypes.AztecAsset calldata _inputAssetB, AztecTypes.AztecAsset calldata _outputAssetA, AztecTypes.AztecAsset calldata _outputAssetB, uint256 _interactionNonce, uint64 _auxData ) external payable returns ( uint256 outputValueA, uint256 outputValueB, bool interactionComplete ); }
// SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec pragma solidity >=0.8.4; // @dev For documentation of the functions within this interface see RollupProcessor contract interface IRollupProcessor { /*---------------------------------------- EVENTS ----------------------------------------*/ event OffchainData(uint256 indexed rollupId, uint256 chunk, uint256 totalChunks, address sender); event RollupProcessed(uint256 indexed rollupId, bytes32[] nextExpectedDefiHashes, address sender); event DefiBridgeProcessed( uint256 indexed encodedBridgeCallData, uint256 indexed nonce, uint256 totalInputValue, uint256 totalOutputValueA, uint256 totalOutputValueB, bool result, bytes errorReason ); event AsyncDefiBridgeProcessed( uint256 indexed encodedBridgeCallData, uint256 indexed nonce, uint256 totalInputValue ); event Deposit(uint256 indexed assetId, address indexed depositorAddress, uint256 depositValue); event WithdrawError(bytes errorReason); event AssetAdded(uint256 indexed assetId, address indexed assetAddress, uint256 assetGasLimit); event BridgeAdded(uint256 indexed bridgeAddressId, address indexed bridgeAddress, uint256 bridgeGasLimit); event RollupProviderUpdated(address indexed providerAddress, bool valid); event VerifierUpdated(address indexed verifierAddress); event Paused(address account); event Unpaused(address account); /*---------------------------------------- MUTATING FUNCTIONS ----------------------------------------*/ function pause() external; function unpause() external; function setRollupProvider(address _provider, bool _valid) external; function setVerifier(address _verifier) external; function setAllowThirdPartyContracts(bool _allowThirdPartyContracts) external; function setDefiBridgeProxy(address _defiBridgeProxy) external; function setSupportedAsset(address _token, uint256 _gasLimit) external; function setSupportedBridge(address _bridge, uint256 _gasLimit) external; function processRollup(bytes calldata _encodedProofData, bytes calldata _signatures) external; function receiveEthFromBridge(uint256 _interactionNonce) external payable; function approveProof(bytes32 _proofHash) external; function depositPendingFunds( uint256 _assetId, uint256 _amount, address _owner, bytes32 _proofHash ) external payable; function offchainData( uint256 _rollupId, uint256 _chunk, uint256 _totalChunks, bytes calldata _offchainTxData ) external; function processAsyncDefiInteraction(uint256 _interactionNonce) external returns (bool); /*---------------------------------------- NON-MUTATING FUNCTIONS ----------------------------------------*/ function rollupStateHash() external view returns (bytes32); function userPendingDeposits(uint256 _assetId, address _user) external view returns (uint256); function defiBridgeProxy() external view returns (address); function prevDefiInteractionsHash() external view returns (bytes32); function paused() external view returns (bool); function verifier() external view returns (address); function getDataSize() external view returns (uint256); function getPendingDefiInteractionHashesLength() external view returns (uint256); function getDefiInteractionHashesLength() external view returns (uint256); function getAsyncDefiInteractionHashesLength() external view returns (uint256); function getSupportedBridge(uint256 _bridgeAddressId) external view returns (address); function getSupportedBridgesLength() external view returns (uint256); function getSupportedAssetsLength() external view returns (uint256); function getSupportedAsset(uint256 _assetId) external view returns (address); function getEscapeHatchStatus() external view returns (bool, uint256); function assetGasLimits(uint256 _bridgeAddressId) external view returns (uint256); function bridgeGasLimits(uint256 _bridgeAddressId) external view returns (uint256); function allowThirdPartyContracts() external view returns (bool); }
// SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec pragma solidity >=0.8.4; // @dev documentation of this interface is in its implementation (Subsidy contract) interface ISubsidy { /** * @notice Container for Subsidy related information * @member available Amount of ETH remaining to be paid out * @member gasUsage Amount of gas the interaction consumes (used to define max possible payout) * @member minGasPerMinute Minimum amount of gas per minute the subsidizer has to subsidize * @member gasPerMinute Amount of gas per minute the subsidizer is willing to subsidize * @member lastUpdated Last time subsidy was paid out or funded (if not subsidy was yet claimed after funding) */ struct Subsidy { uint128 available; uint32 gasUsage; uint32 minGasPerMinute; uint32 gasPerMinute; uint32 lastUpdated; } function setGasUsageAndMinGasPerMinute( uint256 _criteria, uint32 _gasUsage, uint32 _minGasPerMinute ) external; function setGasUsageAndMinGasPerMinute( uint256[] calldata _criteria, uint32[] calldata _gasUsage, uint32[] calldata _minGasPerMinute ) external; function registerBeneficiary(address _beneficiary) external; function subsidize( address _bridge, uint256 _criteria, uint32 _gasPerMinute ) external payable; function topUp(address _bridge, uint256 _criteria) external payable; function claimSubsidy(uint256 _criteria, address _beneficiary) external returns (uint256); function withdraw(address _beneficiary) external returns (uint256); // solhint-disable-next-line function MIN_SUBSIDY_VALUE() external view returns (uint256); function claimableAmount(address _beneficiary) external view returns (uint256); function isRegistered(address _beneficiary) external view returns (bool); function getSubsidy(address _bridge, uint256 _criteria) external view returns (Subsidy memory); function getAccumulatedSubsidyAmount(address _bridge, uint256 _criteria) external view returns (uint256); }
// SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec pragma solidity >=0.8.4; library AztecTypes { enum AztecAssetType { NOT_USED, ETH, ERC20, VIRTUAL } struct AztecAsset { uint256 id; address erc20Address; AztecAssetType assetType; } }
// SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec. pragma solidity >=0.8.4; import {IDefiBridge} from "../../aztec/interfaces/IDefiBridge.sol"; import {ISubsidy} from "../../aztec/interfaces/ISubsidy.sol"; import {AztecTypes} from "../../aztec/libraries/AztecTypes.sol"; import {ErrorLib} from "./ErrorLib.sol"; /** * @title BridgeBase * @notice A base that bridges can be built upon which imports a limited set of features * @dev Reverts `convert` with missing implementation, and `finalise` with async disabled * @author Lasse Herskind */ abstract contract BridgeBase is IDefiBridge { error MissingImplementation(); ISubsidy public constant SUBSIDY = ISubsidy(0xABc30E831B5Cc173A9Ed5941714A7845c909e7fA); address public immutable ROLLUP_PROCESSOR; constructor(address _rollupProcessor) { ROLLUP_PROCESSOR = _rollupProcessor; } modifier onlyRollup() { if (msg.sender != ROLLUP_PROCESSOR) { revert ErrorLib.InvalidCaller(); } _; } function convert( AztecTypes.AztecAsset calldata, AztecTypes.AztecAsset calldata, AztecTypes.AztecAsset calldata, AztecTypes.AztecAsset calldata, uint256, uint256, uint64, address ) external payable virtual override(IDefiBridge) returns ( uint256, uint256, bool ) { revert MissingImplementation(); } function finalise( AztecTypes.AztecAsset calldata, AztecTypes.AztecAsset calldata, AztecTypes.AztecAsset calldata, AztecTypes.AztecAsset calldata, uint256, uint64 ) external payable virtual override(IDefiBridge) returns ( uint256, uint256, bool ) { revert ErrorLib.AsyncDisabled(); } /** * @notice Computes the criteria that is passed on to the subsidy contract when claiming * @dev Should be overridden by bridge implementation if intended to limit subsidy. * @return The criteria to be passed along */ function computeCriteria( AztecTypes.AztecAsset calldata, AztecTypes.AztecAsset calldata, AztecTypes.AztecAsset calldata, AztecTypes.AztecAsset calldata, uint64 ) public view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec. pragma solidity >=0.8.4; library ErrorLib { error InvalidCaller(); error InvalidInput(); error InvalidInputA(); error InvalidInputB(); error InvalidOutputA(); error InvalidOutputB(); error InvalidInputAmount(); error InvalidAuxData(); error ApproveFailed(address token); error TransferFailed(address token); error InvalidNonce(); error AsyncDisabled(); }
// SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec. pragma solidity >=0.8.4; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IWETH is IERC20 { function deposit() external payable; function withdraw(uint256 amount) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.7.5; pragma abicoder v2; /// @title Quoter Interface /// @notice Supports quoting the calculated amounts from exact input or exact output swaps /// @dev These functions are not marked view because they rely on calling non-view functions and reverting /// to compute the result. They are also not gas efficient and should not be called on-chain. interface IQuoter { /// @notice Returns the amount out received for a given exact input swap without executing the swap /// @param path The path of the swap, i.e. each token pair and the pool fee /// @param amountIn The amount of the first token to swap /// @return amountOut The amount of the last token that would be received function quoteExactInput(bytes memory path, uint256 amountIn) external returns (uint256 amountOut); /// @notice Returns the amount out received for a given exact input but for a swap of a single pool /// @param tokenIn The token being swapped in /// @param tokenOut The token being swapped out /// @param fee The fee of the token pool to consider for the pair /// @param amountIn The desired input amount /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap /// @return amountOut The amount of `tokenOut` that would be received function quoteExactInputSingle( address tokenIn, address tokenOut, uint24 fee, uint256 amountIn, uint160 sqrtPriceLimitX96 ) external returns (uint256 amountOut); /// @notice Returns the amount in required for a given exact output swap without executing the swap /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order /// @param amountOut The amount of the last token to receive /// @return amountIn The amount of first token required to be paid function quoteExactOutput(bytes memory path, uint256 amountOut) external returns (uint256 amountIn); /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool /// @param tokenIn The token being swapped in /// @param tokenOut The token being swapped out /// @param fee The fee of the token pool to consider for the pair /// @param amountOut The desired output amount /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap /// @return amountIn The amount required as the input for the swap in order to receive `amountOut` function quoteExactOutputSingle( address tokenIn, address tokenOut, uint24 fee, uint256 amountOut, uint160 sqrtPriceLimitX96 ) external returns (uint256 amountIn); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.4; /// @title Router token swapping functionality /// @notice Functions for swapping tokens via Uniswap V3 interface ISwapRouter { struct ExactInputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; } /// @notice Swaps `amountIn` of one token for as much as possible of another token /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata /// @return amountOut The amount of the received token function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); struct ExactInputParams { bytes path; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; } /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata /// @return amountOut The amount of the received token function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); struct ExactOutputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; uint160 sqrtPriceLimitX96; } /// @notice Swaps as little as possible of one token for `amountOut` of another token /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata /// @return amountIn The amount of the input token function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn); struct ExactOutputParams { bytes path; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; } /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed) /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata /// @return amountIn The amount of the input token function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn); }
{ "remappings": [ "@openzeppelin/=node_modules/@openzeppelin/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "rollup-encoder/=lib/rollup-encoder/src/" ], "optimizer": { "enabled": true, "runs": 100000 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_rollupProcessor","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AsyncDisabled","type":"error"},{"inputs":[],"name":"InsufficientAmountOut","type":"error"},{"inputs":[],"name":"InvalidCaller","type":"error"},{"inputs":[],"name":"InvalidFeeTier","type":"error"},{"inputs":[],"name":"InvalidFeeTierEncoding","type":"error"},{"inputs":[],"name":"InvalidInputA","type":"error"},{"inputs":[],"name":"InvalidOutputA","type":"error"},{"inputs":[],"name":"InvalidPercentageAmounts","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"inputs":[],"name":"InvalidTokenEncoding","type":"error"},{"inputs":[],"name":"MissingImplementation","type":"error"},{"inputs":[],"name":"Overflow","type":"error"},{"anonymous":false,"inputs":[],"name":"DefaultDecimalsWarning","type":"event"},{"inputs":[],"name":"BUSD","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DAI","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXPONENT_MASK","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_MASK","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FRAX","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE_BIT_LENGTH","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE_MASK","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUOTER","outputs":[{"internalType":"contract IQuoter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLLUP_PROCESSOR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROUTER","outputs":[{"internalType":"contract ISwapRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SPLIT_PATHS_BIT_LENGTH","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SPLIT_PATH_BIT_LENGTH","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SPLIT_PATH_MASK","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SUBSIDY","outputs":[{"internalType":"contract ISubsidy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_MASK","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDC","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WBTC","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"erc20Address","type":"address"},{"internalType":"enum AztecTypes.AztecAssetType","name":"assetType","type":"uint8"}],"internalType":"struct AztecTypes.AztecAsset","name":"","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"erc20Address","type":"address"},{"internalType":"enum AztecTypes.AztecAssetType","name":"assetType","type":"uint8"}],"internalType":"struct AztecTypes.AztecAsset","name":"","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"erc20Address","type":"address"},{"internalType":"enum AztecTypes.AztecAssetType","name":"assetType","type":"uint8"}],"internalType":"struct AztecTypes.AztecAsset","name":"","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"erc20Address","type":"address"},{"internalType":"enum AztecTypes.AztecAssetType","name":"assetType","type":"uint8"}],"internalType":"struct AztecTypes.AztecAsset","name":"","type":"tuple"},{"internalType":"uint64","name":"","type":"uint64"}],"name":"computeCriteria","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"erc20Address","type":"address"},{"internalType":"enum AztecTypes.AztecAssetType","name":"assetType","type":"uint8"}],"internalType":"struct AztecTypes.AztecAsset","name":"_inputAssetA","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"erc20Address","type":"address"},{"internalType":"enum AztecTypes.AztecAssetType","name":"assetType","type":"uint8"}],"internalType":"struct AztecTypes.AztecAsset","name":"","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"erc20Address","type":"address"},{"internalType":"enum AztecTypes.AztecAssetType","name":"assetType","type":"uint8"}],"internalType":"struct AztecTypes.AztecAsset","name":"_outputAssetA","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"erc20Address","type":"address"},{"internalType":"enum AztecTypes.AztecAssetType","name":"assetType","type":"uint8"}],"internalType":"struct AztecTypes.AztecAsset","name":"","type":"tuple"},{"internalType":"uint256","name":"_totalInputValue","type":"uint256"},{"internalType":"uint256","name":"_interactionNonce","type":"uint256"},{"internalType":"uint64","name":"_auxData","type":"uint64"},{"internalType":"address","name":"","type":"address"}],"name":"convert","outputs":[{"internalType":"uint256","name":"outputValueA","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_minAmountOut","type":"uint256"},{"internalType":"address","name":"_tokenIn","type":"address"},{"components":[{"internalType":"uint256","name":"percentage","type":"uint256"},{"internalType":"uint256","name":"fee1","type":"uint256"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"fee2","type":"uint256"},{"internalType":"address","name":"token2","type":"address"},{"internalType":"uint256","name":"fee3","type":"uint256"}],"internalType":"struct UniswapBridge.SplitPath","name":"_splitPath1","type":"tuple"},{"components":[{"internalType":"uint256","name":"percentage","type":"uint256"},{"internalType":"uint256","name":"fee1","type":"uint256"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"fee2","type":"uint256"},{"internalType":"address","name":"token2","type":"address"},{"internalType":"uint256","name":"fee3","type":"uint256"}],"internalType":"struct UniswapBridge.SplitPath","name":"_splitPath2","type":"tuple"}],"name":"encodePath","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"erc20Address","type":"address"},{"internalType":"enum AztecTypes.AztecAssetType","name":"assetType","type":"uint8"}],"internalType":"struct AztecTypes.AztecAsset","name":"","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"erc20Address","type":"address"},{"internalType":"enum AztecTypes.AztecAssetType","name":"assetType","type":"uint8"}],"internalType":"struct AztecTypes.AztecAsset","name":"","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"erc20Address","type":"address"},{"internalType":"enum AztecTypes.AztecAssetType","name":"assetType","type":"uint8"}],"internalType":"struct AztecTypes.AztecAsset","name":"","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"erc20Address","type":"address"},{"internalType":"enum AztecTypes.AztecAssetType","name":"assetType","type":"uint8"}],"internalType":"struct AztecTypes.AztecAsset","name":"","type":"tuple"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint64","name":"","type":"uint64"}],"name":"finalise","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokensIn","type":"address[]"},{"internalType":"address[]","name":"_tokensOut","type":"address[]"}],"name":"preApproveTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"uint64","name":"_path","type":"uint64"},{"internalType":"address","name":"_tokenOut","type":"address"}],"name":"quote","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60a06040523480156200001157600080fd5b506040516200267b3803806200267b833981016040819052620000349162000046565b6001600160a01b031660805262000078565b6000602082840312156200005957600080fd5b81516001600160a01b03811681146200007157600080fd5b9392505050565b6080516125cb620000b0600039600081816104460152818161054f01528181610b5601528181610f840152610fc601526125cb6000f3fe60806040526004361061019a5760003560e01c80638cb0d0c9116100e1578063ae9467b51161008a578063dbeacd5411610064578063dbeacd54146104b8578063e0bab4c4146104de578063e5488ed214610506578063ee622c3d1461051e57600080fd5b8063ae9467b514610434578063b0e4556f14610468578063c54e44eb1461049057600080fd5b8063a437399a116100bb578063a437399a146103e2578063aa271e27146103f7578063ad5c46481461040c57600080fd5b80638cb0d0c9146103855780638dae88c2146103a75780639b07d342146103cf57600080fd5b80634dede3de116101435780637c09cfde1161011d5780637c09cfde1461030f57806381ebd5291461032f57806389a302711461035d57600080fd5b80634dede3de146102aa5780636508156e146102d2578063797556cc146102fa57600080fd5b806326c3b5151161017457806326c3b5151461020557806332fe7b2614610235578063484f4ea91461028257600080fd5b806301cbe1f5146101a657806312d6a099146101d957806322cfd024146101f057600080fd5b366101a157005b600080fd5b3480156101b257600080fd5b506101bb601f81565b60405167ffffffffffffffff90911681526020015b60405180910390f35b3480156101e557600080fd5b506101bb6207ffff81565b3480156101fc57600080fd5b506101bb601381565b610218610213366004611e58565b610533565b6040805193845260208401929092521515908201526060016101d0565b34801561024157600080fd5b5061025d73e592427a0aece92de3edee1f18e0157c0586156481565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d0565b34801561028e57600080fd5b5061025d734fabb145d64652a948d72533023f6e7a623c7c5381565b3480156102b657600080fd5b5061025d732260fac5e5542a773aa44fbcfedf7c193bc2c59981565b3480156102de57600080fd5b5061025d73abc30e831b5cc173a9ed5941714a7845c909e7fa81565b34801561030657600080fd5b506101bb602681565b34801561031b57600080fd5b506101bb61032a366004611efc565b610bcb565b34801561033b57600080fd5b5061034f61034a366004611f57565b610ccf565b6040519081526020016101d0565b34801561036957600080fd5b5061025d73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b34801561039157600080fd5b506103a56103a0366004611ff0565b610e63565b005b3480156103b357600080fd5b5061025d73b27308f9f90d607463bb33ea1bebb41c27ce5ab681565b6102186103dd36600461205c565b61101c565b3480156103ee57600080fd5b506101bb600381565b34801561040357600080fd5b506101bb601a81565b34801561041857600080fd5b5061025d73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b34801561044057600080fd5b5061025d7f000000000000000000000000000000000000000000000000000000000000000081565b34801561047457600080fd5b5061025d73853d955acef822db058eb8505911ed77f175b99e81565b34801561049c57600080fd5b5061025d73dac17f958d2ee523a2206206994597c13d831ec781565b3480156104c457600080fd5b5061034f6104d33660046120d1565b600095945050505050565b3480156104ea57600080fd5b5061025d736b175474e89094c44da98b954eedeac495271d0f81565b34801561051257600080fd5b506101bb6303ffffff81565b34801561052a57600080fd5b506101bb600781565b600080803373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146105a6576040517f48f5c3ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060016105ba60608e0160408f01612160565b60038111156105cb576105cb612131565b149050600060016105e260608d0160408e01612160565b60038111156105f3576105f3612131565b14905060028d604001602081019061060b9190612160565b600381111561061c5761061c612131565b14158015610628575081155b1561065f576040517fc582880b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600261067160608d0160408e01612160565b600381111561068257610682612131565b1415801561068e575080155b156106c5576040517f6c98dcaf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061073f836106e7578e60200160208101906106e29190612181565b6106fd565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b8967ffffffffffffffff1684610725578e60200160208101906107209190612181565b611053565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2611053565b90506000606482600001518c61075591906121cb565b61075f9190612208565b8251909150156108355773e592427a0aece92de3edee1f18e0157c0586156463c04b8d598561078f576000610791565b825b6040518060a00160405280866020015181526020013073ffffffffffffffffffffffffffffffffffffffff16815260200142815260200185815260200160008152506040518363ffffffff1660e01b81526004016107ef91906122bd565b60206040518083038185885af115801561080d573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906108329190612323565b96505b60408201511561092757600061084b828d61233c565b905073e592427a0aece92de3edee1f18e0157c0586156463c04b8d5986610873576000610875565b825b6040805160a0810182526060808901518252306020830152428284015281018690526000608082015290517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526108d691906004016122bd565b60206040518083038185885af11580156108f4573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906109199190612323565b6109239089612353565b9750505b601284610a2e578f60200160208101906109419190612181565b73ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156109c5575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526109c29181019061236b565b60015b610a28573d8080156109f3576040519150601f19603f3d011682016040523d82523d6000602084013e6109f8565b606091505b506040517fffedc4485579c09008593425e50995352329b8c53feca227b2866eb5559da9d790600090a150610a2e565b60ff1690505b6000610a3b82600a6124ae565b6080850151610a4a908f6121cb565b610a549190612208565b905080891015610a90576040517fe52970aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8415610bb7576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018a905273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290632e1a7d4d90602401600060405180830381600087803b158015610afc57600080fd5b505af1158015610b10573d6000803e3d6000fd5b50506040517f12a53623000000000000000000000000000000000000000000000000000000008152600481018f905273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001692506312a5362391508b906024016000604051808303818588803b158015610b9d57600080fd5b505af1158015610bb1573d6000803e3d6000fd5b50505050505b505050505050985098509895505050505050565b6000610bd982358435612353565b606414610c12576040517f4fc6923600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c1b82611132565b6013610c2685611132565b901b602667ffffffffffffffff16610cb089898973ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca8919061236b565b60ff166111df565b610cbb92911b612353565b610cc59190612353565b9695505050505050565b600080610ce7858567ffffffffffffffff1685611053565b905060006064826000015188610cfd91906121cb565b610d079190612208565b825190915015610db75760208201516040517fcdca175300000000000000000000000000000000000000000000000000000000815273b27308f9f90d607463bb33ea1bebb41c27ce5ab69163cdca175391610d67919085906004016124ba565b6020604051808303816000875af1158015610d86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610daa9190612323565b610db49084612353565b92505b604082015115610e5957606082015173b27308f9f90d607463bb33ea1bebb41c27ce5ab69063cdca175390610dec848b61233c565b6040518363ffffffff1660e01b8152600401610e099291906124ba565b6020604051808303816000875af1158015610e28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4c9190612323565b610e569084612353565b92505b5050949350505050565b8260005b81811015610f2e576000868683818110610e8357610e836124dc565b9050602002016020810190610e989190612181565b9050610ed073ffffffffffffffffffffffffffffffffffffffff821673e592427a0aece92de3edee1f18e0157c05861564600061129a565b610f2573ffffffffffffffffffffffffffffffffffffffff821673e592427a0aece92de3edee1f18e0157c058615647fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61129a565b50600101610e67565b5081905060005b81811015611014576000848483818110610f5157610f516124dc565b9050602002016020810190610f669190612181565b9050610faa73ffffffffffffffffffffffffffffffffffffffff82167f0000000000000000000000000000000000000000000000000000000000000000600061129a565b61100b73ffffffffffffffffffffffffffffffffffffffff82167f00000000000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61129a565b50600101610f35565b505050505050565b60008060006040517f26d18eab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110856040518060a0016040528060008152602001606081526020016000815260200160608152602001600081525090565b600080611098866207ffff87168661145d565b8185526020850181905290925090506000806110be88601389901c6207ffff168861145d565b90925090506110cd8285612353565b606414611106576040517f4fc6923600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040850182905260608501819052611121602688901c6116ca565b608086015250929695505050505050565b6000813561114257506000919050565b61114f8260a001356116f2565b600261116961116460a0860160808701612181565b61176d565b901b600561117a85606001356116f2565b901b60076111916111646060880160408901612181565b901b600a6111a287602001356116f2565b6111b1911b8735600c1b612353565b6111bb9190612353565b6111c59190612353565b6111cf9190612353565b6111d99190612353565b92915050565b600080846111ee84600a6124ae565b6111f890866121cb565b6112029190612208565b9050621fffff811161121a57600581901b9150611292565b60005b621fffff82111561128057611233600a83612208565b915061123e8161250b565b9050601f81111561127b576040517f35278d1200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61121d565b61128e81600584901b612353565b9250505b509392505050565b80158061133a57506040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611314573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113389190612323565b155b6113cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084015b60405180910390fd5b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905261145890849061195a565b505050565b600c82901c60606003808516906007600287901c811691600588901c81169188811c1690600a89901c16811580159061149557508315155b1561157457896114a482611a66565b6114ad84611add565b6114b686611a66565b6114bf88611add565b6114c88a611a66565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606097881b811660208301527fffffff000000000000000000000000000000000000000000000000000000000060e897881b8116603484015295881b8116603783015293861b8516604b82015291861b8316604e83015290931b9091166062830152918a901b90911660658201526079015b60405160208183030381529060405295506116bd565b811561161d578961158482611a66565b61158d84611add565b61159688611a66565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606095861b811660208301527fffffff000000000000000000000000000000000000000000000000000000000060e895861b8116603484015293861b811660378301529190931b909116604b830152918a901b909116604e82015260620161155e565b8315611636578961162d84611a66565b61158d86611add565b8961164086611a66565b604051606092831b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000908116602083015260e89290921b7fffffff0000000000000000000000000000000000000000000000000000000000166034820152918a901b166037820152604b0160405160208183030381529060405295505b5050505050935093915050565b6000600582901c601f83166116e081600a6124ae565b6116ea90836121cb565b949350505050565b6000816064141561170557506000919050565b816101f4141561171757506001919050565b81610bb8141561172957506002919050565b81612710141561173b57506003919050565b6040517f3733548a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff821661179257506000919050565b73ffffffffffffffffffffffffffffffffffffffff821673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214156117cc57506001919050565b73ffffffffffffffffffffffffffffffffffffffff821673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48141561180657506002919050565b73ffffffffffffffffffffffffffffffffffffffff821673dac17f958d2ee523a2206206994597c13d831ec7141561184057506003919050565b73ffffffffffffffffffffffffffffffffffffffff8216736b175474e89094c44da98b954eedeac495271d0f141561187a57506004919050565b73ffffffffffffffffffffffffffffffffffffffff8216732260fac5e5542a773aa44fbcfedf7c193bc2c59914156118b457506005919050565b73ffffffffffffffffffffffffffffffffffffffff821673853d955acef822db058eb8505911ed77f175b99e14156118ee57506006919050565b73ffffffffffffffffffffffffffffffffffffffff8216734fabb145d64652a948d72533023f6e7a623c7c53141561192857506007919050565b6040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006119bc826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611c0d9092919063ffffffff16565b80519091501561145857808060200190518101906119da9190612544565b611458576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016113c2565b600081611a7557506064919050565b8160011415611a8757506101f4919050565b8160021415611a995750610bb8919050565b8160031415611aab5750612710919050565b6040517f1b719c2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008160011415611b03575073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2919050565b8160021415611b27575073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48919050565b8160031415611b4b575073dac17f958d2ee523a2206206994597c13d831ec7919050565b8160041415611b6f5750736b175474e89094c44da98b954eedeac495271d0f919050565b8160051415611b935750732260fac5e5542a773aa44fbcfedf7c193bc2c599919050565b8160061415611bb7575073853d955acef822db058eb8505911ed77f175b99e919050565b8160071415611bdb5750734fabb145d64652a948d72533023f6e7a623c7c53919050565b6040517f3d51b26900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060611c1c8484600085611c26565b90505b9392505050565b606082471015611cb8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016113c2565b73ffffffffffffffffffffffffffffffffffffffff85163b611d36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016113c2565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611d5f9190612566565b60006040518083038185875af1925050503d8060008114611d9c576040519150601f19603f3d011682016040523d82523d6000602084013e611da1565b606091505b5091509150610e5682828660608315611dbb575081611c1f565b825115611dcb5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113c29190612582565b600060608284031215611e1157600080fd5b50919050565b803567ffffffffffffffff81168114611e2f57600080fd5b919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611e2f57600080fd5b600080600080600080600080610200898b031215611e7557600080fd5b611e7f8a8a611dff565b9750611e8e8a60608b01611dff565b9650611e9d8a60c08b01611dff565b9550611ead8a6101208b01611dff565b945061018089013593506101a08901359250611ecc6101c08a01611e17565b9150611edb6101e08a01611e34565b90509295985092959890939650565b600060c08284031215611e1157600080fd5b60008060008060006101e08688031215611f1557600080fd5b8535945060208601359350611f2c60408701611e34565b9250611f3b8760608801611eea565b9150611f4b876101208801611eea565b90509295509295909350565b60008060008060808587031215611f6d57600080fd5b84359350611f7d60208601611e34565b9250611f8b60408601611e17565b9150611f9960608601611e34565b905092959194509250565b60008083601f840112611fb657600080fd5b50813567ffffffffffffffff811115611fce57600080fd5b6020830191508360208260051b8501011115611fe957600080fd5b9250929050565b6000806000806040858703121561200657600080fd5b843567ffffffffffffffff8082111561201e57600080fd5b61202a88838901611fa4565b9096509450602087013591508082111561204357600080fd5b5061205087828801611fa4565b95989497509550505050565b6000806000806000806101c0878903121561207657600080fd5b6120808888611dff565b955061208f8860608901611dff565b945061209e8860c08901611dff565b93506120ae886101208901611dff565b925061018087013591506120c56101a08801611e17565b90509295509295509295565b60008060008060006101a086880312156120ea57600080fd5b6120f48787611dff565b94506121038760608801611dff565b93506121128760c08801611dff565b9250612122876101208801611dff565b9150611f4b6101808701611e17565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006020828403121561217257600080fd5b813560048110611c1f57600080fd5b60006020828403121561219357600080fd5b611c1f82611e34565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156122035761220361219c565b500290565b60008261223e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60005b8381101561225e578181015183820152602001612246565b8381111561226d576000848401525b50505050565b6000815180845261228b816020860160208601612243565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000825160a060208401526122d960c0840182612273565b905073ffffffffffffffffffffffffffffffffffffffff60208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b60006020828403121561233557600080fd5b5051919050565b60008282101561234e5761234e61219c565b500390565b600082198211156123665761236661219c565b500190565b60006020828403121561237d57600080fd5b815160ff81168114611c1f57600080fd5b600181815b808511156123e757817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156123cd576123cd61219c565b808516156123da57918102915b93841c9390800290612393565b509250929050565b6000826123fe575060016111d9565b8161240b575060006111d9565b8160018114612421576002811461242b57612447565b60019150506111d9565b60ff84111561243c5761243c61219c565b50506001821b6111d9565b5060208310610133831016604e8410600b841016171561246a575081810a6111d9565b612474838361238e565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156124a6576124a661219c565b029392505050565b6000611c1f83836123ef565b6040815260006124cd6040830185612273565b90508260208301529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561253d5761253d61219c565b5060010190565b60006020828403121561255657600080fd5b81518015158114611c1f57600080fd5b60008251612578818460208701612243565b9190910192915050565b602081526000611c1f602083018461227356fea2646970667358221220fe128686af51377f8bf46eba4d571ac89199e95d30bab46d448b577123e8dd8164736f6c634300080a0033000000000000000000000000ff1f2b4adb9df6fc8eafecdcbf96a2b351680455
Deployed Bytecode
0x60806040526004361061019a5760003560e01c80638cb0d0c9116100e1578063ae9467b51161008a578063dbeacd5411610064578063dbeacd54146104b8578063e0bab4c4146104de578063e5488ed214610506578063ee622c3d1461051e57600080fd5b8063ae9467b514610434578063b0e4556f14610468578063c54e44eb1461049057600080fd5b8063a437399a116100bb578063a437399a146103e2578063aa271e27146103f7578063ad5c46481461040c57600080fd5b80638cb0d0c9146103855780638dae88c2146103a75780639b07d342146103cf57600080fd5b80634dede3de116101435780637c09cfde1161011d5780637c09cfde1461030f57806381ebd5291461032f57806389a302711461035d57600080fd5b80634dede3de146102aa5780636508156e146102d2578063797556cc146102fa57600080fd5b806326c3b5151161017457806326c3b5151461020557806332fe7b2614610235578063484f4ea91461028257600080fd5b806301cbe1f5146101a657806312d6a099146101d957806322cfd024146101f057600080fd5b366101a157005b600080fd5b3480156101b257600080fd5b506101bb601f81565b60405167ffffffffffffffff90911681526020015b60405180910390f35b3480156101e557600080fd5b506101bb6207ffff81565b3480156101fc57600080fd5b506101bb601381565b610218610213366004611e58565b610533565b6040805193845260208401929092521515908201526060016101d0565b34801561024157600080fd5b5061025d73e592427a0aece92de3edee1f18e0157c0586156481565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d0565b34801561028e57600080fd5b5061025d734fabb145d64652a948d72533023f6e7a623c7c5381565b3480156102b657600080fd5b5061025d732260fac5e5542a773aa44fbcfedf7c193bc2c59981565b3480156102de57600080fd5b5061025d73abc30e831b5cc173a9ed5941714a7845c909e7fa81565b34801561030657600080fd5b506101bb602681565b34801561031b57600080fd5b506101bb61032a366004611efc565b610bcb565b34801561033b57600080fd5b5061034f61034a366004611f57565b610ccf565b6040519081526020016101d0565b34801561036957600080fd5b5061025d73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b34801561039157600080fd5b506103a56103a0366004611ff0565b610e63565b005b3480156103b357600080fd5b5061025d73b27308f9f90d607463bb33ea1bebb41c27ce5ab681565b6102186103dd36600461205c565b61101c565b3480156103ee57600080fd5b506101bb600381565b34801561040357600080fd5b506101bb601a81565b34801561041857600080fd5b5061025d73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b34801561044057600080fd5b5061025d7f000000000000000000000000ff1f2b4adb9df6fc8eafecdcbf96a2b35168045581565b34801561047457600080fd5b5061025d73853d955acef822db058eb8505911ed77f175b99e81565b34801561049c57600080fd5b5061025d73dac17f958d2ee523a2206206994597c13d831ec781565b3480156104c457600080fd5b5061034f6104d33660046120d1565b600095945050505050565b3480156104ea57600080fd5b5061025d736b175474e89094c44da98b954eedeac495271d0f81565b34801561051257600080fd5b506101bb6303ffffff81565b34801561052a57600080fd5b506101bb600781565b600080803373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ff1f2b4adb9df6fc8eafecdcbf96a2b35168045516146105a6576040517f48f5c3ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060016105ba60608e0160408f01612160565b60038111156105cb576105cb612131565b149050600060016105e260608d0160408e01612160565b60038111156105f3576105f3612131565b14905060028d604001602081019061060b9190612160565b600381111561061c5761061c612131565b14158015610628575081155b1561065f576040517fc582880b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600261067160608d0160408e01612160565b600381111561068257610682612131565b1415801561068e575080155b156106c5576040517f6c98dcaf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061073f836106e7578e60200160208101906106e29190612181565b6106fd565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b8967ffffffffffffffff1684610725578e60200160208101906107209190612181565b611053565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2611053565b90506000606482600001518c61075591906121cb565b61075f9190612208565b8251909150156108355773e592427a0aece92de3edee1f18e0157c0586156463c04b8d598561078f576000610791565b825b6040518060a00160405280866020015181526020013073ffffffffffffffffffffffffffffffffffffffff16815260200142815260200185815260200160008152506040518363ffffffff1660e01b81526004016107ef91906122bd565b60206040518083038185885af115801561080d573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906108329190612323565b96505b60408201511561092757600061084b828d61233c565b905073e592427a0aece92de3edee1f18e0157c0586156463c04b8d5986610873576000610875565b825b6040805160a0810182526060808901518252306020830152428284015281018690526000608082015290517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526108d691906004016122bd565b60206040518083038185885af11580156108f4573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906109199190612323565b6109239089612353565b9750505b601284610a2e578f60200160208101906109419190612181565b73ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156109c5575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526109c29181019061236b565b60015b610a28573d8080156109f3576040519150601f19603f3d011682016040523d82523d6000602084013e6109f8565b606091505b506040517fffedc4485579c09008593425e50995352329b8c53feca227b2866eb5559da9d790600090a150610a2e565b60ff1690505b6000610a3b82600a6124ae565b6080850151610a4a908f6121cb565b610a549190612208565b905080891015610a90576040517fe52970aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8415610bb7576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018a905273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290632e1a7d4d90602401600060405180830381600087803b158015610afc57600080fd5b505af1158015610b10573d6000803e3d6000fd5b50506040517f12a53623000000000000000000000000000000000000000000000000000000008152600481018f905273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ff1f2b4adb9df6fc8eafecdcbf96a2b3516804551692506312a5362391508b906024016000604051808303818588803b158015610b9d57600080fd5b505af1158015610bb1573d6000803e3d6000fd5b50505050505b505050505050985098509895505050505050565b6000610bd982358435612353565b606414610c12576040517f4fc6923600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c1b82611132565b6013610c2685611132565b901b602667ffffffffffffffff16610cb089898973ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca8919061236b565b60ff166111df565b610cbb92911b612353565b610cc59190612353565b9695505050505050565b600080610ce7858567ffffffffffffffff1685611053565b905060006064826000015188610cfd91906121cb565b610d079190612208565b825190915015610db75760208201516040517fcdca175300000000000000000000000000000000000000000000000000000000815273b27308f9f90d607463bb33ea1bebb41c27ce5ab69163cdca175391610d67919085906004016124ba565b6020604051808303816000875af1158015610d86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610daa9190612323565b610db49084612353565b92505b604082015115610e5957606082015173b27308f9f90d607463bb33ea1bebb41c27ce5ab69063cdca175390610dec848b61233c565b6040518363ffffffff1660e01b8152600401610e099291906124ba565b6020604051808303816000875af1158015610e28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4c9190612323565b610e569084612353565b92505b5050949350505050565b8260005b81811015610f2e576000868683818110610e8357610e836124dc565b9050602002016020810190610e989190612181565b9050610ed073ffffffffffffffffffffffffffffffffffffffff821673e592427a0aece92de3edee1f18e0157c05861564600061129a565b610f2573ffffffffffffffffffffffffffffffffffffffff821673e592427a0aece92de3edee1f18e0157c058615647fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61129a565b50600101610e67565b5081905060005b81811015611014576000848483818110610f5157610f516124dc565b9050602002016020810190610f669190612181565b9050610faa73ffffffffffffffffffffffffffffffffffffffff82167f000000000000000000000000ff1f2b4adb9df6fc8eafecdcbf96a2b351680455600061129a565b61100b73ffffffffffffffffffffffffffffffffffffffff82167f000000000000000000000000ff1f2b4adb9df6fc8eafecdcbf96a2b3516804557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61129a565b50600101610f35565b505050505050565b60008060006040517f26d18eab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110856040518060a0016040528060008152602001606081526020016000815260200160608152602001600081525090565b600080611098866207ffff87168661145d565b8185526020850181905290925090506000806110be88601389901c6207ffff168861145d565b90925090506110cd8285612353565b606414611106576040517f4fc6923600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040850182905260608501819052611121602688901c6116ca565b608086015250929695505050505050565b6000813561114257506000919050565b61114f8260a001356116f2565b600261116961116460a0860160808701612181565b61176d565b901b600561117a85606001356116f2565b901b60076111916111646060880160408901612181565b901b600a6111a287602001356116f2565b6111b1911b8735600c1b612353565b6111bb9190612353565b6111c59190612353565b6111cf9190612353565b6111d99190612353565b92915050565b600080846111ee84600a6124ae565b6111f890866121cb565b6112029190612208565b9050621fffff811161121a57600581901b9150611292565b60005b621fffff82111561128057611233600a83612208565b915061123e8161250b565b9050601f81111561127b576040517f35278d1200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61121d565b61128e81600584901b612353565b9250505b509392505050565b80158061133a57506040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611314573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113389190612323565b155b6113cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084015b60405180910390fd5b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905261145890849061195a565b505050565b600c82901c60606003808516906007600287901c811691600588901c81169188811c1690600a89901c16811580159061149557508315155b1561157457896114a482611a66565b6114ad84611add565b6114b686611a66565b6114bf88611add565b6114c88a611a66565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606097881b811660208301527fffffff000000000000000000000000000000000000000000000000000000000060e897881b8116603484015295881b8116603783015293861b8516604b82015291861b8316604e83015290931b9091166062830152918a901b90911660658201526079015b60405160208183030381529060405295506116bd565b811561161d578961158482611a66565b61158d84611add565b61159688611a66565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606095861b811660208301527fffffff000000000000000000000000000000000000000000000000000000000060e895861b8116603484015293861b811660378301529190931b909116604b830152918a901b909116604e82015260620161155e565b8315611636578961162d84611a66565b61158d86611add565b8961164086611a66565b604051606092831b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000908116602083015260e89290921b7fffffff0000000000000000000000000000000000000000000000000000000000166034820152918a901b166037820152604b0160405160208183030381529060405295505b5050505050935093915050565b6000600582901c601f83166116e081600a6124ae565b6116ea90836121cb565b949350505050565b6000816064141561170557506000919050565b816101f4141561171757506001919050565b81610bb8141561172957506002919050565b81612710141561173b57506003919050565b6040517f3733548a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff821661179257506000919050565b73ffffffffffffffffffffffffffffffffffffffff821673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214156117cc57506001919050565b73ffffffffffffffffffffffffffffffffffffffff821673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48141561180657506002919050565b73ffffffffffffffffffffffffffffffffffffffff821673dac17f958d2ee523a2206206994597c13d831ec7141561184057506003919050565b73ffffffffffffffffffffffffffffffffffffffff8216736b175474e89094c44da98b954eedeac495271d0f141561187a57506004919050565b73ffffffffffffffffffffffffffffffffffffffff8216732260fac5e5542a773aa44fbcfedf7c193bc2c59914156118b457506005919050565b73ffffffffffffffffffffffffffffffffffffffff821673853d955acef822db058eb8505911ed77f175b99e14156118ee57506006919050565b73ffffffffffffffffffffffffffffffffffffffff8216734fabb145d64652a948d72533023f6e7a623c7c53141561192857506007919050565b6040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006119bc826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611c0d9092919063ffffffff16565b80519091501561145857808060200190518101906119da9190612544565b611458576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016113c2565b600081611a7557506064919050565b8160011415611a8757506101f4919050565b8160021415611a995750610bb8919050565b8160031415611aab5750612710919050565b6040517f1b719c2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008160011415611b03575073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2919050565b8160021415611b27575073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48919050565b8160031415611b4b575073dac17f958d2ee523a2206206994597c13d831ec7919050565b8160041415611b6f5750736b175474e89094c44da98b954eedeac495271d0f919050565b8160051415611b935750732260fac5e5542a773aa44fbcfedf7c193bc2c599919050565b8160061415611bb7575073853d955acef822db058eb8505911ed77f175b99e919050565b8160071415611bdb5750734fabb145d64652a948d72533023f6e7a623c7c53919050565b6040517f3d51b26900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060611c1c8484600085611c26565b90505b9392505050565b606082471015611cb8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016113c2565b73ffffffffffffffffffffffffffffffffffffffff85163b611d36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016113c2565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611d5f9190612566565b60006040518083038185875af1925050503d8060008114611d9c576040519150601f19603f3d011682016040523d82523d6000602084013e611da1565b606091505b5091509150610e5682828660608315611dbb575081611c1f565b825115611dcb5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113c29190612582565b600060608284031215611e1157600080fd5b50919050565b803567ffffffffffffffff81168114611e2f57600080fd5b919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611e2f57600080fd5b600080600080600080600080610200898b031215611e7557600080fd5b611e7f8a8a611dff565b9750611e8e8a60608b01611dff565b9650611e9d8a60c08b01611dff565b9550611ead8a6101208b01611dff565b945061018089013593506101a08901359250611ecc6101c08a01611e17565b9150611edb6101e08a01611e34565b90509295985092959890939650565b600060c08284031215611e1157600080fd5b60008060008060006101e08688031215611f1557600080fd5b8535945060208601359350611f2c60408701611e34565b9250611f3b8760608801611eea565b9150611f4b876101208801611eea565b90509295509295909350565b60008060008060808587031215611f6d57600080fd5b84359350611f7d60208601611e34565b9250611f8b60408601611e17565b9150611f9960608601611e34565b905092959194509250565b60008083601f840112611fb657600080fd5b50813567ffffffffffffffff811115611fce57600080fd5b6020830191508360208260051b8501011115611fe957600080fd5b9250929050565b6000806000806040858703121561200657600080fd5b843567ffffffffffffffff8082111561201e57600080fd5b61202a88838901611fa4565b9096509450602087013591508082111561204357600080fd5b5061205087828801611fa4565b95989497509550505050565b6000806000806000806101c0878903121561207657600080fd5b6120808888611dff565b955061208f8860608901611dff565b945061209e8860c08901611dff565b93506120ae886101208901611dff565b925061018087013591506120c56101a08801611e17565b90509295509295509295565b60008060008060006101a086880312156120ea57600080fd5b6120f48787611dff565b94506121038760608801611dff565b93506121128760c08801611dff565b9250612122876101208801611dff565b9150611f4b6101808701611e17565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006020828403121561217257600080fd5b813560048110611c1f57600080fd5b60006020828403121561219357600080fd5b611c1f82611e34565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156122035761220361219c565b500290565b60008261223e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60005b8381101561225e578181015183820152602001612246565b8381111561226d576000848401525b50505050565b6000815180845261228b816020860160208601612243565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000825160a060208401526122d960c0840182612273565b905073ffffffffffffffffffffffffffffffffffffffff60208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b60006020828403121561233557600080fd5b5051919050565b60008282101561234e5761234e61219c565b500390565b600082198211156123665761236661219c565b500190565b60006020828403121561237d57600080fd5b815160ff81168114611c1f57600080fd5b600181815b808511156123e757817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156123cd576123cd61219c565b808516156123da57918102915b93841c9390800290612393565b509250929050565b6000826123fe575060016111d9565b8161240b575060006111d9565b8160018114612421576002811461242b57612447565b60019150506111d9565b60ff84111561243c5761243c61219c565b50506001821b6111d9565b5060208310610133831016604e8410600b841016171561246a575081810a6111d9565b612474838361238e565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156124a6576124a661219c565b029392505050565b6000611c1f83836123ef565b6040815260006124cd6040830185612273565b90508260208301529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561253d5761253d61219c565b5060010190565b60006020828403121561255657600080fd5b81518015158114611c1f57600080fd5b60008251612578818460208701612243565b9190910192915050565b602081526000611c1f602083018461227356fea2646970667358221220fe128686af51377f8bf46eba4d571ac89199e95d30bab46d448b577123e8dd8164736f6c634300080a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ff1f2b4adb9df6fc8eafecdcbf96a2b351680455
-----Decoded View---------------
Arg [0] : _rollupProcessor (address): 0xFF1F2B4ADb9dF6FC8eAFecDcbF96A2B351680455
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000ff1f2b4adb9df6fc8eafecdcbf96a2b351680455
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.