ETH Price: $3,314.04 (+1.98%)
Gas: 3 Gwei

Contract

0x5594808e8A7b44da9D2382E6d72ad50a3e2571E0
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Pre Approve Toke...158068382022-10-22 23:10:11643 days ago1666480211IN
0x5594808e...a3e2571E0
0 ETH0.0018513312
0x60a06040158068382022-10-22 23:10:11643 days ago1666480211IN
 Create: UniswapBridge
0 ETH0.0255914112

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
UniswapBridge

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 100000 runs

Other Settings:
default evmVersion
File 1 of 15 : UniswapBridge.sol
// 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();
    }
}

File 2 of 15 : IERC20.sol
// 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);
}

File 3 of 15 : IERC20Metadata.sol
// 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);
}

File 4 of 15 : draft-IERC20Permit.sol
// 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);
}

File 5 of 15 : SafeERC20.sol
// 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");
        }
    }
}

File 6 of 15 : Address.sol
// 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);
            }
        }
    }
}

File 7 of 15 : IDefiBridge.sol
// 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
        );
}

File 8 of 15 : IRollupProcessor.sol
// 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);
}

File 9 of 15 : ISubsidy.sol
// 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);
}

File 10 of 15 : AztecTypes.sol
// 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;
    }
}

File 11 of 15 : BridgeBase.sol
// 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;
    }
}

File 12 of 15 : ErrorLib.sol
// 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();
}

File 13 of 15 : IWETH.sol
// 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;
}

File 14 of 15 : IQuoter.sol
// 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);
}

File 15 of 15 : ISwapRouter.sol
// 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);
}

Settings
{
  "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

Contract ABI

[{"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"}]

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


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
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.