ETH Price: $3,488.12 (+7.46%)
Gas: 5 Gwei

Contract

0x94679A39679ffE53B53b6a1187aa1c649A101321
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Rebalance And Fi...157819872022-10-19 11:55:23635 days ago1666180523IN
0x94679A39...49A101321
0 ETH0.005336716.1646384
Rebalance And Fi...157670142022-10-17 9:44:11637 days ago1665999851IN
0x94679A39...49A101321
0 ETH0.0037301512.6289126
Rebalance And Fi...157136872022-10-09 23:01:35645 days ago1665356495IN
0x94679A39...49A101321
0 ETH0.0121013330.78476996
Rebalance And Fi...156914922022-10-06 20:37:35648 days ago1665088655IN
0x94679A39...49A101321
0 ETH0.0042653915.40510194
Rebalance And Fi...156830522022-10-05 16:19:47649 days ago1664986787IN
0x94679A39...49A101321
0 ETH0.0109350539.50010762
Rebalance And Fi...156757162022-10-04 15:39:23650 days ago1664897963IN
0x94679A39...49A101321
0 ETH0.0050812217.79179393
Rebalance And Fi...156707612022-10-03 22:59:23651 days ago1664837963IN
0x94679A39...49A101321
0 ETH0.0045586816.46138568
Rebalance And Fi...156593362022-10-02 8:42:35652 days ago1664700155IN
0x94679A39...49A101321
0 ETH0.00156984.71323688
Rebalance And Fi...156483152022-09-30 19:43:11654 days ago1664566991IN
0x94679A39...49A101321
0 ETH0.0042625115.30911615
Rebalance And Fi...156483102022-09-30 19:42:11654 days ago1664566931IN
0x94679A39...49A101321
0 ETH0.0049967716.42448274
Rebalance And Fi...156403012022-09-29 16:50:35655 days ago1664470235IN
0x94679A39...49A101321
0 ETH0.007333326.33815322
Rebalance And Fi...156331032022-09-28 16:42:47656 days ago1664383367IN
0x94679A39...49A101321
0 ETH0.0037920413.61794909
0x61012060155827932022-09-21 15:59:35663 days ago1663775975IN
 Create: UniswapDCABridge
0 ETH0.0644382416.72635344

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
169674672023-04-03 8:57:59469 days ago1680512279
0x94679A39...49A101321
0.98877328 ETH
169674672023-04-03 8:57:59469 days ago1680512279
0x94679A39...49A101321
0.98877328 ETH
168864102023-03-22 23:30:59481 days ago1679527859
0x94679A39...49A101321
1.14831567 ETH
168864102023-03-22 23:30:59481 days ago1679527859
0x94679A39...49A101321
1.14831567 ETH
168832892023-03-22 12:59:35481 days ago1679489975
0x94679A39...49A101321
0.00038 ETH
168832892023-03-22 12:59:35481 days ago1679489975
0x94679A39...49A101321
0.00038 ETH
168718762023-03-20 22:32:23483 days ago1679351543
0x94679A39...49A101321
0.05846 ETH
168718762023-03-20 22:32:23483 days ago1679351543
0x94679A39...49A101321
0.05846 ETH
168692742023-03-20 13:46:47483 days ago1679320007
0x94679A39...49A101321
0.047775 ETH
168692742023-03-20 13:46:47483 days ago1679320007
0x94679A39...49A101321
0.047775 ETH
168576682023-03-18 22:39:23485 days ago1679179163
0x94679A39...49A101321
10.181478 ETH
168576682023-03-18 22:39:23485 days ago1679179163
0x94679A39...49A101321
10.181478 ETH
168538562023-03-18 9:49:35485 days ago1679132975
0x94679A39...49A101321
2.5244728 ETH
168538562023-03-18 9:49:35485 days ago1679132975
0x94679A39...49A101321
2.5244728 ETH
168538562023-03-18 9:49:35485 days ago1679132975
0x94679A39...49A101321
1.02731719 ETH
168538562023-03-18 9:49:35485 days ago1679132975
0x94679A39...49A101321
1.02731719 ETH
168387622023-03-16 6:53:59487 days ago1678949639
0x94679A39...49A101321
3.6635447 ETH
168387622023-03-16 6:53:59487 days ago1678949639
0x94679A39...49A101321
3.6635447 ETH
168270542023-03-14 15:22:47489 days ago1678807367
0x94679A39...49A101321
0.151196 ETH
168270542023-03-14 15:22:47489 days ago1678807367
0x94679A39...49A101321
0.151196 ETH
168196592023-03-13 14:27:35490 days ago1678717655
0x94679A39...49A101321
1.98253301 ETH
168196592023-03-13 14:27:35490 days ago1678717655
0x94679A39...49A101321
1.98253301 ETH
168196592023-03-13 14:27:35490 days ago1678717655
0x94679A39...49A101321
8.4556439 ETH
168196592023-03-13 14:27:35490 days ago1678717655
0x94679A39...49A101321
8.4556439 ETH
168115242023-03-12 11:03:23491 days ago1678619003
0x94679A39...49A101321
0.268017 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
UniswapDCABridge

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 100000 runs

Other Settings:
default evmVersion
File 1 of 16 : UniswapDCABridge.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 {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import {IWETH} from "../../interfaces/IWETH.sol";
import {IChainlinkOracle} from "../../interfaces/chainlink/IChainlinkOracle.sol";
import {ISwapRouter} from "../../interfaces/uniswapv3/ISwapRouter.sol";
import {BiDCABridge} from "./BiDCABridge.sol";

/**
 * @notice Initial implementation of the BiDCA bridge using Uniswap as the DEX and Chainlink as oracle.
 * The bridge is using DAI and WETH for A and B with a Chainlink oracle to get prices.
 * The bridge allows users to force a rebalance through Uniswap pools.
 * The forced rebalance will:
 * 1. rebalance internally in the ticks, as the BiDCABridge,
 * 2. rebalance cross-ticks, e.g., excess from the individual ticks are matched,
 * 3. swap any remaining excess using Uniswap, and rebalance with the returned assets
 * @dev The slippage + path is immutable, so low liquidity in Uniswap might block the `rebalanceAndfillUniswap` flow.
 * @author Lasse Herskind (LHerskind on GitHub).
 */
contract UniswapDCABridge is BiDCABridge {
    using SafeERC20 for IERC20;

    error NegativePrice();

    address internal constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
    address internal constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;

    uint160 internal constant SQRT_PRICE_LIMIT_X96 = 1461446703485210103287273052203988822378723970341;
    ISwapRouter public constant UNI_ROUTER = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564);

    uint256 public constant SLIPPAGE = 100; // Basis points

    IChainlinkOracle public constant ORACLE = IChainlinkOracle(0x773616E4d11A78F511299002da57A0a94577F1f4);

    constructor(
        address _rollupProcessor,
        uint256 _tickSize,
        uint256 _fee
    ) BiDCABridge(_rollupProcessor, DAI, address(WETH), _tickSize, _fee) {
        IERC20(DAI).safeApprove(address(UNI_ROUTER), type(uint256).max);
        IERC20(address(WETH)).safeApprove(address(UNI_ROUTER), type(uint256).max);
    }

    function rebalanceAndFillUniswap() public returns (int256, int256) {
        rebalanceAndFillUniswap(type(uint256).max);
    }

    /**
     * @notice Rebalances within ticks, then across ticks, and finally, take the remaining funds to uniswap
     * where it is traded for the opposite, and used to rebalance completely
     * @dev Uses a specific path for the assets to do the swap
     * @dev Slippage protection through the chainlink oracle, as a base price
     * @dev Can be quite gas intensive as it will loop multiple times over the ticks to fill orders.
     * @return aFlow The flow of token A
     * @return bFlow The flow of token B
     */
    function rebalanceAndFillUniswap(uint256 _upperTick) public returns (int256, int256) {
        uint256 oraclePrice = getPrice();
        (int256 aFlow, int256 bFlow, uint256 a, uint256 b) = _rebalanceAndFill(0, 0, oraclePrice, _upperTick, true);

        // If we have available A and B, we can do internal rebalancing across ticks with these values.
        if (a > 0 && b > 0) {
            (aFlow, bFlow, a, b) = _rebalanceAndFill(a, b, oraclePrice, _upperTick, true);
        }

        if (a > 0) {
            // Trade all A to B using uniswap.
            uint256 bOffer = UNI_ROUTER.exactInput(
                ISwapRouter.ExactInputParams({
                    path: abi.encodePacked(ASSET_A, uint24(100), USDC, uint24(500), ASSET_B),
                    recipient: address(this),
                    deadline: block.timestamp,
                    amountIn: a,
                    amountOutMinimum: (denominateAssetAInB(a, oraclePrice, false) * (10000 - SLIPPAGE)) / 10000
                })
            );

            // Rounding DOWN ensures that B received / price >= A available
            uint256 price = (bOffer * 1e18) / a;

            (aFlow, bFlow, , ) = _rebalanceAndFill(0, bOffer, price, _upperTick, true);
        }

        if (b > 0) {
            // Trade all B to A using uniswap.
            uint256 aOffer = UNI_ROUTER.exactInput(
                ISwapRouter.ExactInputParams({
                    path: abi.encodePacked(ASSET_B, uint24(500), USDC, uint24(100), ASSET_A),
                    recipient: address(this),
                    deadline: block.timestamp,
                    amountIn: b,
                    amountOutMinimum: (denominateAssetBInA(b, oraclePrice, false) * (10000 - SLIPPAGE)) / 10000
                })
            );

            // Rounding UP to ensure that A received * price >= B available
            uint256 price = (b * 1e18 + aOffer - 1) / aOffer;

            (aFlow, bFlow, , ) = _rebalanceAndFill(aOffer, 0, price, _upperTick, true);
        }

        return (aFlow, bFlow);
    }

    /**
     * @notice Fetch the price from the chainlink oracle.
     * @dev Reverts if the price is stale or negative
     * @return Price
     */
    function getPrice() public virtual override(BiDCABridge) returns (uint256) {
        (, int256 answer, , , ) = ORACLE.latestRoundData();
        if (answer < 0) {
            revert NegativePrice();
        }

        return uint256(answer);
    }
}

File 2 of 16 : 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 16 : 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 4 of 16 : 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 5 of 16 : IChainlinkOracle.sol
// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec.
pragma solidity >=0.8.4;

interface IChainlinkOracle {
    function latestRoundData()
        external
        view
        returns (
            uint80,
            int256,
            uint256,
            uint256,
            uint80
        );
}

File 6 of 16 : 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);
}

File 7 of 16 : BiDCABridge.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 {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import {IRollupProcessor} from "../../aztec/interfaces/IRollupProcessor.sol";
import {BridgeBase} from "../base/BridgeBase.sol";
import {ErrorLib} from "../base/ErrorLib.sol";
import {AztecTypes} from "../../aztec/libraries/AztecTypes.sol";

import {IWETH} from "../../interfaces/IWETH.sol";

import {SafeCastLib} from "./SafeCastLib.sol";

/**
 * @notice Initial abstract implementation of "Dollar" Cost Averaging.
 * The bridge implements a bidirectional dollar cost averaging protocol,
 * allowing users to go either direction between two tokens A and B.
 * The "order" is executed over a period of time, instead of all at once.
 * For Eth and Dai, this allows the user to sell Dai to buy Eth over X days, and vice versa.
 * The timeperiod is divided into ticks, with each tick keeping track of the funds that should be traded in that tick.
 * As well as the price, and how much have been received in return.
 * To "balance" the scheme, an external party can buy assets at the orace-price (no slippage).
 * The amount that can be bought by the external party, depends on the ticks and how much can be matched internally.
 * As part of the balancing act, each tick will match the A and B holdings it has to sell, using the oracle price
 * (or infer price from prior price and current price).
 * The excess from this internal matching is then sold off to the caller at oracle price, to match his offer.
 * The rebalancing is expected to be done by arbitrageurs when prices deviate sufficiently between the oracle and dexes.
 * The finalise function is incentivised by giving part of the traded value to the `tx.origin` (msg.sender always rollup processor).
 * Extensions to this bridge can be made such that the external party can be Uniswap or another dex.
 * An extension should also define the oracle to be used for the price.
 * @dev Built for assets with 18 decimals precision
 * @dev A contract that inherits must handle the case for forcing a swap through a DEX.
 * @author Lasse Herskind (LHerskind on GitHub).
 */
abstract contract BiDCABridge is BridgeBase {
    using SafeERC20 for IERC20;
    using SafeCastLib for uint256;
    using SafeCastLib for uint128;

    error FeeTooLarge();
    error PositionAlreadyExists();
    error NoDeposits();

    /**
     * @notice A struct used in-memory to get around stack-to-deep errors
     * @member currentPrice Current oracle price
     * @member earliestTickWithAvailableA Earliest tick with available asset A
     * @member earliestTickWithAvailableB Earliest tick with available asset B
     * @member offerAInB Amount of asset B that is offered to be bought at the current price for A
     * @member offerBInA Amount of asset A that is offered to be bought at the current price for B
     * @member protocolSoldA Amount of asset A the bridge sold
     * @member protocolSoldB Amount of asset B the bridge sold
     * @member protocolBoughtA Amount of asset A the bridge bought
     * @member protocolBoughtB Amount of asset B the bridge bought
     * @member lastUsedPrice Last used price during rebalancing (cache in case new price won't be available)
     * @member lastUsedPriceTime Time at which last used price was set
     * @member availableA The amount of asset A that is available
     * @member availableB The amount of asset B that is available
     */
    struct RebalanceValues {
        uint256 currentPrice;
        uint256 earliestTickWithAvailableA;
        uint256 earliestTickWithAvailableB;
        uint256 offerAInB;
        uint256 offerBInA;
        uint256 protocolSoldA;
        uint256 protocolSoldB;
        uint256 protocolBoughtA;
        uint256 protocolBoughtB;
        uint256 lastUsedPrice;
        uint256 lastUsedPriceTime;
        uint256 availableA;
        uint256 availableB;
    }

    /**
     * @notice A struct representing 1 DCA position
     * @member amount Amount of asset A or B to be sold
     * @member start Index of the first tick this position touches
     * @member end Index of the last tick this position touches
     * @member aToB True if A is being sold to B, false otherwise
     */
    struct DCA {
        uint128 amount;
        uint32 start;
        uint32 end;
        bool aToB;
    }

    /**
     * @notice A struct defining one direction in a tick
     * @member sold Amount of asset sold
     * @member bought Amount of asset bought
     */
    struct SubTick {
        uint128 sold;
        uint128 bought;
    }

    /**
     * @notice A container for Tick related data
     * @member availableA Amount of A available in a tick for sale
     * @member availableB Amount of B available in a tick for sale
     * @member poke A value used only to initialize a storage slot
     * @member aToBSubTick A struct capturing info of A to B trades
     * @member aToBSubTick A struct capturing info of B to A trades
     * @member priceAToB A price of A denominated in B
     * @member priceTime A time at which price was last updated
     */
    struct Tick {
        uint120 availableA;
        uint120 availableB;
        uint16 poke;
        SubTick aToBSubTick;
        SubTick bToASubTick;
        uint128 priceOfAInB;
        uint32 priceTime;
    }

    IWETH internal constant WETH = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
    uint256 public constant FEE_DIVISOR = 10000;

    // The assets that are DCAed between
    IERC20 public immutable ASSET_A;
    IERC20 public immutable ASSET_B;

    // The timespan that a tick covers
    uint256 public immutable TICK_SIZE;
    uint256 public immutable FEE;

    // The earliest tick where we had available A or B respectively.
    uint32 public earliestTickWithAvailableA;
    uint32 public earliestTickWithAvailableB;

    // tick id => Tick.
    mapping(uint256 => Tick) public ticks;
    // nonce => DCA
    mapping(uint256 => DCA) public dcas;

    /**
     * @notice Constructor
     * @param _rollupProcessor The address of the rollup processor for the bridge
     * @param _assetA The address of asset A
     * @param _assetB The address of asset B
     * @param _tickSize The time-span that each tick covers in seconds
     * @dev Smaller _tickSizes will increase looping and gas costs
     */
    constructor(
        address _rollupProcessor,
        address _assetA,
        address _assetB,
        uint256 _tickSize,
        uint256 _fee
    ) BridgeBase(_rollupProcessor) {
        ASSET_A = IERC20(_assetA);
        ASSET_B = IERC20(_assetB);
        TICK_SIZE = _tickSize;

        IERC20(_assetA).safeApprove(_rollupProcessor, type(uint256).max);
        IERC20(_assetB).safeApprove(_rollupProcessor, type(uint256).max);

        if (_fee > FEE_DIVISOR) {
            revert FeeTooLarge();
        }
        FEE = _fee;
    }

    receive() external payable {}

    /**
     * @notice Helper used to poke storage from next tick and `_ticks` forwards
     * @param _numTicks The number of ticks to poke
     */
    function pokeNextTicks(uint256 _numTicks) external {
        pokeTicks(_nextTick(block.timestamp), _numTicks);
    }

    /**
     * @notice Helper used to poke storage of ticks to make deposits more consistent in gas usage
     * @dev First sstore is very expensive, so by doing it as this, we can prepare it before deposit
     * @param _startTick The first tick to poke
     * @param _numTicks The number of ticks to poke
     */
    function pokeTicks(uint256 _startTick, uint256 _numTicks) public {
        for (uint256 i = _startTick; i < _startTick + _numTicks; i++) {
            ticks[i].poke++;
        }
    }

    /**
     * @notice Rebalances ticks using internal values first, then with externally provided assets.
     * Ticks are balanced internally using the price at the specific tick (either stored in tick, or interpolated).
     * Leftover assets are sold using current price to fill as much of the offer as possible.
     * @param _offerA The amount of asset A that is offered for sale to the bridge
     * @param _offerB The amount of asset B that is offered for sale to the bridge
     * @return flowA The flow of asset A from the bridge POV, e.g., >0 = buying of tokens, <0 = selling tokens
     * @return flowB The flow of asset B from the bridge POV, e.g., >0 = buying of tokens, <0 = selling tokens
     */
    function rebalanceAndFill(uint256 _offerA, uint256 _offerB) public returns (int256, int256) {
        return rebalanceAndFill(_offerA, _offerB, type(uint256).max);
    }

    /**
     * @notice Rebalances ticks using internal values first, then with externally provided assets.
     * Ticks are balanced internally using the price at the specific tick (either stored in tick, or interpolated).
     * Leftover assets are sold using current price to fill as much of the offer as possible.
     * @param _offerA The amount of asset A that is offered for sale to the bridge
     * @param _offerB The amount of asset B that is offered for sale to the bridge
     * @param _upperTick The upper limit for ticks (useful gas-capped rebalancing)
     * @return flowA The flow of asset A from the bridge POV, e.g., >0 = buying of tokens, <0 = selling tokens
     * @return flowB The flow of asset B from the bridge POV, e.g., >0 = buying of tokens, <0 = selling tokens
     */
    function rebalanceAndFill(
        uint256 _offerA,
        uint256 _offerB,
        uint256 _upperTick
    ) public returns (int256, int256) {
        (int256 flowA, int256 flowB, , ) = _rebalanceAndFill(_offerA, _offerB, getPrice(), _upperTick, false);
        if (flowA > 0) {
            ASSET_A.safeTransferFrom(msg.sender, address(this), uint256(flowA));
        } else if (flowA < 0) {
            ASSET_A.safeTransfer(msg.sender, uint256(-flowA));
        }

        if (flowB > 0) {
            ASSET_B.safeTransferFrom(msg.sender, address(this), uint256(flowB));
        } else if (flowB < 0) {
            ASSET_B.safeTransfer(msg.sender, uint256(-flowB));
        }

        return (flowA, flowB);
    }

    /**
     * @notice Function to create DCA position from `_inputAssetA` to `_outputAssetA` over `_ticks` ticks.
     * @param _inputAssetA The asset to be sold
     * @param _outputAssetA The asset to be bought
     * @param _inputValue The value of `_inputAssetA` to be sold
     * @param _interactionNonce The unique identifier for the interaction, used to identify the DCA position
     * @param _numTicks The auxdata, passing the number of ticks the position should run
     * @return Will always return 0 assets, and isAsync = true.
     */
    function convert(
        AztecTypes.AztecAsset calldata _inputAssetA,
        AztecTypes.AztecAsset calldata,
        AztecTypes.AztecAsset calldata _outputAssetA,
        AztecTypes.AztecAsset calldata,
        uint256 _inputValue,
        uint256 _interactionNonce,
        uint64 _numTicks,
        address
    )
        external
        payable
        override(BridgeBase)
        onlyRollup
        returns (
            uint256,
            uint256,
            bool
        )
    {
        address inputAssetAddress = _inputAssetA.erc20Address;
        address outputAssetAddress = _outputAssetA.erc20Address;

        if (_inputAssetA.assetType == AztecTypes.AztecAssetType.ETH) {
            WETH.deposit{value: _inputValue}();
            inputAssetAddress = address(WETH);
        }
        if (_outputAssetA.assetType == AztecTypes.AztecAssetType.ETH) {
            outputAssetAddress = address(WETH);
        }

        if (inputAssetAddress != address(ASSET_A) && inputAssetAddress != address(ASSET_B)) {
            revert ErrorLib.InvalidInputA();
        }
        bool aToB = inputAssetAddress == address(ASSET_A);

        if (outputAssetAddress != (aToB ? address(ASSET_B) : address(ASSET_A))) {
            revert ErrorLib.InvalidOutputA();
        }
        if (dcas[_interactionNonce].start != 0) {
            revert PositionAlreadyExists();
        }

        _deposit(_interactionNonce, _inputValue, _numTicks, aToB);
        return (0, 0, true);
    }

    /**
     * @notice Function used to close a completed DCA position
     * @param _outputAssetA The asset bought with the DCA position
     * @param _interactionNonce The identifier for the DCA position
     * @return outputValueA The amount of assets bought
     * @return interactionComplete True if the interaction is completed and can be executed, false otherwise
     */
    function finalise(
        AztecTypes.AztecAsset calldata,
        AztecTypes.AztecAsset calldata,
        AztecTypes.AztecAsset calldata _outputAssetA,
        AztecTypes.AztecAsset calldata,
        uint256 _interactionNonce,
        uint64
    )
        external
        payable
        virtual
        override(BridgeBase)
        onlyRollup
        returns (
            uint256 outputValueA,
            uint256,
            bool interactionComplete
        )
    {
        uint256 accumulated;
        (accumulated, interactionComplete) = getAccumulated(_interactionNonce);

        if (interactionComplete) {
            bool toEth;

            address outputAssetAddress = _outputAssetA.erc20Address;
            if (_outputAssetA.assetType == AztecTypes.AztecAssetType.ETH) {
                toEth = true;
                outputAssetAddress = address(WETH);
            }

            if (outputAssetAddress != (dcas[_interactionNonce].aToB ? address(ASSET_B) : address(ASSET_A))) {
                revert ErrorLib.InvalidOutputA();
            }

            uint256 incentive;
            if (FEE > 0) {
                incentive = (accumulated * FEE) / FEE_DIVISOR;
            }

            outputValueA = accumulated - incentive;
            delete dcas[_interactionNonce];

            if (toEth) {
                WETH.withdraw(outputValueA);
                IRollupProcessor(ROLLUP_PROCESSOR).receiveEthFromBridge{value: outputValueA}(_interactionNonce);
            }

            if (incentive > 0) {
                // Cannot use the `msg.sender` as that would simply be the rollup.
                IERC20(outputAssetAddress).safeTransfer(tx.origin, incentive);
            }
        }
    }

    /**
     * @notice The brice of A in B, e.g., 10 would mean 1 A = 10 B
     * @return priceAToB measured with precision 1e18
     */
    function getPrice() public virtual returns (uint256);

    /**
     * @notice Computes the value of `_amount` A tokens in B tokens
     * @param _amount The amount of A tokens
     * @param _priceAToB The price of A tokens in B
     * @param _roundUp Flag to round up, if true rounding up, otherwise rounding down
     */
    function denominateAssetAInB(
        uint256 _amount,
        uint256 _priceAToB,
        bool _roundUp
    ) public pure returns (uint256) {
        if (_roundUp) {
            return (_amount * _priceAToB + 1e18 - 1) / 1e18;
        }
        return (_amount * _priceAToB) / 1e18;
    }

    /**
     * @notice Computes the value of `_amount` A tokens in B tokens
     * @param _amount The amount of A tokens
     * @param _priceAToB The price of A tokens in B
     * @param _roundUp Flag to round up, if true rounding up, otherwise rounding down
     */
    function denominateAssetBInA(
        uint256 _amount,
        uint256 _priceAToB,
        bool _roundUp
    ) public pure returns (uint256) {
        if (_roundUp) {
            return (_amount * 1e18 + _priceAToB - 1) / _priceAToB;
        }
        return (_amount * 1e18) / _priceAToB;
    }

    /**
     * @notice Helper to fetch the tick at `_tick`
     * @param _tick The tick to fetch
     * @return The Tick structure
     */
    function getTick(uint256 _tick) public view returns (Tick memory) {
        return ticks[_tick];
    }

    /**
     * @notice Helper to fetch the DCA at `_nonce`
     * @param _nonce The DCA to fetch
     * @return The DCA structure
     */
    function getDCA(uint256 _nonce) public view returns (DCA memory) {
        return dcas[_nonce];
    }

    /**
     * @notice Helper to compute the amount of available tokens (not taking rebalancing into account)
     * @return availableA Available amount of token A
     * @return availableB Available amount of token B
     */
    function getAvailable() public view returns (uint256 availableA, uint256 availableB) {
        uint256 start = _earliestUsedTick(earliestTickWithAvailableA, earliestTickWithAvailableB);
        uint256 lastTick = block.timestamp / TICK_SIZE;
        for (uint256 i = start; i <= lastTick; i++) {
            availableA += ticks[i].availableA;
            availableB += ticks[i].availableB;
        }
    }

    /**
     * @notice Helper to get the amount of accumulated tokens for a specific DCA (and a flag for finalisation readiness)
     * @param _nonce The DCA to fetch
     * @return accumulated The amount of assets accumulated
     * @return ready A flag that is true if the accumulation has completed, false otherwise
     */
    function getAccumulated(uint256 _nonce) public view returns (uint256 accumulated, bool ready) {
        DCA memory dca = dcas[_nonce];
        uint256 start = dca.start;
        uint256 end = dca.end;
        uint256 tickAmount = dca.amount / (end - start);
        bool aToB = dca.aToB;

        ready = true;

        for (uint256 i = start; i < end; i++) {
            Tick storage tick = ticks[i];
            (uint256 available, uint256 sold, uint256 bought) = aToB
                ? (tick.availableA, tick.aToBSubTick.sold, tick.aToBSubTick.bought)
                : (tick.availableB, tick.bToASubTick.sold, tick.bToASubTick.bought);
            ready = ready && available == 0 && sold > 0;
            accumulated += sold == 0 ? 0 : (bought * tickAmount) / (sold + available);
        }
    }

    /**
     * @notice Computes the next tick
     * @dev    Note that the return value can be the current tick if we are exactly at the threshold
     * @return The next tick
     */
    function _nextTick(uint256 _time) internal view returns (uint256) {
        return ((_time + TICK_SIZE - 1) / TICK_SIZE);
    }

    function _min(uint256 _a, uint256 _b) internal pure returns (uint256) {
        return _a > _b ? _b : _a;
    }

    /**
     * @notice Create a new DCA position starting at next tick and accumulates the available assets to the future ticks.
     * @param _nonce The interaction nonce
     * @param _amount The amount of assets deposited
     * @param _ticks The number of ticks that the position span
     * @param _aToB A flag that is true if input asset is assetA and false otherwise.
     */
    function _deposit(
        uint256 _nonce,
        uint256 _amount,
        uint256 _ticks,
        bool _aToB
    ) internal {
        uint256 nextTick = _nextTick(block.timestamp);
        if (_aToB && earliestTickWithAvailableA == 0) {
            earliestTickWithAvailableA = nextTick.toU32();
        }
        if (!_aToB && earliestTickWithAvailableB == 0) {
            earliestTickWithAvailableB = nextTick.toU32();
        }
        // Update prices of last tick, might be 1 second in the past.
        ticks[nextTick - 1].priceOfAInB = getPrice().toU128();
        ticks[nextTick - 1].priceTime = block.timestamp.toU32();

        uint256 tickAmount = _amount / _ticks;
        for (uint256 i = nextTick; i < nextTick + _ticks; i++) {
            if (_aToB) {
                ticks[i].availableA += tickAmount.toU120();
            } else {
                ticks[i].availableB += tickAmount.toU120();
            }
        }
        dcas[_nonce] = DCA({
            amount: _amount.toU128(),
            start: nextTick.toU32(),
            end: (nextTick + _ticks).toU32(),
            aToB: _aToB
        });
    }

    /**
     * @notice Rebalances ticks using internal values first, then with externally provided assets.
     * Ticks are balanced internally using the price at the specific tick (either stored in tick, or interpolated).
     * Leftover assets are sold using current price to fill as much of the offer as possible.
     * @param _offerA The amount of asset A that is offered for sale to the bridge
     * @param _offerB The amount of asset B that is offered for sale to the bridge
     * @param _currentPrice Current oracle price
     * @param _self A flag that is true if rebalancing with self, e.g., swapping available funds with dex and rebalancing, and false otherwise
     * @param _upperTick A upper limit for the ticks, useful for gas-capped execution
     * @return flowA The flow of asset A from the bridge POV, e.g., >0 = buying of tokens, <0 = selling tokens
     * @return flowB The flow of asset B from the bridge POV, e.g., >0 = buying of tokens, <0 = selling tokens
     * @return availableA The amount of asset A that is available after the rebalancing
     * @return availableB The amount of asset B that is available after the rebalancing
     */
    function _rebalanceAndFill(
        uint256 _offerA,
        uint256 _offerB,
        uint256 _currentPrice,
        uint256 _upperTick,
        bool _self
    )
        internal
        returns (
            int256,
            int256,
            uint256,
            uint256
        )
    {
        RebalanceValues memory vars;
        vars.currentPrice = _currentPrice;

        // Cache and use earliest ticks with available funds
        vars.earliestTickWithAvailableA = earliestTickWithAvailableA;
        vars.earliestTickWithAvailableB = earliestTickWithAvailableB;
        uint256 earliestTick = _earliestUsedTick(vars.earliestTickWithAvailableA, vars.earliestTickWithAvailableB);

        // Cache last used price for use in case we don't have a fresh price.
        vars.lastUsedPrice = ticks[earliestTick].priceOfAInB;
        vars.lastUsedPriceTime = ticks[earliestTick].priceTime;
        if (vars.lastUsedPrice == 0) {
            uint256 lookBack = earliestTick;
            while (vars.lastUsedPrice == 0) {
                lookBack--;
                vars.lastUsedPrice = ticks[lookBack].priceOfAInB;
                vars.lastUsedPriceTime = ticks[lookBack].priceTime;
            }
        }

        // Compute the amount of B that is offered to be bought at current price for A. Round down
        vars.offerAInB = denominateAssetAInB(_offerA, vars.currentPrice, false);
        // Compute the amount of A that is offered to be bought at current price for B. Round down
        vars.offerBInA = denominateAssetBInA(_offerB, vars.currentPrice, false);

        uint256 nextTick = _nextTick(block.timestamp);
        // Update the latest tick, might be 1 second in the past.
        ticks[nextTick - 1].priceOfAInB = vars.currentPrice.toU128();
        ticks[nextTick - 1].priceTime = block.timestamp.toU32();

        for (uint256 i = earliestTick; i < _min(nextTick, _upperTick); i++) {
            // Load a cache
            Tick memory tick = ticks[i];

            _rebalanceTickInternally(vars, tick, i);
            _useAOffer(vars, tick, _self);
            _useBOffer(vars, tick, _self);

            // If no more available and earliest is current tick, increment tick.
            if (tick.availableA == 0 && vars.earliestTickWithAvailableA == i) {
                vars.earliestTickWithAvailableA += 1;
            }
            if (tick.availableB == 0 && vars.earliestTickWithAvailableB == i) {
                vars.earliestTickWithAvailableB += 1;
            }

            // Add the leftover A and B from the tick to total available
            vars.availableA += tick.availableA;
            vars.availableB += tick.availableB;

            // Update the storage
            ticks[i] = tick;
        }

        if (vars.earliestTickWithAvailableA > earliestTickWithAvailableA) {
            earliestTickWithAvailableA = vars.earliestTickWithAvailableA.toU32();
        }
        if (vars.earliestTickWithAvailableB > earliestTickWithAvailableB) {
            earliestTickWithAvailableB = vars.earliestTickWithAvailableB.toU32();
        }

        // Compute flow of tokens, from the POV of this contract, e.g., >0 is inflow, <0 outflow
        int256 flowA = int256(vars.protocolBoughtA) - int256(vars.protocolSoldA);
        int256 flowB = int256(vars.protocolBoughtB) - int256(vars.protocolSoldB);

        return (flowA, flowB, vars.availableA, vars.availableB);
    }

    /**
     * @notice Perform internal rebalancing of a single tick using available balances
     * @dev Heavily uses that internal functions are passing reference to memory structures
     *
     */
    function _rebalanceTickInternally(
        RebalanceValues memory _vars,
        Tick memory _tick,
        uint256 _tickId
    ) internal view {
        // Only perform internal rebalance if we have both assets available, otherwise nothing to rebalance
        if (_tick.availableA > 0 && _tick.availableB > 0) {
            uint256 price = _tick.priceOfAInB;

            // If a price is stored at tick, update the last used price and timestamp. Otherwise interpolate.
            if (price > 0) {
                _vars.lastUsedPrice = price;
                _vars.lastUsedPriceTime = _tick.priceTime;
            } else {
                int256 slope = (int256(_vars.currentPrice) - int256(_vars.lastUsedPrice)) /
                    int256(block.timestamp - _vars.lastUsedPriceTime);
                // lastUsedPriceTime will always be an earlier tick than this.
                uint256 dt = _tickId * TICK_SIZE + TICK_SIZE / 2 - _vars.lastUsedPriceTime;
                int256 _price = int256(_vars.lastUsedPrice) + slope * int256(dt);
                if (_price <= 0) {
                    price = 0;
                } else {
                    price = uint256(_price);
                }
            }

            // To compare we need same basis. Compute value of the available A in base B. Round down
            uint128 availableADenominatedInB = denominateAssetAInB(_tick.availableA, price, false).toU128();

            // If more value in A than B, we can use all available B. Otherwise, use all available A
            if (availableADenominatedInB > _tick.availableB) {
                // The value of all available B in asset A. Round down
                uint128 availableBDenominatedInA = denominateAssetBInA(_tick.availableB, price, false).toU128();

                // Update Asset A
                _tick.aToBSubTick.bought += _tick.availableB;
                _tick.aToBSubTick.sold += availableBDenominatedInA;

                // Update Asset B
                _tick.bToASubTick.bought += availableBDenominatedInA;
                _tick.bToASubTick.sold += _tick.availableB;

                // Update available values
                _tick.availableA -= availableBDenominatedInA.toU120();
                _tick.availableB = 0;
            } else {
                // We got more B than A, fill everything in A and part of B

                // Update Asset B
                _tick.bToASubTick.bought += _tick.availableA;
                _tick.bToASubTick.sold += availableADenominatedInB;

                // Update Asset A
                _tick.aToBSubTick.bought += availableADenominatedInB;
                _tick.aToBSubTick.sold += _tick.availableA;

                // Update available values
                _tick.availableA = 0;
                _tick.availableB -= availableADenominatedInB.toU120();
            }
        }
    }

    /**
     * @notice Fills as much of the A offered as possible
     * @dev Heavily uses that internal functions are passing reference to memory structures
     * @param _self True if buying from "self" false otherwise.
     */
    function _useAOffer(
        RebalanceValues memory _vars,
        Tick memory _tick,
        bool _self
    ) internal pure {
        if (_vars.offerAInB > 0 && _tick.availableB > 0) {
            uint128 amountBSold = _vars.offerAInB.toU128();
            // We cannot buy more than available
            if (_vars.offerAInB > _tick.availableB) {
                amountBSold = _tick.availableB;
            }
            // Underpays actual price if self, otherwise overpay (to not mess rounding)
            uint128 assetAPayment = denominateAssetBInA(amountBSold, _vars.currentPrice, !_self).toU128();

            _tick.availableB -= amountBSold.toU120();
            _tick.bToASubTick.sold += amountBSold;
            _tick.bToASubTick.bought += assetAPayment;

            _vars.offerAInB -= amountBSold;
            _vars.protocolSoldB += amountBSold;
            _vars.protocolBoughtA += assetAPayment;
        }
    }

    /**
     * @notice Fills as much of the A offered as possible
     * @dev Heavily uses that internal functions are passing reference to memory structures
     * @param _self True if buying from "self" false otherwise.
     */
    function _useBOffer(
        RebalanceValues memory _vars,
        Tick memory _tick,
        bool _self
    ) internal pure {
        if (_vars.offerBInA > 0 && _tick.availableA > 0) {
            // Buying Asset A using Asset B
            uint128 amountASold = _vars.offerBInA.toU128();
            if (_vars.offerBInA > _tick.availableA) {
                amountASold = _tick.availableA;
            }
            // Underpays actual price if self, otherwise overpay (to not mess rounding)
            uint128 assetBPayment = denominateAssetAInB(amountASold, _vars.currentPrice, !_self).toU128();

            _tick.availableA -= amountASold.toU120();
            _tick.aToBSubTick.sold += amountASold;
            _tick.aToBSubTick.bought += assetBPayment;

            _vars.offerBInA -= amountASold;
            _vars.protocolSoldA += amountASold;
            _vars.protocolBoughtB += assetBPayment;
        }
    }

    /**
     * @notice Computes the earliest tick where we had available funds
     * @param _earliestTickA The ealiest tick with available A
     * @param _earliestTickB The ealiest tick with available B
     * @return The earliest tick with available assets
     */
    function _earliestUsedTick(uint256 _earliestTickA, uint256 _earliestTickB) internal pure returns (uint256) {
        uint256 start;
        if (_earliestTickA == 0 && _earliestTickB == 0) {
            revert NoDeposits();
        } else if (_earliestTickA * _earliestTickB == 0) {
            // one are zero (the both case is handled explicitly above)
            start = _earliestTickA > _earliestTickB ? _earliestTickA : _earliestTickB;
        } else {
            start = _earliestTickA < _earliestTickB ? _earliestTickA : _earliestTickB;
        }
        return start;
    }
}

File 8 of 16 : 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 9 of 16 : 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 10 of 16 : 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);
}

File 11 of 16 : 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 16 : 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 16 : 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 14 of 16 : SafeCastLib.sol
// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec.
pragma solidity >=0.8.4;

library SafeCastLib {
    function toU128(uint256 _a) internal pure returns (uint128) {
        if (_a > type(uint128).max) {
            revert("Overflow");
        }
        return uint128(_a);
    }

    function toU120(uint256 _a) internal pure returns (uint120) {
        if (_a > type(uint120).max) {
            revert("Overflow");
        }
        return uint120(_a);
    }

    function toU32(uint256 _a) internal pure returns (uint32) {
        if (_a > type(uint32).max) {
            revert("Overflow");
        }
        return uint32(_a);
    }
}

File 15 of 16 : 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 16 of 16 : 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);
}

Settings
{
  "remappings": [
    "@openzeppelin/=node_modules/@openzeppelin/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/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"},{"internalType":"uint256","name":"_tickSize","type":"uint256"},{"internalType":"uint256","name":"_fee","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FeeTooLarge","type":"error"},{"inputs":[],"name":"InvalidCaller","type":"error"},{"inputs":[],"name":"InvalidInputA","type":"error"},{"inputs":[],"name":"InvalidOutputA","type":"error"},{"inputs":[],"name":"MissingImplementation","type":"error"},{"inputs":[],"name":"NegativePrice","type":"error"},{"inputs":[],"name":"NoDeposits","type":"error"},{"inputs":[],"name":"PositionAlreadyExists","type":"error"},{"inputs":[],"name":"ASSET_A","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ASSET_B","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_DIVISOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ORACLE","outputs":[{"internalType":"contract IChainlinkOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLLUP_PROCESSOR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SLIPPAGE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SUBSIDY","outputs":[{"internalType":"contract ISubsidy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TICK_SIZE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNI_ROUTER","outputs":[{"internalType":"contract ISwapRouter","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":"_inputValue","type":"uint256"},{"internalType":"uint256","name":"_interactionNonce","type":"uint256"},{"internalType":"uint64","name":"_numTicks","type":"uint64"},{"internalType":"address","name":"","type":"address"}],"name":"convert","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"dcas","outputs":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint32","name":"start","type":"uint32"},{"internalType":"uint32","name":"end","type":"uint32"},{"internalType":"bool","name":"aToB","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_priceAToB","type":"uint256"},{"internalType":"bool","name":"_roundUp","type":"bool"}],"name":"denominateAssetAInB","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_priceAToB","type":"uint256"},{"internalType":"bool","name":"_roundUp","type":"bool"}],"name":"denominateAssetBInA","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"earliestTickWithAvailableA","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"earliestTickWithAvailableB","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"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":"_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":"_interactionNonce","type":"uint256"},{"internalType":"uint64","name":"","type":"uint64"}],"name":"finalise","outputs":[{"internalType":"uint256","name":"outputValueA","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"interactionComplete","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"getAccumulated","outputs":[{"internalType":"uint256","name":"accumulated","type":"uint256"},{"internalType":"bool","name":"ready","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAvailable","outputs":[{"internalType":"uint256","name":"availableA","type":"uint256"},{"internalType":"uint256","name":"availableB","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"getDCA","outputs":[{"components":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint32","name":"start","type":"uint32"},{"internalType":"uint32","name":"end","type":"uint32"},{"internalType":"bool","name":"aToB","type":"bool"}],"internalType":"struct BiDCABridge.DCA","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tick","type":"uint256"}],"name":"getTick","outputs":[{"components":[{"internalType":"uint120","name":"availableA","type":"uint120"},{"internalType":"uint120","name":"availableB","type":"uint120"},{"internalType":"uint16","name":"poke","type":"uint16"},{"components":[{"internalType":"uint128","name":"sold","type":"uint128"},{"internalType":"uint128","name":"bought","type":"uint128"}],"internalType":"struct BiDCABridge.SubTick","name":"aToBSubTick","type":"tuple"},{"components":[{"internalType":"uint128","name":"sold","type":"uint128"},{"internalType":"uint128","name":"bought","type":"uint128"}],"internalType":"struct BiDCABridge.SubTick","name":"bToASubTick","type":"tuple"},{"internalType":"uint128","name":"priceOfAInB","type":"uint128"},{"internalType":"uint32","name":"priceTime","type":"uint32"}],"internalType":"struct BiDCABridge.Tick","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_numTicks","type":"uint256"}],"name":"pokeNextTicks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_startTick","type":"uint256"},{"internalType":"uint256","name":"_numTicks","type":"uint256"}],"name":"pokeTicks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_offerA","type":"uint256"},{"internalType":"uint256","name":"_offerB","type":"uint256"},{"internalType":"uint256","name":"_upperTick","type":"uint256"}],"name":"rebalanceAndFill","outputs":[{"internalType":"int256","name":"","type":"int256"},{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_offerA","type":"uint256"},{"internalType":"uint256","name":"_offerB","type":"uint256"}],"name":"rebalanceAndFill","outputs":[{"internalType":"int256","name":"","type":"int256"},{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_upperTick","type":"uint256"}],"name":"rebalanceAndFillUniswap","outputs":[{"internalType":"int256","name":"","type":"int256"},{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rebalanceAndFillUniswap","outputs":[{"internalType":"int256","name":"","type":"int256"},{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ticks","outputs":[{"internalType":"uint120","name":"availableA","type":"uint120"},{"internalType":"uint120","name":"availableB","type":"uint120"},{"internalType":"uint16","name":"poke","type":"uint16"},{"components":[{"internalType":"uint128","name":"sold","type":"uint128"},{"internalType":"uint128","name":"bought","type":"uint128"}],"internalType":"struct BiDCABridge.SubTick","name":"aToBSubTick","type":"tuple"},{"components":[{"internalType":"uint128","name":"sold","type":"uint128"},{"internalType":"uint128","name":"bought","type":"uint128"}],"internalType":"struct BiDCABridge.SubTick","name":"bToASubTick","type":"tuple"},{"internalType":"uint128","name":"priceOfAInB","type":"uint128"},{"internalType":"uint32","name":"priceTime","type":"uint32"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

6101206040523480156200001257600080fd5b50604051620049fe380380620049fe833981016040819052620000359162000546565b6001600160a01b038316608052736b175474e89094c44da98b954eedeac495271d0f60a081905273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc260c081905260e084905284919084846200009b848660001962000180602090811b62001e2c17901c565b620000c285600019856001600160a01b03166200018060201b62001e2c179092919060201c565b612710811115620000e657604051637e2df70960e11b815260040160405180910390fd5b6101005250620001349250736b175474e89094c44da98b954eedeac495271d0f915073e592427a0aece92de3edee1f18e0157c05861564905060001962000180602090811b62001e2c17901c565b6200017773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273e592427a0aece92de3edee1f18e0157c0586156460001962000180602090811b62001e2c17901c565b5050506200064f565b801580620001fe5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015620001d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001fc91906200058b565b155b620002765760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084015b60405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b17909152620002ce918591620002d316565b505050565b60006200032f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316620003b160201b62002031179092919060201c565b805190915015620002ce5780806020019051810190620003509190620005a5565b620002ce5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016200026d565b6060620003c28484600085620003cc565b90505b9392505050565b6060824710156200042f5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016200026d565b6001600160a01b0385163b620004885760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016200026d565b600080866001600160a01b03168587604051620004a69190620005fc565b60006040518083038185875af1925050503d8060008114620004e5576040519150601f19603f3d011682016040523d82523d6000602084013e620004ea565b606091505b509092509050620004fd82828662000508565b979650505050505050565b6060831562000519575081620003c5565b8251156200052a5782518084602001fd5b8160405162461bcd60e51b81526004016200026d91906200061a565b6000806000606084860312156200055c57600080fd5b83516001600160a01b03811681146200057457600080fd5b602085015160409095015190969495509392505050565b6000602082840312156200059e57600080fd5b5051919050565b600060208284031215620005b857600080fd5b81518015158114620003c557600080fd5b60005b83811015620005e6578181015183820152602001620005cc565b83811115620005f6576000848401525b50505050565b6000825162000610818460208701620005c9565b9190910192915050565b60208152600082518060208401526200063b816040850160208701620005c9565b601f01601f19169190910160400192915050565b60805160a05160c05160e051610100516142c26200073c600039600081816107050152818161147601526114a201526000818161067001528181611d7701528181612be10152818161317801526131a60152600081816108c701528181610b0b01528181610c110152818161104c015281816110a6015281816113ee015281816117d6015261196801526000818161063c01528181610ab401528181610b9501528181610beb01528181610fa801528181611002015281816113c80152818161173a0152611a040152600081816106a40152818161093a015281816112cf01526115c501526142c26000f3fe6080604052600436106101d15760003560e01c80639e0e5555116100f7578063c57981b511610095578063ee0ab46511610064578063ee0ab4651461088d578063f577279b146108b5578063f8f7e258146108e9578063f9cc06051461090957600080fd5b8063c57981b5146106f3578063c91e083614610727578063dbeacd541461073c578063ed2b85481461076257600080fd5b8063a24f6d91116100d1578063a24f6d911461062a578063abc11cd01461065e578063ae9467b514610692578063be2505ae146106c657600080fd5b80639e0e5555146105d45780639e93ad8e146105f4578063a24b87461461060a57600080fd5b8063422a787f1161016f5780638f88553b1161013e5780638f88553b146104b4578063901f4cd01461058c57806398d5fdca146105ac5780639b07d342146105c157600080fd5b8063422a787f14610343578063534cb30d146103635780636508156e1461046a5780637c26f0641461049257600080fd5b806338013f02116101ab57806338013f02146102675780633a55355b146102b45780633aa0f6d3146102e95780633be44da21461031e57600080fd5b806326c3b515146101dd57806336b4134a14610212578063374a0d961461023557600080fd5b366101d857005b600080fd5b6101f06101eb3660046138a8565b61091e565b6040805193845260208401929092521515908201526060015b60405180910390f35b34801561021e57600080fd5b50610227606481565b604051908152602001610209565b34801561024157600080fd5b506000546102529063ffffffff1681565b60405163ffffffff9091168152602001610209565b34801561027357600080fd5b5061028f73773616e4d11a78f511299002da57a0a94577f1f481565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610209565b3480156102c057600080fd5b506102d46102cf36600461393a565b610d24565b60408051928352901515602083015201610209565b3480156102f557600080fd5b50610309610304366004613953565b610f64565b60408051928352602083019190915201610209565b34801561032a57600080fd5b5060005461025290640100000000900463ffffffff1681565b34801561034f57600080fd5b5061022761035e36600461398d565b6110d9565b34801561036f57600080fd5b5061045761037e36600461393a565b600160208181526000928352604092839020805484518086018652938201546fffffffffffffffffffffffffffffffff8082168652700100000000000000000000000000000000918290048116868601528651808801909752600284015480821688528290048116948701949094526003909201546effffffffffffffffffffffffffffff808316966f010000000000000000000000000000008404909116957e0100000000000000000000000000000000000000000000000000000000000090930461ffff1694929390928216910463ffffffff1687565b60405161020997969594939291906139c6565b34801561047657600080fd5b5061028f73abc30e831b5cc173a9ed5941714a7845c909e7fa81565b34801561049e57600080fd5b506104b26104ad366004613a74565b61114a565b005b3480156104c057600080fd5b5061054d6104cf36600461393a565b6002602052600090815260409020546fffffffffffffffffffffffffffffffff81169063ffffffff70010000000000000000000000000000000082048116917401000000000000000000000000000000000000000081049091169060ff78010000000000000000000000000000000000000000000000009091041684565b604080516fffffffffffffffffffffffffffffffff95909516855263ffffffff9384166020860152919092169083015215156060820152608001610209565b34801561059857600080fd5b506104b26105a736600461393a565b6111d2565b3480156105b857600080fd5b506102276111e7565b6101f06105cf366004613a96565b6112b3565b3480156105e057600080fd5b506103096105ef366004613a74565b611673565b34801561060057600080fd5b5061022761271081565b34801561061657600080fd5b5061030961062536600461393a565b6116ac565b34801561063657600080fd5b5061028f7f000000000000000000000000000000000000000000000000000000000000000081565b34801561066a57600080fd5b506102277f000000000000000000000000000000000000000000000000000000000000000081565b34801561069e57600080fd5b5061028f7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106d257600080fd5b506106e66106e136600461393a565b611b86565b6040516102099190613b0b565b3480156106ff57600080fd5b506102277f000000000000000000000000000000000000000000000000000000000000000081565b34801561073357600080fd5b50610309611cde565b34801561074857600080fd5b50610227610757366004613bd5565b600095945050505050565b34801561076e57600080fd5b5061083b61077d36600461393a565b60408051608080820183526000808352602080840182905283850182905260609384018290529481526002855283902083519182018452546fffffffffffffffffffffffffffffffff81168252700100000000000000000000000000000000810463ffffffff9081169583019590955274010000000000000000000000000000000000000000810490941692810192909252780100000000000000000000000000000000000000000000000090920460ff1615159181019190915290565b6040805182516fffffffffffffffffffffffffffffffff16815260208084015163ffffffff90811691830191909152838301511691810191909152606091820151151591810191909152608001610209565b34801561089957600080fd5b5061028f73e592427a0aece92de3edee1f18e0157c0586156481565b3480156108c157600080fd5b5061028f7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108f557600080fd5b5061022761090436600461398d565b611d10565b34801561091557600080fd5b50610309611d4b565b600080803373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610991576040517f48f5c3ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006109a360408d0160208e01613c41565b905060006109b760408c0160208d01613c41565b905060018d60400160208101906109ce9190613c8b565b60038111156109df576109df613c5c565b1415610a725773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db08a6040518263ffffffff1660e01b81526004016000604051808303818588803b158015610a4157600080fd5b505af1158015610a55573d6000803e3d6000fd5b505050505073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291505b6001610a8460608d0160408e01613c8b565b6003811115610a9557610a95613c5c565b1415610ab2575073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015610b5a57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15610b91576040517fc582880b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614905080610c0f577f0000000000000000000000000000000000000000000000000000000000000000610c31565b7f00000000000000000000000000000000000000000000000000000000000000005b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610c95576040517f6c98dcaf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600089815260026020526040902054700100000000000000000000000000000000900463ffffffff1615610cf5576040517f6e8de45800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d0b898b8a67ffffffffffffffff1684612040565b5060009d8e9d5060019c509a5050505050505050505050565b6000818152600260209081526040808320815160808101835290546fffffffffffffffffffffffffffffffff8116825263ffffffff700100000000000000000000000000000000820481169483018590527401000000000000000000000000000000000000000082041692820183905260ff780100000000000000000000000000000000000000000000000090910416151560608201528392909183610dca8383613cdb565b8451610de891906fffffffffffffffffffffffffffffffff16613d21565b606085015160019650909150835b83811015610f5957600081815260016020526040812090808085610e7057835460028501546f010000000000000000000000000000009091046effffffffffffffffffffffffffffff16906fffffffffffffffffffffffffffffffff80821691700100000000000000000000000000000000900416610eb6565b835460018501546effffffffffffffffffffffffffffff909116906fffffffffffffffffffffffffffffffff808216917001000000000000000000000000000000009004165b6fffffffffffffffffffffffffffffffff1692506fffffffffffffffffffffffffffffffff1692506effffffffffffffffffffffffffffff1692508a8015610efc575082155b8015610f085750600082115b9a508115610f3357610f1a8383613d35565b610f248883613d4d565b610f2e9190613d21565b610f36565b60005b610f40908d613d35565b9b50505050508080610f5190613d8a565b915050610df6565b505050505050915091565b600080600080610f7f8787610f776111e7565b886000612432565b5050915091506000821315610fd557610fd073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016333085612b23565b611029565b60008212156110295761102933610feb84613dc3565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169190612b87565b60008113156110795761107473ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016333084612b23565b6110cd565b60008112156110cd576110cd3361108f83613dc3565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169190612b87565b90969095509350505050565b6000811561112357670de0b6b3a764000060016110f68587613d4d565b61110890670de0b6b3a7640000613d35565b6111129190613cdb565b61111c9190613d21565b9050611143565b670de0b6b3a76400006111368486613d4d565b6111409190613d21565b90505b9392505050565b815b6111568284613d35565b8110156111cd57600081815260016020526040902080547e01000000000000000000000000000000000000000000000000000000000000900461ffff1690601e61119f83613dfc565b91906101000a81548161ffff021916908361ffff1602179055505080806111c590613d8a565b91505061114c565b505050565b6111e46111de42612bdd565b8261114a565b50565b60008073773616e4d11a78f511299002da57a0a94577f1f473ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611249573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126d9190613e38565b50505091505060008112156112ae576040517f61ca76d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b600080803373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611326576040517f48f5c3ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061133186610d24565b9250905081156116665760008061134e60408b0160208c01613c41565b9050600161136260608c0160408d01613c8b565b600381111561137357611373613c5c565b141561139457506001905073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b6000888152600260205260409020547801000000000000000000000000000000000000000000000000900460ff166113ec577f000000000000000000000000000000000000000000000000000000000000000061140e565b7f00000000000000000000000000000000000000000000000000000000000000005b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611472576040517f6c98dcaf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007f0000000000000000000000000000000000000000000000000000000000000000156114d4576127106114c77f000000000000000000000000000000000000000000000000000000000000000086613d4d565b6114d19190613d21565b90505b6114de8185613cdb565b60008a815260026020526040902080547fffffffffffffff000000000000000000000000000000000000000000000000001690559650821561163b576040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810188905273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290632e1a7d4d90602401600060405180830381600087803b15801561158057600080fd5b505af1158015611594573d6000803e3d6000fd5b50506040517f12a53623000000000000000000000000000000000000000000000000000000008152600481018c90527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1692506312a53623915089906024016000604051808303818588803b15801561162157600080fd5b505af1158015611635573d6000803e3d6000fd5b50505050505b80156116625761166273ffffffffffffffffffffffffffffffffffffffff83163283612b87565b5050505b5096509650969350505050565b6000806116a184847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610f64565b915091509250929050565b60008060006116b96111e7565b90506000806000806116d0600080878b6001612432565b93509350935093506000821180156116e85750600081115b15611706576116fb8282878b6001612432565b929650909450925090505b8115611934576040805160a081019091527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000606090811b821660c08401527d64000000000000000000000000000000000000000000000000000000000060d48401527fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000060d78401527e01f4000000000000000000000000000000000000000000000000000000000060eb8401527f0000000000000000000000000000000000000000000000000000000000000000901b1660ee82015260009073e592427a0aece92de3edee1f18e0157c058615649063c04b8d5990806101028101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152908252306020830152429082015260608101879052608001612710611876606482613cdb565b611882898d60006110d9565b61188c9190613d4d565b6118969190613d21565b8152506040518263ffffffff1660e01b81526004016118b59190613ef2565b6020604051808303816000875af11580156118d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f89190613f58565b905060008361190f83670de0b6b3a7640000613d4d565b6119199190613d21565b905061192a600083838d6001612432565b5091975095505050505b8015611b79576040805160a081019091527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000606090811b821660c08401527e01f4000000000000000000000000000000000000000000000000000000000060d48401527fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000060d78401527d64000000000000000000000000000000000000000000000000000000000060eb8401527f0000000000000000000000000000000000000000000000000000000000000000901b1660ee82015260009073e592427a0aece92de3edee1f18e0157c058615649063c04b8d5990806101028101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152908252306020830152429082015260608101869052608001612710611aa4606482613cdb565b611ab0888d6000611d10565b611aba9190613d4d565b611ac49190613d21565b8152506040518263ffffffff1660e01b8152600401611ae39190613ef2565b6020604051808303816000875af1158015611b02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b269190613f58565b9050600081600181611b4086670de0b6b3a7640000613d4d565b611b4a9190613d35565b611b549190613cdb565b611b5e9190613d21565b9050611b6f826000838d6001612432565b5091975095505050505b5091969095509350505050565b611be36040805160e081018252600080825260208083018290528284018290528351808501855282815280820183905260608401528351808501909452818452830152906080820190815260006020820181905260409091015290565b50600090815260016020818152604092839020835160e08101855281546effffffffffffffffffffffffffffff80821683526f01000000000000000000000000000000820416828501527e01000000000000000000000000000000000000000000000000000000000000900461ffff168186015284518086018652938201546fffffffffffffffffffffffffffffffff808216865270010000000000000000000000000000000091829004811686860152606083019590955285518087019096526002830154808616875281900485169386019390935260808101949094526003015491821660a0840152900463ffffffff1660c082015290565b600080611d0a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6116ac565b50509091565b60008115611d385782600181611d2e87670de0b6b3a7640000613d4d565b6111089190613d35565b8261113685670de0b6b3a7640000613d4d565b6000805481908190611d6e9063ffffffff80821691640100000000900416612c26565b90506000611d9c7f000000000000000000000000000000000000000000000000000000000000000042613d21565b9050815b818111611e2557600081815260016020526040902054611dd1906effffffffffffffffffffffffffffff1686613d35565b600082815260016020526040902054909550611e11906f0100000000000000000000000000000090046effffffffffffffffffffffffffffff1685613d35565b935080611e1d81613d8a565b915050611da0565b5050509091565b801580611ecc57506040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611ea6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eca9190613f58565b155b611f5d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084015b60405180910390fd5b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526111cd9084907f095ea7b300000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612ca3565b60606111408484600085612daf565b600061204b42612bdd565b9050818015612060575060005463ffffffff16155b156120a45761206e81612f45565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff929092169190911790555b811580156120c05750600054640100000000900463ffffffff16155b156120ef576120ce81612f45565b600060046101000a81548163ffffffff021916908363ffffffff1602179055505b6120ff6120fa6111e7565b612fb9565b6001600061210d8285613cdb565b815260200190815260200160002060030160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555061215d42612f45565b6001600061216b8285613cdb565b815260200190815260200160002060030160106101000a81548163ffffffff021916908363ffffffff160217905550600083856121a89190613d21565b9050815b6121b68584613d35565b8110156122c6578315612234576121cc82613035565b600082815260016020526040812080549091906121fb9084906effffffffffffffffffffffffffffff16613f71565b92506101000a8154816effffffffffffffffffffffffffffff02191690836effffffffffffffffffffffffffffff1602179055506122b4565b61223d82613035565b60008281526001602052604090208054600f9061227f9084906f0100000000000000000000000000000090046effffffffffffffffffffffffffffff16613f71565b92506101000a8154816effffffffffffffffffffffffffffff02191690836effffffffffffffffffffffffffffff1602179055505b806122be81613d8a565b9150506121ac565b5060405180608001604052806122db87612fb9565b6fffffffffffffffffffffffffffffffff1681526020016122fb84612f45565b63ffffffff1681526020016123186123138786613d35565b612f45565b63ffffffff908116825294151560209182015260009788526002815260409788902082518154928401519984015160609094015115157801000000000000000000000000000000000000000000000000027fffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffff9488167401000000000000000000000000000000000000000002949094167fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff9a909716700100000000000000000000000000000000027fffffffffffffffffffffffff00000000000000000000000000000000000000009093166fffffffffffffffffffffffffffffffff909116179190911797909716939093179290921790945550505050565b6000806000806124a3604051806101a00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8781526000805463ffffffff8082166020850181905264010000000090920416604084018190526124d49190612c26565b60008181526001602081815260408320600301546fffffffffffffffffffffffffffffffff8116610120880190815293859052919052700100000000000000000000000000000000900463ffffffff16610140850152519091506125a557805b6101208301516125a3578061254881613fa4565b60008181526001602081815260408320600301546fffffffffffffffffffffffffffffffff81166101208a01529284905252700100000000000000000000000000000000900463ffffffff1661014086015291506125349050565b505b6125b58b836000015160006110d9565b606083015281516125c9908b906000611d10565b608083015260006125d942612bdd565b90506125e88360000151612fb9565b600160006125f68285613cdb565b815260200190815260200160002060030160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555061264642612f45565b600160006126548285613cdb565b81526020810191909152604001600020600301805463ffffffff92909216700100000000000000000000000000000000027fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff909216919091179055815b6126bb828b6130b0565b811015612a2a57600081815260016020818152604092839020835160e08101855281546effffffffffffffffffffffffffffff80821683526f01000000000000000000000000000000820416828501527e01000000000000000000000000000000000000000000000000000000000000900461ffff168186015284518086018652938201546fffffffffffffffffffffffffffffffff808216865270010000000000000000000000000000000091829004811686860152606083019590955285518087019096526002830154808616875281900485169386019390935260808101949094526003015491821660a0840152900463ffffffff1660c08201526127c48582846130c5565b6127cf85828c6134bf565b6127da85828c61366c565b80516effffffffffffffffffffffffffffff161580156127fd5750818560200151145b15612819576001856020018181516128159190613d35565b9052505b60208101516effffffffffffffffffffffffffffff1615801561283f5750818560400151145b1561285b576001856040018181516128579190613d35565b9052505b80600001516effffffffffffffffffffffffffffff1685610160018181516128839190613d35565b9052506020810151610180860180516effffffffffffffffffffffffffffff909216916128b1908390613d35565b90525060008281526001602081815260409283902084518154838701519587015161ffff167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6effffffffffffffffffffffffffffff9788166f01000000000000000000000000000000027fffff0000000000000000000000000000000000000000000000000000000000009093169790931696909617171693909317835560608401518051908201516fffffffffffffffffffffffffffffffff9081167001000000000000000000000000000000009081029282169290921793850193909355608085015180519201518316810291831691909117600284015560a08401516003909301805460c09095015163ffffffff169091027fffffffffffffffffffffffff0000000000000000000000000000000000000000909416929091169190911791909117905580612a2281613d8a565b9150506126b1565b50600054602084015163ffffffff9091161015612a8457612a4e8360200151612f45565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff929092169190911790555b600054604084015164010000000090910463ffffffff161015612acf57612aae8360400151612f45565b600060046101000a81548163ffffffff021916908363ffffffff1602179055505b60008360a001518460e00151612ae59190613fd9565b905060008460c00151856101000151612afe9190613fd9565b61016086015161018090960151929f909e50949c50909a509298505050505050505050565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052612b819085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401611faf565b50505050565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526111cd9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611faf565b60007f00000000000000000000000000000000000000000000000000000000000000006001612c0c8285613d35565b612c169190613cdb565b612c209190613d21565b92915050565b60008083158015612c35575082155b15612c6c576040517f1562001c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612c768385613d4d565b612c8e57828411612c87578261111c565b5082611143565b828410612c9b5782611140565b509192915050565b6000612d05826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166120319092919063ffffffff16565b8051909150156111cd5780806020019051810190612d23919061404d565b6111cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401611f54565b606082471015612e41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401611f54565b73ffffffffffffffffffffffffffffffffffffffff85163b612ebf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611f54565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612ee8919061406a565b60006040518083038185875af1925050503d8060008114612f25576040519150601f19603f3d011682016040523d82523d6000602084013e612f2a565b606091505b5091509150612f3a828286613807565b979650505050505050565b600063ffffffff821115612fb5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f4f766572666c6f770000000000000000000000000000000000000000000000006044820152606401611f54565b5090565b60006fffffffffffffffffffffffffffffffff821115612fb5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f4f766572666c6f770000000000000000000000000000000000000000000000006044820152606401611f54565b60006effffffffffffffffffffffffffffff821115612fb5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f4f766572666c6f770000000000000000000000000000000000000000000000006044820152606401611f54565b60008183116130bf5782611143565b50919050565b81516effffffffffffffffffffffffffffff16158015906130fb5750600082602001516effffffffffffffffffffffffffffff16115b156111cd5760a08201516fffffffffffffffffffffffffffffffff16801561313b57610120840181905260c083015163ffffffff16610140850152613218565b60008461014001514261314e9190613cdb565b61012086015186516131609190613fd9565b61316a9190614086565b9050600085610140015160027f00000000000000000000000000000000000000000000000000000000000000006131a19190613d21565b6131cb7f000000000000000000000000000000000000000000000000000000000000000087613d4d565b6131d59190613d35565b6131df9190613cdb565b905060006131ed82846140ee565b8761012001516131fd91906141aa565b9050600081136132105760009350613214565b8093505b5050505b600061323e6120fa85600001516effffffffffffffffffffffffffffff168460006110d9565b905083602001516effffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff1611156133ac5760006132956120fa86602001516effffffffffffffffffffffffffffff16856000611d10565b905084602001516effffffffffffffffffffffffffffff1685606001516020018181516132c2919061421e565b6fffffffffffffffffffffffffffffffff16905250606085015180518291906132ec90839061421e565b6fffffffffffffffffffffffffffffffff169052506080850151602001805182919061331990839061421e565b6fffffffffffffffffffffffffffffffff169052506020850151608086015180516effffffffffffffffffffffffffffff9092169161335990839061421e565b6fffffffffffffffffffffffffffffffff90811690915261337c91508216613035565b8551869061338b908390614249565b6effffffffffffffffffffffffffffff1690525050600060208501526134b8565b83600001516effffffffffffffffffffffffffffff1684608001516020018181516133d7919061421e565b6fffffffffffffffffffffffffffffffff169052506080840151805182919061340190839061421e565b6fffffffffffffffffffffffffffffffff169052506060840151602001805182919061342e90839061421e565b6fffffffffffffffffffffffffffffffff169052508351606085015180516effffffffffffffffffffffffffffff9092169161346b90839061421e565b6fffffffffffffffffffffffffffffffff9081169091526000865261349291508216613035565b846020018181516134a39190614249565b6effffffffffffffffffffffffffffff169052505b5050505050565b600083606001511180156134e85750600082602001516effffffffffffffffffffffffffffff16115b156111cd5760006134fc8460600151612fb9565b905082602001516effffffffffffffffffffffffffffff1684606001511115613537575060208201516effffffffffffffffffffffffffffff165b600061355e6120fa836fffffffffffffffffffffffffffffffff1687600001518615611d10565b905061357b826fffffffffffffffffffffffffffffffff16613035565b8460200181815161358c9190614249565b6effffffffffffffffffffffffffffff16905250608084015180518391906135b590839061421e565b6fffffffffffffffffffffffffffffffff16905250608084015160200180518291906135e290839061421e565b6fffffffffffffffffffffffffffffffff908116909152606087018051918516925090613610908390613cdb565b90525060c0850180516fffffffffffffffffffffffffffffffff84169190613639908390613d35565b90525060e0850180516fffffffffffffffffffffffffffffffff83169190613662908390613d35565b9052505050505050565b60008360800151118015613691575081516effffffffffffffffffffffffffffff1615155b156111cd5760006136a58460800151612fb9565b905082600001516effffffffffffffffffffffffffffff16846080015111156136dd575081516effffffffffffffffffffffffffffff165b60006137046120fa836fffffffffffffffffffffffffffffffff16876000015186156110d9565b9050613721826fffffffffffffffffffffffffffffffff16613035565b84518590613730908390614249565b6effffffffffffffffffffffffffffff169052506060840151805183919061375990839061421e565b6fffffffffffffffffffffffffffffffff169052506060840151602001805182919061378690839061421e565b6fffffffffffffffffffffffffffffffff9081169091526080870180519185169250906137b4908390613cdb565b90525060a0850180516fffffffffffffffffffffffffffffffff841691906137dd908390613d35565b905250610100850180516fffffffffffffffffffffffffffffffff83169190613662908390613d35565b60608315613816575081611143565b8251156138265782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f549190614279565b6000606082840312156130bf57600080fd5b803567ffffffffffffffff811681146112ae57600080fd5b803573ffffffffffffffffffffffffffffffffffffffff811681146112ae57600080fd5b600080600080600080600080610200898b0312156138c557600080fd5b6138cf8a8a61385a565b97506138de8a60608b0161385a565b96506138ed8a60c08b0161385a565b95506138fd8a6101208b0161385a565b945061018089013593506101a0890135925061391c6101c08a0161386c565b915061392b6101e08a01613884565b90509295985092959890939650565b60006020828403121561394c57600080fd5b5035919050565b60008060006060848603121561396857600080fd5b505081359360208301359350604090920135919050565b80151581146111e457600080fd5b6000806000606084860312156139a257600080fd5b833592506020840135915060408401356139bb8161397f565b809150509250925092565b6effffffffffffffffffffffffffffff88811682528716602082015261ffff861660408201526101208101613a1d606083018780516fffffffffffffffffffffffffffffffff908116835260209182015116910152565b84516fffffffffffffffffffffffffffffffff90811660a084015260208601511660c08301526fffffffffffffffffffffffffffffffff841660e083015263ffffffff831661010083015298975050505050505050565b60008060408385031215613a8757600080fd5b50508035926020909101359150565b6000806000806000806101c08789031215613ab057600080fd5b613aba888861385a565b9550613ac9886060890161385a565b9450613ad88860c0890161385a565b9350613ae888610120890161385a565b92506101808701359150613aff6101a0880161386c565b90509295509295509295565b6000610120820190506effffffffffffffffffffffffffffff8084511683528060208501511660208401525061ffff60408401511660408301526060830151613b76606084018280516fffffffffffffffffffffffffffffffff908116835260209182015116910152565b50608083015180516fffffffffffffffffffffffffffffffff90811660a085015260208201511660c08401525060a08301516fffffffffffffffffffffffffffffffff1660e083015260c09092015163ffffffff166101009091015290565b60008060008060006101a08688031215613bee57600080fd5b613bf8878761385a565b9450613c07876060880161385a565b9350613c168760c0880161385a565b9250613c2687610120880161385a565b9150613c35610180870161386c565b90509295509295909350565b600060208284031215613c5357600080fd5b61114382613884565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600060208284031215613c9d57600080fd5b81356004811061114357600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015613ced57613ced613cac565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082613d3057613d30613cf2565b500490565b60008219821115613d4857613d48613cac565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615613d8557613d85613cac565b500290565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415613dbc57613dbc613cac565b5060010190565b60007f8000000000000000000000000000000000000000000000000000000000000000821415613df557613df5613cac565b5060000390565b600061ffff80831681811415613e1457613e14613cac565b6001019392505050565b805169ffffffffffffffffffff811681146112ae57600080fd5b600080600080600060a08688031215613e5057600080fd5b613e5986613e1e565b9450602086015193506040860151925060608601519150613c3560808701613e1e565b60005b83811015613e97578181015183820152602001613e7f565b83811115612b815750506000910152565b60008151808452613ec0816020860160208601613e7c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000825160a06020840152613f0e60c0840182613ea8565b905073ffffffffffffffffffffffffffffffffffffffff60208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b600060208284031215613f6a57600080fd5b5051919050565b60006effffffffffffffffffffffffffffff808316818516808303821115613f9b57613f9b613cac565b01949350505050565b600081613fb357613fb3613cac565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b6000808312837f80000000000000000000000000000000000000000000000000000000000000000183128115161561401357614013613cac565b837f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01831381161561404757614047613cac565b50500390565b60006020828403121561405f57600080fd5b81516111438161397f565b6000825161407c818460208701613e7c565b9190910192915050565b60008261409557614095613cf2565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f8000000000000000000000000000000000000000000000000000000000000000831416156140e9576140e9613cac565b500590565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60008413600084138583048511828216161561412f5761412f613cac565b7f8000000000000000000000000000000000000000000000000000000000000000600087128682058812818416161561416a5761416a613cac565b6000871292508782058712848416161561418657614186613cac565b8785058712818416161561419c5761419c613cac565b505050929093029392505050565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038413811516156141e4576141e4613cac565b827f800000000000000000000000000000000000000000000000000000000000000003841281161561421857614218613cac565b50500190565b60006fffffffffffffffffffffffffffffffff808316818516808303821115613f9b57613f9b613cac565b60006effffffffffffffffffffffffffffff8381169083168181101561427157614271613cac565b039392505050565b6020815260006111436020830184613ea856fea2646970667358221220dadb774879862d74b0e99a5df4951bbca87781aba24dabf096b57c8b2786c66a64736f6c634300080a0033000000000000000000000000ff1f2b4adb9df6fc8eafecdcbf96a2b3516804550000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000000000000000000a

Deployed Bytecode

0x6080604052600436106101d15760003560e01c80639e0e5555116100f7578063c57981b511610095578063ee0ab46511610064578063ee0ab4651461088d578063f577279b146108b5578063f8f7e258146108e9578063f9cc06051461090957600080fd5b8063c57981b5146106f3578063c91e083614610727578063dbeacd541461073c578063ed2b85481461076257600080fd5b8063a24f6d91116100d1578063a24f6d911461062a578063abc11cd01461065e578063ae9467b514610692578063be2505ae146106c657600080fd5b80639e0e5555146105d45780639e93ad8e146105f4578063a24b87461461060a57600080fd5b8063422a787f1161016f5780638f88553b1161013e5780638f88553b146104b4578063901f4cd01461058c57806398d5fdca146105ac5780639b07d342146105c157600080fd5b8063422a787f14610343578063534cb30d146103635780636508156e1461046a5780637c26f0641461049257600080fd5b806338013f02116101ab57806338013f02146102675780633a55355b146102b45780633aa0f6d3146102e95780633be44da21461031e57600080fd5b806326c3b515146101dd57806336b4134a14610212578063374a0d961461023557600080fd5b366101d857005b600080fd5b6101f06101eb3660046138a8565b61091e565b6040805193845260208401929092521515908201526060015b60405180910390f35b34801561021e57600080fd5b50610227606481565b604051908152602001610209565b34801561024157600080fd5b506000546102529063ffffffff1681565b60405163ffffffff9091168152602001610209565b34801561027357600080fd5b5061028f73773616e4d11a78f511299002da57a0a94577f1f481565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610209565b3480156102c057600080fd5b506102d46102cf36600461393a565b610d24565b60408051928352901515602083015201610209565b3480156102f557600080fd5b50610309610304366004613953565b610f64565b60408051928352602083019190915201610209565b34801561032a57600080fd5b5060005461025290640100000000900463ffffffff1681565b34801561034f57600080fd5b5061022761035e36600461398d565b6110d9565b34801561036f57600080fd5b5061045761037e36600461393a565b600160208181526000928352604092839020805484518086018652938201546fffffffffffffffffffffffffffffffff8082168652700100000000000000000000000000000000918290048116868601528651808801909752600284015480821688528290048116948701949094526003909201546effffffffffffffffffffffffffffff808316966f010000000000000000000000000000008404909116957e0100000000000000000000000000000000000000000000000000000000000090930461ffff1694929390928216910463ffffffff1687565b60405161020997969594939291906139c6565b34801561047657600080fd5b5061028f73abc30e831b5cc173a9ed5941714a7845c909e7fa81565b34801561049e57600080fd5b506104b26104ad366004613a74565b61114a565b005b3480156104c057600080fd5b5061054d6104cf36600461393a565b6002602052600090815260409020546fffffffffffffffffffffffffffffffff81169063ffffffff70010000000000000000000000000000000082048116917401000000000000000000000000000000000000000081049091169060ff78010000000000000000000000000000000000000000000000009091041684565b604080516fffffffffffffffffffffffffffffffff95909516855263ffffffff9384166020860152919092169083015215156060820152608001610209565b34801561059857600080fd5b506104b26105a736600461393a565b6111d2565b3480156105b857600080fd5b506102276111e7565b6101f06105cf366004613a96565b6112b3565b3480156105e057600080fd5b506103096105ef366004613a74565b611673565b34801561060057600080fd5b5061022761271081565b34801561061657600080fd5b5061030961062536600461393a565b6116ac565b34801561063657600080fd5b5061028f7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f81565b34801561066a57600080fd5b506102277f000000000000000000000000000000000000000000000000000000000001518081565b34801561069e57600080fd5b5061028f7f000000000000000000000000ff1f2b4adb9df6fc8eafecdcbf96a2b35168045581565b3480156106d257600080fd5b506106e66106e136600461393a565b611b86565b6040516102099190613b0b565b3480156106ff57600080fd5b506102277f000000000000000000000000000000000000000000000000000000000000000a81565b34801561073357600080fd5b50610309611cde565b34801561074857600080fd5b50610227610757366004613bd5565b600095945050505050565b34801561076e57600080fd5b5061083b61077d36600461393a565b60408051608080820183526000808352602080840182905283850182905260609384018290529481526002855283902083519182018452546fffffffffffffffffffffffffffffffff81168252700100000000000000000000000000000000810463ffffffff9081169583019590955274010000000000000000000000000000000000000000810490941692810192909252780100000000000000000000000000000000000000000000000090920460ff1615159181019190915290565b6040805182516fffffffffffffffffffffffffffffffff16815260208084015163ffffffff90811691830191909152838301511691810191909152606091820151151591810191909152608001610209565b34801561089957600080fd5b5061028f73e592427a0aece92de3edee1f18e0157c0586156481565b3480156108c157600080fd5b5061028f7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b3480156108f557600080fd5b5061022761090436600461398d565b611d10565b34801561091557600080fd5b50610309611d4b565b600080803373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ff1f2b4adb9df6fc8eafecdcbf96a2b3516804551614610991576040517f48f5c3ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006109a360408d0160208e01613c41565b905060006109b760408c0160208d01613c41565b905060018d60400160208101906109ce9190613c8b565b60038111156109df576109df613c5c565b1415610a725773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db08a6040518263ffffffff1660e01b81526004016000604051808303818588803b158015610a4157600080fd5b505af1158015610a55573d6000803e3d6000fd5b505050505073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291505b6001610a8460608d0160408e01613c8b565b6003811115610a9557610a95613c5c565b1415610ab2575073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015610b5a57507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15610b91576040517fc582880b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614905080610c0f577f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f610c31565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610c95576040517f6c98dcaf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600089815260026020526040902054700100000000000000000000000000000000900463ffffffff1615610cf5576040517f6e8de45800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d0b898b8a67ffffffffffffffff1684612040565b5060009d8e9d5060019c509a5050505050505050505050565b6000818152600260209081526040808320815160808101835290546fffffffffffffffffffffffffffffffff8116825263ffffffff700100000000000000000000000000000000820481169483018590527401000000000000000000000000000000000000000082041692820183905260ff780100000000000000000000000000000000000000000000000090910416151560608201528392909183610dca8383613cdb565b8451610de891906fffffffffffffffffffffffffffffffff16613d21565b606085015160019650909150835b83811015610f5957600081815260016020526040812090808085610e7057835460028501546f010000000000000000000000000000009091046effffffffffffffffffffffffffffff16906fffffffffffffffffffffffffffffffff80821691700100000000000000000000000000000000900416610eb6565b835460018501546effffffffffffffffffffffffffffff909116906fffffffffffffffffffffffffffffffff808216917001000000000000000000000000000000009004165b6fffffffffffffffffffffffffffffffff1692506fffffffffffffffffffffffffffffffff1692506effffffffffffffffffffffffffffff1692508a8015610efc575082155b8015610f085750600082115b9a508115610f3357610f1a8383613d35565b610f248883613d4d565b610f2e9190613d21565b610f36565b60005b610f40908d613d35565b9b50505050508080610f5190613d8a565b915050610df6565b505050505050915091565b600080600080610f7f8787610f776111e7565b886000612432565b5050915091506000821315610fd557610fd073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f16333085612b23565b611029565b60008212156110295761102933610feb84613dc3565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f169190612b87565b60008113156110795761107473ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216333084612b23565b6110cd565b60008112156110cd576110cd3361108f83613dc3565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2169190612b87565b90969095509350505050565b6000811561112357670de0b6b3a764000060016110f68587613d4d565b61110890670de0b6b3a7640000613d35565b6111129190613cdb565b61111c9190613d21565b9050611143565b670de0b6b3a76400006111368486613d4d565b6111409190613d21565b90505b9392505050565b815b6111568284613d35565b8110156111cd57600081815260016020526040902080547e01000000000000000000000000000000000000000000000000000000000000900461ffff1690601e61119f83613dfc565b91906101000a81548161ffff021916908361ffff1602179055505080806111c590613d8a565b91505061114c565b505050565b6111e46111de42612bdd565b8261114a565b50565b60008073773616e4d11a78f511299002da57a0a94577f1f473ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611249573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126d9190613e38565b50505091505060008112156112ae576040517f61ca76d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b600080803373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ff1f2b4adb9df6fc8eafecdcbf96a2b3516804551614611326576040517f48f5c3ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061133186610d24565b9250905081156116665760008061134e60408b0160208c01613c41565b9050600161136260608c0160408d01613c8b565b600381111561137357611373613c5c565b141561139457506001905073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b6000888152600260205260409020547801000000000000000000000000000000000000000000000000900460ff166113ec577f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f61140e565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611472576040517f6c98dcaf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007f000000000000000000000000000000000000000000000000000000000000000a156114d4576127106114c77f000000000000000000000000000000000000000000000000000000000000000a86613d4d565b6114d19190613d21565b90505b6114de8185613cdb565b60008a815260026020526040902080547fffffffffffffff000000000000000000000000000000000000000000000000001690559650821561163b576040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810188905273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290632e1a7d4d90602401600060405180830381600087803b15801561158057600080fd5b505af1158015611594573d6000803e3d6000fd5b50506040517f12a53623000000000000000000000000000000000000000000000000000000008152600481018c90527f000000000000000000000000ff1f2b4adb9df6fc8eafecdcbf96a2b35168045573ffffffffffffffffffffffffffffffffffffffff1692506312a53623915089906024016000604051808303818588803b15801561162157600080fd5b505af1158015611635573d6000803e3d6000fd5b50505050505b80156116625761166273ffffffffffffffffffffffffffffffffffffffff83163283612b87565b5050505b5096509650969350505050565b6000806116a184847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610f64565b915091509250929050565b60008060006116b96111e7565b90506000806000806116d0600080878b6001612432565b93509350935093506000821180156116e85750600081115b15611706576116fb8282878b6001612432565b929650909450925090505b8115611934576040805160a081019091527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000007f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f606090811b821660c08401527d64000000000000000000000000000000000000000000000000000000000060d48401527fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000060d78401527e01f4000000000000000000000000000000000000000000000000000000000060eb8401527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2901b1660ee82015260009073e592427a0aece92de3edee1f18e0157c058615649063c04b8d5990806101028101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152908252306020830152429082015260608101879052608001612710611876606482613cdb565b611882898d60006110d9565b61188c9190613d4d565b6118969190613d21565b8152506040518263ffffffff1660e01b81526004016118b59190613ef2565b6020604051808303816000875af11580156118d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f89190613f58565b905060008361190f83670de0b6b3a7640000613d4d565b6119199190613d21565b905061192a600083838d6001612432565b5091975095505050505b8015611b79576040805160a081019091527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000007f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2606090811b821660c08401527e01f4000000000000000000000000000000000000000000000000000000000060d48401527fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000060d78401527d64000000000000000000000000000000000000000000000000000000000060eb8401527f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f901b1660ee82015260009073e592427a0aece92de3edee1f18e0157c058615649063c04b8d5990806101028101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152908252306020830152429082015260608101869052608001612710611aa4606482613cdb565b611ab0888d6000611d10565b611aba9190613d4d565b611ac49190613d21565b8152506040518263ffffffff1660e01b8152600401611ae39190613ef2565b6020604051808303816000875af1158015611b02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b269190613f58565b9050600081600181611b4086670de0b6b3a7640000613d4d565b611b4a9190613d35565b611b549190613cdb565b611b5e9190613d21565b9050611b6f826000838d6001612432565b5091975095505050505b5091969095509350505050565b611be36040805160e081018252600080825260208083018290528284018290528351808501855282815280820183905260608401528351808501909452818452830152906080820190815260006020820181905260409091015290565b50600090815260016020818152604092839020835160e08101855281546effffffffffffffffffffffffffffff80821683526f01000000000000000000000000000000820416828501527e01000000000000000000000000000000000000000000000000000000000000900461ffff168186015284518086018652938201546fffffffffffffffffffffffffffffffff808216865270010000000000000000000000000000000091829004811686860152606083019590955285518087019096526002830154808616875281900485169386019390935260808101949094526003015491821660a0840152900463ffffffff1660c082015290565b600080611d0a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6116ac565b50509091565b60008115611d385782600181611d2e87670de0b6b3a7640000613d4d565b6111089190613d35565b8261113685670de0b6b3a7640000613d4d565b6000805481908190611d6e9063ffffffff80821691640100000000900416612c26565b90506000611d9c7f000000000000000000000000000000000000000000000000000000000001518042613d21565b9050815b818111611e2557600081815260016020526040902054611dd1906effffffffffffffffffffffffffffff1686613d35565b600082815260016020526040902054909550611e11906f0100000000000000000000000000000090046effffffffffffffffffffffffffffff1685613d35565b935080611e1d81613d8a565b915050611da0565b5050509091565b801580611ecc57506040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611ea6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eca9190613f58565b155b611f5d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084015b60405180910390fd5b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526111cd9084907f095ea7b300000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612ca3565b60606111408484600085612daf565b600061204b42612bdd565b9050818015612060575060005463ffffffff16155b156120a45761206e81612f45565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff929092169190911790555b811580156120c05750600054640100000000900463ffffffff16155b156120ef576120ce81612f45565b600060046101000a81548163ffffffff021916908363ffffffff1602179055505b6120ff6120fa6111e7565b612fb9565b6001600061210d8285613cdb565b815260200190815260200160002060030160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555061215d42612f45565b6001600061216b8285613cdb565b815260200190815260200160002060030160106101000a81548163ffffffff021916908363ffffffff160217905550600083856121a89190613d21565b9050815b6121b68584613d35565b8110156122c6578315612234576121cc82613035565b600082815260016020526040812080549091906121fb9084906effffffffffffffffffffffffffffff16613f71565b92506101000a8154816effffffffffffffffffffffffffffff02191690836effffffffffffffffffffffffffffff1602179055506122b4565b61223d82613035565b60008281526001602052604090208054600f9061227f9084906f0100000000000000000000000000000090046effffffffffffffffffffffffffffff16613f71565b92506101000a8154816effffffffffffffffffffffffffffff02191690836effffffffffffffffffffffffffffff1602179055505b806122be81613d8a565b9150506121ac565b5060405180608001604052806122db87612fb9565b6fffffffffffffffffffffffffffffffff1681526020016122fb84612f45565b63ffffffff1681526020016123186123138786613d35565b612f45565b63ffffffff908116825294151560209182015260009788526002815260409788902082518154928401519984015160609094015115157801000000000000000000000000000000000000000000000000027fffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffff9488167401000000000000000000000000000000000000000002949094167fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff9a909716700100000000000000000000000000000000027fffffffffffffffffffffffff00000000000000000000000000000000000000009093166fffffffffffffffffffffffffffffffff909116179190911797909716939093179290921790945550505050565b6000806000806124a3604051806101a00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8781526000805463ffffffff8082166020850181905264010000000090920416604084018190526124d49190612c26565b60008181526001602081815260408320600301546fffffffffffffffffffffffffffffffff8116610120880190815293859052919052700100000000000000000000000000000000900463ffffffff16610140850152519091506125a557805b6101208301516125a3578061254881613fa4565b60008181526001602081815260408320600301546fffffffffffffffffffffffffffffffff81166101208a01529284905252700100000000000000000000000000000000900463ffffffff1661014086015291506125349050565b505b6125b58b836000015160006110d9565b606083015281516125c9908b906000611d10565b608083015260006125d942612bdd565b90506125e88360000151612fb9565b600160006125f68285613cdb565b815260200190815260200160002060030160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555061264642612f45565b600160006126548285613cdb565b81526020810191909152604001600020600301805463ffffffff92909216700100000000000000000000000000000000027fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff909216919091179055815b6126bb828b6130b0565b811015612a2a57600081815260016020818152604092839020835160e08101855281546effffffffffffffffffffffffffffff80821683526f01000000000000000000000000000000820416828501527e01000000000000000000000000000000000000000000000000000000000000900461ffff168186015284518086018652938201546fffffffffffffffffffffffffffffffff808216865270010000000000000000000000000000000091829004811686860152606083019590955285518087019096526002830154808616875281900485169386019390935260808101949094526003015491821660a0840152900463ffffffff1660c08201526127c48582846130c5565b6127cf85828c6134bf565b6127da85828c61366c565b80516effffffffffffffffffffffffffffff161580156127fd5750818560200151145b15612819576001856020018181516128159190613d35565b9052505b60208101516effffffffffffffffffffffffffffff1615801561283f5750818560400151145b1561285b576001856040018181516128579190613d35565b9052505b80600001516effffffffffffffffffffffffffffff1685610160018181516128839190613d35565b9052506020810151610180860180516effffffffffffffffffffffffffffff909216916128b1908390613d35565b90525060008281526001602081815260409283902084518154838701519587015161ffff167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6effffffffffffffffffffffffffffff9788166f01000000000000000000000000000000027fffff0000000000000000000000000000000000000000000000000000000000009093169790931696909617171693909317835560608401518051908201516fffffffffffffffffffffffffffffffff9081167001000000000000000000000000000000009081029282169290921793850193909355608085015180519201518316810291831691909117600284015560a08401516003909301805460c09095015163ffffffff169091027fffffffffffffffffffffffff0000000000000000000000000000000000000000909416929091169190911791909117905580612a2281613d8a565b9150506126b1565b50600054602084015163ffffffff9091161015612a8457612a4e8360200151612f45565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff929092169190911790555b600054604084015164010000000090910463ffffffff161015612acf57612aae8360400151612f45565b600060046101000a81548163ffffffff021916908363ffffffff1602179055505b60008360a001518460e00151612ae59190613fd9565b905060008460c00151856101000151612afe9190613fd9565b61016086015161018090960151929f909e50949c50909a509298505050505050505050565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052612b819085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401611faf565b50505050565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526111cd9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611faf565b60007f00000000000000000000000000000000000000000000000000000000000151806001612c0c8285613d35565b612c169190613cdb565b612c209190613d21565b92915050565b60008083158015612c35575082155b15612c6c576040517f1562001c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612c768385613d4d565b612c8e57828411612c87578261111c565b5082611143565b828410612c9b5782611140565b509192915050565b6000612d05826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166120319092919063ffffffff16565b8051909150156111cd5780806020019051810190612d23919061404d565b6111cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401611f54565b606082471015612e41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401611f54565b73ffffffffffffffffffffffffffffffffffffffff85163b612ebf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611f54565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612ee8919061406a565b60006040518083038185875af1925050503d8060008114612f25576040519150601f19603f3d011682016040523d82523d6000602084013e612f2a565b606091505b5091509150612f3a828286613807565b979650505050505050565b600063ffffffff821115612fb5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f4f766572666c6f770000000000000000000000000000000000000000000000006044820152606401611f54565b5090565b60006fffffffffffffffffffffffffffffffff821115612fb5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f4f766572666c6f770000000000000000000000000000000000000000000000006044820152606401611f54565b60006effffffffffffffffffffffffffffff821115612fb5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f4f766572666c6f770000000000000000000000000000000000000000000000006044820152606401611f54565b60008183116130bf5782611143565b50919050565b81516effffffffffffffffffffffffffffff16158015906130fb5750600082602001516effffffffffffffffffffffffffffff16115b156111cd5760a08201516fffffffffffffffffffffffffffffffff16801561313b57610120840181905260c083015163ffffffff16610140850152613218565b60008461014001514261314e9190613cdb565b61012086015186516131609190613fd9565b61316a9190614086565b9050600085610140015160027f00000000000000000000000000000000000000000000000000000000000151806131a19190613d21565b6131cb7f000000000000000000000000000000000000000000000000000000000001518087613d4d565b6131d59190613d35565b6131df9190613cdb565b905060006131ed82846140ee565b8761012001516131fd91906141aa565b9050600081136132105760009350613214565b8093505b5050505b600061323e6120fa85600001516effffffffffffffffffffffffffffff168460006110d9565b905083602001516effffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff1611156133ac5760006132956120fa86602001516effffffffffffffffffffffffffffff16856000611d10565b905084602001516effffffffffffffffffffffffffffff1685606001516020018181516132c2919061421e565b6fffffffffffffffffffffffffffffffff16905250606085015180518291906132ec90839061421e565b6fffffffffffffffffffffffffffffffff169052506080850151602001805182919061331990839061421e565b6fffffffffffffffffffffffffffffffff169052506020850151608086015180516effffffffffffffffffffffffffffff9092169161335990839061421e565b6fffffffffffffffffffffffffffffffff90811690915261337c91508216613035565b8551869061338b908390614249565b6effffffffffffffffffffffffffffff1690525050600060208501526134b8565b83600001516effffffffffffffffffffffffffffff1684608001516020018181516133d7919061421e565b6fffffffffffffffffffffffffffffffff169052506080840151805182919061340190839061421e565b6fffffffffffffffffffffffffffffffff169052506060840151602001805182919061342e90839061421e565b6fffffffffffffffffffffffffffffffff169052508351606085015180516effffffffffffffffffffffffffffff9092169161346b90839061421e565b6fffffffffffffffffffffffffffffffff9081169091526000865261349291508216613035565b846020018181516134a39190614249565b6effffffffffffffffffffffffffffff169052505b5050505050565b600083606001511180156134e85750600082602001516effffffffffffffffffffffffffffff16115b156111cd5760006134fc8460600151612fb9565b905082602001516effffffffffffffffffffffffffffff1684606001511115613537575060208201516effffffffffffffffffffffffffffff165b600061355e6120fa836fffffffffffffffffffffffffffffffff1687600001518615611d10565b905061357b826fffffffffffffffffffffffffffffffff16613035565b8460200181815161358c9190614249565b6effffffffffffffffffffffffffffff16905250608084015180518391906135b590839061421e565b6fffffffffffffffffffffffffffffffff16905250608084015160200180518291906135e290839061421e565b6fffffffffffffffffffffffffffffffff908116909152606087018051918516925090613610908390613cdb565b90525060c0850180516fffffffffffffffffffffffffffffffff84169190613639908390613d35565b90525060e0850180516fffffffffffffffffffffffffffffffff83169190613662908390613d35565b9052505050505050565b60008360800151118015613691575081516effffffffffffffffffffffffffffff1615155b156111cd5760006136a58460800151612fb9565b905082600001516effffffffffffffffffffffffffffff16846080015111156136dd575081516effffffffffffffffffffffffffffff165b60006137046120fa836fffffffffffffffffffffffffffffffff16876000015186156110d9565b9050613721826fffffffffffffffffffffffffffffffff16613035565b84518590613730908390614249565b6effffffffffffffffffffffffffffff169052506060840151805183919061375990839061421e565b6fffffffffffffffffffffffffffffffff169052506060840151602001805182919061378690839061421e565b6fffffffffffffffffffffffffffffffff9081169091526080870180519185169250906137b4908390613cdb565b90525060a0850180516fffffffffffffffffffffffffffffffff841691906137dd908390613d35565b905250610100850180516fffffffffffffffffffffffffffffffff83169190613662908390613d35565b60608315613816575081611143565b8251156138265782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f549190614279565b6000606082840312156130bf57600080fd5b803567ffffffffffffffff811681146112ae57600080fd5b803573ffffffffffffffffffffffffffffffffffffffff811681146112ae57600080fd5b600080600080600080600080610200898b0312156138c557600080fd5b6138cf8a8a61385a565b97506138de8a60608b0161385a565b96506138ed8a60c08b0161385a565b95506138fd8a6101208b0161385a565b945061018089013593506101a0890135925061391c6101c08a0161386c565b915061392b6101e08a01613884565b90509295985092959890939650565b60006020828403121561394c57600080fd5b5035919050565b60008060006060848603121561396857600080fd5b505081359360208301359350604090920135919050565b80151581146111e457600080fd5b6000806000606084860312156139a257600080fd5b833592506020840135915060408401356139bb8161397f565b809150509250925092565b6effffffffffffffffffffffffffffff88811682528716602082015261ffff861660408201526101208101613a1d606083018780516fffffffffffffffffffffffffffffffff908116835260209182015116910152565b84516fffffffffffffffffffffffffffffffff90811660a084015260208601511660c08301526fffffffffffffffffffffffffffffffff841660e083015263ffffffff831661010083015298975050505050505050565b60008060408385031215613a8757600080fd5b50508035926020909101359150565b6000806000806000806101c08789031215613ab057600080fd5b613aba888861385a565b9550613ac9886060890161385a565b9450613ad88860c0890161385a565b9350613ae888610120890161385a565b92506101808701359150613aff6101a0880161386c565b90509295509295509295565b6000610120820190506effffffffffffffffffffffffffffff8084511683528060208501511660208401525061ffff60408401511660408301526060830151613b76606084018280516fffffffffffffffffffffffffffffffff908116835260209182015116910152565b50608083015180516fffffffffffffffffffffffffffffffff90811660a085015260208201511660c08401525060a08301516fffffffffffffffffffffffffffffffff1660e083015260c09092015163ffffffff166101009091015290565b60008060008060006101a08688031215613bee57600080fd5b613bf8878761385a565b9450613c07876060880161385a565b9350613c168760c0880161385a565b9250613c2687610120880161385a565b9150613c35610180870161386c565b90509295509295909350565b600060208284031215613c5357600080fd5b61114382613884565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600060208284031215613c9d57600080fd5b81356004811061114357600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015613ced57613ced613cac565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082613d3057613d30613cf2565b500490565b60008219821115613d4857613d48613cac565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615613d8557613d85613cac565b500290565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415613dbc57613dbc613cac565b5060010190565b60007f8000000000000000000000000000000000000000000000000000000000000000821415613df557613df5613cac565b5060000390565b600061ffff80831681811415613e1457613e14613cac565b6001019392505050565b805169ffffffffffffffffffff811681146112ae57600080fd5b600080600080600060a08688031215613e5057600080fd5b613e5986613e1e565b9450602086015193506040860151925060608601519150613c3560808701613e1e565b60005b83811015613e97578181015183820152602001613e7f565b83811115612b815750506000910152565b60008151808452613ec0816020860160208601613e7c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000825160a06020840152613f0e60c0840182613ea8565b905073ffffffffffffffffffffffffffffffffffffffff60208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b600060208284031215613f6a57600080fd5b5051919050565b60006effffffffffffffffffffffffffffff808316818516808303821115613f9b57613f9b613cac565b01949350505050565b600081613fb357613fb3613cac565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b6000808312837f80000000000000000000000000000000000000000000000000000000000000000183128115161561401357614013613cac565b837f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01831381161561404757614047613cac565b50500390565b60006020828403121561405f57600080fd5b81516111438161397f565b6000825161407c818460208701613e7c565b9190910192915050565b60008261409557614095613cf2565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f8000000000000000000000000000000000000000000000000000000000000000831416156140e9576140e9613cac565b500590565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60008413600084138583048511828216161561412f5761412f613cac565b7f8000000000000000000000000000000000000000000000000000000000000000600087128682058812818416161561416a5761416a613cac565b6000871292508782058712848416161561418657614186613cac565b8785058712818416161561419c5761419c613cac565b505050929093029392505050565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038413811516156141e4576141e4613cac565b827f800000000000000000000000000000000000000000000000000000000000000003841281161561421857614218613cac565b50500190565b60006fffffffffffffffffffffffffffffffff808316818516808303821115613f9b57613f9b613cac565b60006effffffffffffffffffffffffffffff8381169083168181101561427157614271613cac565b039392505050565b6020815260006111436020830184613ea856fea2646970667358221220dadb774879862d74b0e99a5df4951bbca87781aba24dabf096b57c8b2786c66a64736f6c634300080a0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000ff1f2b4adb9df6fc8eafecdcbf96a2b3516804550000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000000000000000000a

-----Decoded View---------------
Arg [0] : _rollupProcessor (address): 0xFF1F2B4ADb9dF6FC8eAFecDcbF96A2B351680455
Arg [1] : _tickSize (uint256): 86400
Arg [2] : _fee (uint256): 10

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000ff1f2b4adb9df6fc8eafecdcbf96a2b351680455
Arg [1] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [2] : 000000000000000000000000000000000000000000000000000000000000000a


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  ]
[ 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.