ETH Price: $3,204.53 (+0.85%)

Contract

0x8430Be7B8fd28Cc58EA70A25C9c7A624F26f5D09
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
RollupProcessorV2

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 2000 runs

Other Settings:
default evmVersion
File 1 of 20 : RollupProcessorV2.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 {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

import {IVerifier} from "../interfaces/IVerifier.sol";
import {IRollupProcessorV2, IRollupProcessor} from "rollup-encoder/interfaces/IRollupProcessorV2.sol";
import {IDefiBridge} from "../interfaces/IDefiBridge.sol";

import {Decoder} from "../Decoder.sol";
import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol";

import {TokenTransfers} from "../libraries/TokenTransfers.sol";
import {RollupProcessorLibrary} from "rollup-encoder/libraries/RollupProcessorLibrary.sol";
import {SafeCast} from "../libraries/SafeCast.sol";

/**
 * @title Rollup Processor
 * @dev Smart contract responsible for processing Aztec zkRollups, relaying them to a verifier
 *      contract for validation and performing all the relevant ERC20 token transfers
 */
contract RollupProcessorV2 is IRollupProcessorV2, Decoder, Initializable, AccessControl {
    using SafeCast for uint256;
    /*----------------------------------------
      ERROR TAGS
      ----------------------------------------*/

    error PAUSED();
    error NOT_PAUSED();
    error LOCKED_NO_REENTER();
    error INVALID_PROVIDER();
    error THIRD_PARTY_CONTRACTS_FLAG_NOT_SET();
    error INSUFFICIENT_DEPOSIT();
    error INVALID_ADDRESS_NO_CODE();
    error INVALID_ASSET_GAS();
    error INVALID_ASSET_ID();
    error INVALID_ASSET_ADDRESS();
    error INVALID_BRIDGE_GAS();
    error INVALID_BRIDGE_CALL_DATA();
    error INVALID_BRIDGE_ADDRESS();
    error INVALID_ESCAPE_BOUNDS();
    error INCONSISTENT_BRIDGE_CALL_DATA();
    error BRIDGE_WITH_IDENTICAL_INPUT_ASSETS(uint256 inputAssetId);
    error BRIDGE_WITH_IDENTICAL_OUTPUT_ASSETS(uint256 outputAssetId);
    error ZERO_TOTAL_INPUT_VALUE();
    error ARRAY_OVERFLOW();
    error MSG_VALUE_WRONG_AMOUNT();
    error INSUFFICIENT_ETH_PAYMENT();
    error WITHDRAW_TO_ZERO_ADDRESS();
    error DEPOSIT_TOKENS_WRONG_PAYMENT_TYPE();
    error INSUFFICIENT_TOKEN_APPROVAL();
    error NONZERO_OUTPUT_VALUE_ON_NOT_USED_ASSET(uint256 outputValue);
    error INCORRECT_STATE_HASH(bytes32 oldStateHash, bytes32 newStateHash);
    error INCORRECT_DATA_START_INDEX(uint256 providedIndex, uint256 expectedIndex);
    error INCORRECT_PREVIOUS_DEFI_INTERACTION_HASH(
        bytes32 providedDefiInteractionHash, bytes32 expectedDefiInteractionHash
    );
    error PUBLIC_INPUTS_HASH_VERIFICATION_FAILED(uint256, uint256);
    error PROOF_VERIFICATION_FAILED();
    error PENDING_CAP_SURPASSED();
    error DAILY_CAP_SURPASSED();

    /*----------------------------------------
      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 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 AllowThirdPartyContractsUpdated(bool allowed);
    event DefiBridgeProxyUpdated(address defiBridgeProxy);
    event Paused(address account);
    event Unpaused(address account);
    event DelayBeforeEscapeHatchUpdated(uint32 delay);
    event AssetCapUpdated(uint256 assetId, uint256 pendingCap, uint256 dailyCap);
    event CappedUpdated(bool isCapped);

    /*----------------------------------------
      STRUCTS
      ----------------------------------------*/

    // @dev ALLOW_ASYNC_REENTER lock is present to allow calling of `processAsyncDefiInteraction(...)` from within
    //      bridge's `convert(...)` method.
    enum Lock {
        UNLOCKED,
        ALLOW_ASYNC_REENTER,
        LOCKED
    }

    /**
     * @dev RollupState struct contains the following data:
     *
     * | bit offset   | num bits    | description |
     * | ---          | ---         | ---         |
     * | 0            | 160         | PLONK verifier contract address |
     * | 160          | 32          | datasize: number of filled entries in note tree |
     * | 192          | 16          | asyncDefiInteractionHashes.length : number of entries in asyncDefiInteractionHashes array |
     * | 208          | 16          | defiInteractionHashes.length : number of entries in defiInteractionHashes array |
     * | 224          | 8           | Lock enum used to guard against reentrancy attacks (minimum value to store in is uint8)
     * | 232          | 8           | pause flag, true if contract is paused, false otherwise
     * | 240          | 8           | capped flag, true if assets should check cap, false otherwise
     *
     * Note: (RollupState struct gets packed to 1 storage slot -> bit offset signifies location withing the 256 bit string)
     */
    struct RollupState {
        IVerifier verifier;
        uint32 datasize;
        uint16 numAsyncDefiInteractionHashes;
        uint16 numDefiInteractionHashes;
        Lock lock;
        bool paused;
        bool capped;
    }

    /**
     * @dev Contains information that describes a specific call to a bridge
     */
    struct FullBridgeCallData {
        uint256 bridgeAddressId;
        address bridgeAddress;
        uint256 inputAssetIdA;
        uint256 inputAssetIdB;
        uint256 outputAssetIdA;
        uint256 outputAssetIdB;
        uint256 auxData;
        bool firstInputVirtual;
        bool secondInputVirtual;
        bool firstOutputVirtual;
        bool secondOutputVirtual;
        bool secondInputInUse;
        bool secondOutputInUse;
        uint256 bridgeGasLimit;
    }

    /**
     * @dev Represents an asynchronous DeFi bridge interaction that has not been resolved
     * @param encodedBridgeCallData bit-string encoded bridge call data
     * @param totalInputValue number of tokens/wei sent to the bridge
     */
    struct PendingDefiBridgeInteraction {
        uint256 encodedBridgeCallData;
        uint256 totalInputValue;
    }

    /**
     * @dev Container for the results of a DeFi interaction
     * @param outputValueA amount of output asset A returned from the interaction
     * @param outputValueB amount of output asset B returned from the interaction (0 if asset B unused)
     * @param isAsync true if the interaction is asynchronous, false otherwise
     * @param success true if the call succeeded, false otherwise
     */
    struct BridgeResult {
        uint256 outputValueA;
        uint256 outputValueB;
        bool isAsync;
        bool success;
    }

    /**
     * @dev Container for the inputs of a DeFi interaction
     * @param totalInputValue number of tokens/wei sent to the bridge
     * @param interactionNonce the unique id of the interaction
     * @param auxData additional input specific to the type of interaction
     */
    struct InteractionInputs {
        uint256 totalInputValue;
        uint256 interactionNonce;
        uint64 auxData;
    }

    /**
     * @dev Container for asset cap restrictions
     * @dev Caps used to limit usefulness of using Aztec to "wash" larger hacks
     * @param available The amount of tokens that can be deposited, bounded by `dailyCap * 10 ** decimals`.
     * @param lastUpdatedTimestamp The timestamp of the last deposit with caps activated
     * @param pendingCap The cap for each individual pending deposit measured in whole tokens
     * @param dailyCap The cap for total amount that can be added to `available` in 24 hours, measured in whole tokens
     * @param precision The number of decimals in the precision for specific asset.
     */
    struct AssetCap {
        uint128 available;
        uint32 lastUpdatedTimestamp;
        uint32 pendingCap;
        uint32 dailyCap;
        uint8 precision;
    }

    /*----------------------------------------
      FUNCTION SELECTORS (PRECOMPUTED)
      ----------------------------------------*/
    // DEFI_BRIDGE_PROXY_CONVERT_SELECTOR = function signature of:
    //   function convert(
    //       address,
    //       AztecTypes.AztecAsset memory inputAssetA,
    //       AztecTypes.AztecAsset memory inputAssetB,
    //       AztecTypes.AztecAsset memory outputAssetA,
    //       AztecTypes.AztecAsset memory outputAssetB,
    //       uint256 totalInputValue,
    //       uint256 interactionNonce,
    //       uint256 auxData,
    //       uint256 ethPaymentsSlot
    //       address rollupBeneficary)
    // N.B. this is the selector of the 'convert' function of the DefiBridgeProxy contract.
    //      This has a different interface to the IDefiBridge.convert function
    bytes4 private constant DEFI_BRIDGE_PROXY_CONVERT_SELECTOR = 0x4bd947a8;

    bytes4 private constant INVALID_ADDRESS_NO_CODE_SELECTOR = 0x21409272; // bytes4(keccak256('INVALID_ADDRESS_NO_CODE()'));

    bytes4 private constant ARRAY_OVERFLOW_SELECTOR = 0x58a4ab0e; // bytes4(keccak256('ARRAY_OVERFLOW()'));

    /*----------------------------------------
      CONSTANT STATE VARIABLES
      ----------------------------------------*/
    uint256 private constant ETH_ASSET_ID = 0; // if assetId == ETH_ASSET_ID, treat as native ETH and not ERC20 token

    // starting root hash of the DeFi interaction result Merkle tree
    bytes32 private constant INIT_DEFI_ROOT = 0x2e4ab7889ab3139204945f9e722c7a8fdb84e66439d787bd066c3d896dba04ea;

    bytes32 private constant DEFI_BRIDGE_PROCESSED_SIGHASH =
        0x692cf5822a02f5edf084dc7249b3a06293621e069f11975ed70908ed10ed2e2c;

    bytes32 private constant ASYNC_BRIDGE_PROCESSED_SIGHASH =
        0x38ce48f4c2f3454bcf130721f25a4262b2ff2c8e36af937b30edf01ba481eb1d;

    // We need to cap the amount of gas sent to the DeFi bridge contract for two reasons:
    // 1. To provide consistency to rollup providers around costs,
    // 2. to prevent griefing attacks where a bridge consumes all our gas.
    uint256 private constant MIN_BRIDGE_GAS_LIMIT = 35000;
    uint256 private constant MIN_ERC20_GAS_LIMIT = 55000;
    uint256 private constant MAX_BRIDGE_GAS_LIMIT = 5000000;
    uint256 private constant MAX_ERC20_GAS_LIMIT = 1500000;

    // Bit offsets and bit masks used to extract values from `uint256 encodedBridgeCallData` to FullBridgeCallData struct
    uint256 private constant INPUT_ASSET_ID_A_SHIFT = 32;
    uint256 private constant INPUT_ASSET_ID_B_SHIFT = 62;
    uint256 private constant OUTPUT_ASSET_ID_A_SHIFT = 92;
    uint256 private constant OUTPUT_ASSET_ID_B_SHIFT = 122;
    uint256 private constant BITCONFIG_SHIFT = 152;
    uint256 private constant AUX_DATA_SHIFT = 184;
    uint256 private constant VIRTUAL_ASSET_ID_FLAG_SHIFT = 29;
    uint256 private constant VIRTUAL_ASSET_ID_FLAG = 0x2000_0000; // 2 ** 29
    uint256 private constant MASK_THIRTY_TWO_BITS = 0xffff_ffff;
    uint256 private constant MASK_THIRTY_BITS = 0x3fff_ffff;
    uint256 private constant MASK_SIXTY_FOUR_BITS = 0xffff_ffff_ffff_ffff;

    // Offsets and masks used to encode/decode the rollupState storage variable of RollupProcessor
    uint256 private constant DATASIZE_BIT_OFFSET = 160;
    uint256 private constant ASYNCDEFIINTERACTIONHASHES_BIT_OFFSET = 192;
    uint256 private constant DEFIINTERACTIONHASHES_BIT_OFFSET = 208;
    uint256 private constant ARRAY_LENGTH_MASK = 0x3ff; // 1023
    uint256 private constant DATASIZE_MASK = 0xffff_ffff;

    // the value of hashing a 'zeroed' DeFi interaction result
    bytes32 private constant DEFI_RESULT_ZERO_HASH = 0x2d25a1e3a51eb293004c4b56abe12ed0da6bca2b4a21936752a85d102593c1b4;

    // roles used in access control
    bytes32 public constant OWNER_ROLE = keccak256("OWNER_ROLE");
    bytes32 public constant EMERGENCY_ROLE = keccak256("EMERGENCY_ROLE");
    bytes32 public constant LISTER_ROLE = keccak256("LISTER_ROLE");
    bytes32 public constant RESUME_ROLE = keccak256("RESUME_ROLE");

    // bounds used for escape hatch
    uint256 public immutable escapeBlockLowerBound;
    uint256 public immutable escapeBlockUpperBound;

    /*----------------------------------------
      STATE VARIABLES
      ----------------------------------------*/
    RollupState internal rollupState;

    // An array of addresses of supported ERC20 tokens
    address[] internal supportedAssets;

    // An array of addresses of supported bridges
    // @dev `bridgeAddressId` is an index of the bridge's address in this array incremented by 1
    address[] internal supportedBridges;

    // A mapping from index to async interaction hash (emulates an array)
    // @dev next index is stored in `RollupState.numAsyncDefiInteractionHashes`
    mapping(uint256 => bytes32) public asyncDefiInteractionHashes;

    // A mapping from index to interaction hash (emulates an array)
    // @dev next index is stored in the `RollupState.numDefiInteractionHashes`
    mapping(uint256 => bytes32) public defiInteractionHashes;

    // A mapping from assetId to a mapping of userAddress to the user's public pending balance
    mapping(uint256 => mapping(address => uint256)) public userPendingDeposits;

    // A mapping from user's address to a mapping of proof hashes to a boolean which indicates approval
    mapping(address => mapping(bytes32 => bool)) public depositProofApprovals;

    // A hash of the latest rollup state
    bytes32 public override(IRollupProcessor) rollupStateHash;

    // An address of DefiBridgeProxy contract
    address public override(IRollupProcessor) defiBridgeProxy;

    // A flag indicating whether addresses without a LISTER role can list assets and bridges
    // Note: will be set to true once Aztec Connect is no longer in BETA
    bool public allowThirdPartyContracts;

    // A mapping from an address to a boolean which indicates whether address is an approved rollup provider
    // @dev A rollup provider is an address which is allowed to call `processRollup(...)` out of escape hatch window.
    mapping(address => bool) public rollupProviders;

    // A mapping from interactionNonce to PendingDefiBridgeInteraction struct
    mapping(uint256 => PendingDefiBridgeInteraction) public pendingDefiInteractions;

    // A mapping from interactionNonce to ETH amount which was received for that interaction.
    // interaction
    mapping(uint256 => uint256) public ethPayments;

    // A mapping from an `assetId` to a gas limit
    mapping(uint256 => uint256) public assetGasLimits;

    // A mapping from a `bridgeAddressId` to a gas limit
    mapping(uint256 => uint256) public bridgeGasLimits;

    // A hash of hashes of pending DeFi interactions, the notes of which are expected to be added in the 'next' rollup
    bytes32 public override(IRollupProcessor) prevDefiInteractionsHash;

    // The timestamp of the last rollup that was performed by a rollup provider
    uint32 public lastRollupTimeStamp;
    // The delay in seconds from `lastRollupTimeStamp` until the escape hatch can be used.
    uint32 public delayBeforeEscapeHatch;

    mapping(uint256 => AssetCap) public caps;

    /*----------------------------------------
      MODIFIERS
      ----------------------------------------*/
    /**
     * @notice A modifier forbidding functions from being called by addresses without LISTER role when Aztec Connect
     *         is still in BETA (`allowThirdPartyContracts` variable set to false)
     */
    modifier checkThirdPartyContractStatus() {
        if (!hasRole(LISTER_ROLE, msg.sender) && !allowThirdPartyContracts) {
            revert THIRD_PARTY_CONTRACTS_FLAG_NOT_SET();
        }
        _;
    }

    /**
     * @notice A modifier reverting if this contract is paused
     */
    modifier whenNotPaused() {
        if (rollupState.paused) {
            revert PAUSED();
        }
        _;
    }

    /**
     * @notice A modifier reverting if this contract is NOT paused
     */
    modifier whenPaused() {
        if (!rollupState.paused) {
            revert NOT_PAUSED();
        }
        _;
    }

    /**
     * @notice A modifier reverting on any re-enter
     */
    modifier noReenter() {
        if (rollupState.lock != Lock.UNLOCKED) {
            revert LOCKED_NO_REENTER();
        }
        rollupState.lock = Lock.LOCKED;
        _;
        rollupState.lock = Lock.UNLOCKED;
    }

    /**
     * @notice A modifier reverting on any re-enter but allowing async to be called
     */
    modifier allowAsyncReenter() {
        if (rollupState.lock != Lock.UNLOCKED) {
            revert LOCKED_NO_REENTER();
        }
        rollupState.lock = Lock.ALLOW_ASYNC_REENTER;
        _;
        rollupState.lock = Lock.UNLOCKED;
    }

    /**
     * @notice A modifier reverting if re-entering after locking, but passes if unlocked or if async is re-enter is
     *         allowed
     */
    modifier noReenterButAsync() {
        Lock lock = rollupState.lock;
        if (lock == Lock.ALLOW_ASYNC_REENTER) {
            _;
        } else if (lock == Lock.UNLOCKED) {
            rollupState.lock = Lock.ALLOW_ASYNC_REENTER;
            _;
            rollupState.lock = Lock.UNLOCKED;
        } else {
            revert LOCKED_NO_REENTER();
        }
    }

    /**
     * @notice A modifier which reverts if a given `_assetId` represents a virtual asset
     * @param _assetId 30-bit integer that describes the asset
     * @dev If _assetId's 29th bit is set, it represents a virtual asset with no ERC20 equivalent
     *      Virtual assets are used by the bridges to track non-token data. E.g. to represent a loan.
     *      If an _assetId is *not* a virtual asset, its ERC20 address can be recovered from
     *      `supportedAssets[_assetId]`
     */
    modifier validateAssetIdIsNotVirtual(uint256 _assetId) {
        if (_assetId > 0x1fffffff) {
            revert INVALID_ASSET_ID();
        }
        _;
    }

    /*----------------------------------------
      CONSTRUCTORS & INITIALIZERS
      ----------------------------------------*/
    /**
     * @notice Constructor sets escape hatch window and ensure that the implementation cannot be initialized
     * @param _escapeBlockLowerBound a block number which defines a start of the escape hatch window
     * @param _escapeBlockUpperBound a block number which defines an end of the escape hatch window
     */
    constructor(uint256 _escapeBlockLowerBound, uint256 _escapeBlockUpperBound) {
        if (_escapeBlockLowerBound == 0 || _escapeBlockLowerBound >= _escapeBlockUpperBound) {
            revert INVALID_ESCAPE_BOUNDS();
        }

        // Set storage in implementation.
        // Disable initializers to ensure no-one can call initialize on implementation directly
        // Pause to limit possibility for user error
        _disableInitializers();
        rollupState.paused = true;

        // Set immutables (part of code) so will be used in proxy calls as well
        escapeBlockLowerBound = _escapeBlockLowerBound;
        escapeBlockUpperBound = _escapeBlockUpperBound;
    }

    /**
     * @notice Initialiser function which emulates constructor behaviour for upgradeable contracts
     */
    function initialize() external reinitializer(getImplementationVersion()) {
        rollupState.capped = true;
        lastRollupTimeStamp = uint32(block.timestamp);

        // Set Eth asset caps. 6 Eth to cover 5 eth deposits + fee up to 1 eth.
        caps[0] = AssetCap({
            available: uint128(1000e18),
            lastUpdatedTimestamp: uint32(block.timestamp),
            pendingCap: 6,
            dailyCap: 1000,
            precision: 18
        });

        // Set Dai asset cap. 10100 Dai to cover 10K deposits + fee up to 100 dai.
        caps[1] = AssetCap({
            available: uint128(1e24),
            lastUpdatedTimestamp: uint32(block.timestamp),
            pendingCap: 10100,
            dailyCap: 1e6,
            precision: 18
        });

        emit AssetCapUpdated(0, 6, 1000);
        emit AssetCapUpdated(1, 10100, 1e6);
    }

    /*----------------------------------------
      MUTATING FUNCTIONS WITH ACCESS CONTROL 
      ----------------------------------------*/
    /**
     * @notice A function which allow the holders of the EMERGENCY_ROLE role to pause the contract
     */
    function pause() public override (IRollupProcessor) whenNotPaused onlyRole(EMERGENCY_ROLE) noReenter {
        rollupState.paused = true;
        emit Paused(msg.sender);
    }

    /**
     * @dev Allow the holders of the RESUME_ROLE to unpause the contract.
     */
    function unpause() public override (IRollupProcessor) whenPaused onlyRole(RESUME_ROLE) noReenter {
        rollupState.paused = false;
        emit Unpaused(msg.sender);
    }

    /**
     * @notice A function which allows holders of OWNER_ROLE to set the capped flag
     * @dev When going from uncapped to capped, will update `lastRollupTimeStamp`
     * @param _isCapped a flag indicating whether caps are used or not
     */
    function setCapped(bool _isCapped) external onlyRole(OWNER_ROLE) noReenter {
        if (_isCapped == rollupState.capped) return;

        if (_isCapped) {
            lastRollupTimeStamp = uint32(block.timestamp);
        }

        rollupState.capped = _isCapped;
        emit CappedUpdated(_isCapped);
    }

    /**
     * @notice A function which allows holders of OWNER_ROLE to add and remove a rollup provider.
     * @param _provider an address of the rollup provider
     * @param _valid a flag indicating whether `_provider` is valid
     */
    function setRollupProvider(address _provider, bool _valid)
        external
        override (IRollupProcessor)
        onlyRole(OWNER_ROLE)
        noReenter
    {
        rollupProviders[_provider] = _valid;
        emit RollupProviderUpdated(_provider, _valid);
    }

    /**
     * @notice A function which allows holders of the LISTER_ROLE to update asset caps
     * @param _assetId The asset id to update the cap for
     * @param _pendingCap The pending cap in whole tokens
     * @param _dailyCap The daily "accrual" to available deposits in whole tokens
     * @param _precision The precision (decimals) to multiply the caps with
     */
    function setAssetCap(uint256 _assetId, uint32 _pendingCap, uint32 _dailyCap, uint8 _precision)
        external
        onlyRole(LISTER_ROLE)
        noReenter
    {
        caps[_assetId] = AssetCap({
            available: (uint256(_dailyCap) * 10 ** _precision).toU128(),
            lastUpdatedTimestamp: uint32(block.timestamp),
            pendingCap: _pendingCap,
            dailyCap: _dailyCap,
            precision: _precision
        });

        emit AssetCapUpdated(_assetId, _pendingCap, _dailyCap);
    }

    /**
     * @notice A function which allows holders of the OWNER_ROLE to specify the delay before escapehatch is possible
     * @param _delay the delay in seconds between last rollup by a provider, and escape hatch being possible
     */
    function setDelayBeforeEscapeHatch(uint32 _delay) external onlyRole(OWNER_ROLE) noReenter {
        delayBeforeEscapeHatch = _delay;
        emit DelayBeforeEscapeHatchUpdated(_delay);
    }

    /**
     * @notice A function which allows holders of OWNER_ROLE to set the address of the PLONK verification smart
     *  (         contract
     * @param _verifier an address of the verification smart contract
     */
    function setVerifier(address _verifier) public override (IRollupProcessor) onlyRole(OWNER_ROLE) noReenter {
        if (_verifier.code.length == 0) {
            revert INVALID_ADDRESS_NO_CODE();
        }

        rollupState.verifier = IVerifier(_verifier);
        emit VerifierUpdated(_verifier);
    }

    /**
     * @notice A function which allows holders of OWNER_ROLE to set `allowThirdPartyContracts` flag
     * @param _allowThirdPartyContracts A flag indicating true if allowing third parties to register, false otherwise
     */
    function setAllowThirdPartyContracts(bool _allowThirdPartyContracts)
        external
        override (IRollupProcessor)
        onlyRole(OWNER_ROLE)
        noReenter
    {
        allowThirdPartyContracts = _allowThirdPartyContracts;
        emit AllowThirdPartyContractsUpdated(_allowThirdPartyContracts);
    }

    /**
     * @notice A function which allows holders of OWNER_ROLE to set address of `DefiBridgeProxy` contract
     * @param _defiBridgeProxy an address of `DefiBridgeProxy` contract
     */
    function setDefiBridgeProxy(address _defiBridgeProxy)
        public
        override (IRollupProcessor)
        onlyRole(OWNER_ROLE)
        noReenter
    {
        if (_defiBridgeProxy.code.length == 0) {
            revert INVALID_ADDRESS_NO_CODE();
        }
        defiBridgeProxy = _defiBridgeProxy;
        emit DefiBridgeProxyUpdated(_defiBridgeProxy);
    }

    /**
     * @notice Registers an ERC20 token as a supported asset
     * @param _token address of the ERC20 token
     * @param _gasLimit gas limit used when transferring the token (in withdraw or transferFee)
     */
    function setSupportedAsset(address _token, uint256 _gasLimit)
        external
        override (IRollupProcessor)
        whenNotPaused
        checkThirdPartyContractStatus
        noReenter
    {
        if (_token.code.length == 0) {
            revert INVALID_ADDRESS_NO_CODE();
        }
        if (_gasLimit < MIN_ERC20_GAS_LIMIT || _gasLimit > MAX_ERC20_GAS_LIMIT) {
            revert INVALID_ASSET_GAS();
        }

        supportedAssets.push(_token);
        uint256 assetId = supportedAssets.length;
        assetGasLimits[assetId] = _gasLimit;
        emit AssetAdded(assetId, _token, assetGasLimits[assetId]);
    }

    /**
     * @dev Appends a bridge contract to the supportedBridges
     * @param _bridge address of the bridge contract
     * @param _gasLimit gas limit forwarded to the DefiBridgeProxy to perform convert
     */
    function setSupportedBridge(address _bridge, uint256 _gasLimit)
        external
        override (IRollupProcessor)
        whenNotPaused
        checkThirdPartyContractStatus
        noReenter
    {
        if (_bridge.code.length == 0) {
            revert INVALID_ADDRESS_NO_CODE();
        }
        if (_gasLimit < MIN_BRIDGE_GAS_LIMIT || _gasLimit > MAX_BRIDGE_GAS_LIMIT) {
            revert INVALID_BRIDGE_GAS();
        }

        supportedBridges.push(_bridge);
        uint256 bridgeAddressId = supportedBridges.length;
        bridgeGasLimits[bridgeAddressId] = _gasLimit;
        emit BridgeAdded(bridgeAddressId, _bridge, bridgeGasLimits[bridgeAddressId]);
    }

    /**
     * @notice A function which processes a rollup
     * @dev Rollup processing consists of decoding a rollup, verifying the corresponding proof and updating relevant
     *      state variables
     * @dev The `encodedProofData` is unnamed param as we are reading it directly from calldata when decoding
     *      and creating the `proofData` in `Decoder::decodeProof()`.
     * @dev For the rollup to be processed `msg.sender` has to be an authorised rollup provider or escape hatch has
     *      to be open
     * @dev This function always transfers fees to the `rollupBeneficiary` encoded in the proof data
     *
     * @param - cryptographic proof data associated with a rollup
     * @param _signatures a byte array of secp256k1 ECDSA signatures, authorising a transfer of tokens from
     *                    the publicOwner for the particular inner proof in question
     *
     * Structure of each signature in the bytes array is:
     * 0x00 - 0x20 : r
     * 0x20 - 0x40 : s
     * 0x40 - 0x60 : v (in form: 0x0000....0001b for example)
     */
    function processRollup(bytes calldata, /* encodedProofData */ bytes calldata _signatures)
        external
        override (IRollupProcessor)
        whenNotPaused
        allowAsyncReenter
    {
        if (rollupProviders[msg.sender]) {
            if (rollupState.capped) {
                lastRollupTimeStamp = uint32(block.timestamp);
            }
        } else {
            (bool isOpen,) = getEscapeHatchStatus();
            if (!isOpen) {
                revert INVALID_PROVIDER();
            }
        }

        (bytes memory proofData, uint256 numTxs, uint256 publicInputsHash) = decodeProof();
        address rollupBeneficiary = extractRollupBeneficiary(proofData);

        processRollupProof(proofData, _signatures, numTxs, publicInputsHash, rollupBeneficiary);

        transferFee(proofData, rollupBeneficiary);
    }

    /*----------------------------------------
      PUBLIC/EXTERNAL MUTATING FUNCTIONS 
      ----------------------------------------*/

    /**
     * @notice A function used by bridges to send ETH to the RollupProcessor during an interaction
     * @param _interactionNonce an interaction nonce that used as an ID of this payment
     */
    function receiveEthFromBridge(uint256 _interactionNonce) external payable override (IRollupProcessor) {
        assembly {
            // ethPayments[interactionNonce] += msg.value
            mstore(0x00, _interactionNonce)
            mstore(0x20, ethPayments.slot)
            let slot := keccak256(0x00, 0x40)
            // no need to check for overflows as this would require sending more than the blockchain's total supply of ETH!
            sstore(slot, add(sload(slot), callvalue()))
        }
    }

    /**
     * @notice A function which approves a proofHash to spend the user's pending deposited funds
     * @dev this function is one way and must be called by the owner of the funds
     * @param _proofHash keccak256 hash of the inner proof public inputs
     */
    function approveProof(bytes32 _proofHash) public override (IRollupProcessor) whenNotPaused {
        // asm implementation to reduce compiled bytecode size
        assembly {
            // depositProofApprovals[msg.sender][_proofHash] = true;
            mstore(0x00, caller())
            mstore(0x20, depositProofApprovals.slot)
            mstore(0x20, keccak256(0x00, 0x40))
            mstore(0x00, _proofHash)
            sstore(keccak256(0x00, 0x40), 1)
        }
    }

    /**
     * @notice A function which deposits funds to the contract
     * @dev This is the first stage of a 2 stage deposit process. In the second stage funds are claimed by the user on
     *      L2.
     * @param _assetId asset ID which was assigned during asset registration
     * @param _amount token deposit amount
     * @param _owner address that can spend the deposited funds
     * @param _proofHash 32 byte transaction id that can spend the deposited funds
     */
    function depositPendingFunds(uint256 _assetId, uint256 _amount, address _owner, bytes32 _proofHash)
        external
        payable
        override (IRollupProcessor)
        whenNotPaused
        noReenter
    {
        // Perform sanity checks on user input
        if (_assetId == ETH_ASSET_ID && msg.value != _amount) {
            revert MSG_VALUE_WRONG_AMOUNT();
        }
        if (_assetId != ETH_ASSET_ID && msg.value != 0) {
            revert DEPOSIT_TOKENS_WRONG_PAYMENT_TYPE();
        }

        increasePendingDepositBalance(_assetId, _owner, _amount);

        if (_proofHash != 0) approveProof(_proofHash);

        emit Deposit(_assetId, _owner, _amount);

        if (_assetId != ETH_ASSET_ID) {
            address assetAddress = getSupportedAsset(_assetId);
            // check user approved contract to transfer funds, so can throw helpful error to user
            if (IERC20(assetAddress).allowance(msg.sender, address(this)) < _amount) {
                revert INSUFFICIENT_TOKEN_APPROVAL();
            }
            TokenTransfers.safeTransferFrom(assetAddress, msg.sender, address(this), _amount);
        }
    }

    /**
     * @notice A function used to publish data that doesn't need to be accessible on-chain
     * @dev This function can be called multiple times to work around maximum tx size limits
     * @dev The data is expected to be reconstructed by the client
     * @param _rollupId rollup id this data is related to
     * @param _chunk the chunk number, from 0 to totalChunks-1.
     * @param _totalChunks the total number of chunks.
     * @param - the data
     */
    function offchainData(uint256 _rollupId, uint256 _chunk, uint256 _totalChunks, bytes calldata /* offchainTxData */ )
        external
        override (IRollupProcessor)
        whenNotPaused
    {
        emit OffchainData(_rollupId, _chunk, _totalChunks, msg.sender);
    }

    /**
     * @notice A function which process async bridge interaction
     * @param _interactionNonce unique id of the interaction
     * @return true if successful, false otherwise
     */
    function processAsyncDefiInteraction(uint256 _interactionNonce)
        external
        override (IRollupProcessor)
        whenNotPaused
        noReenterButAsync
        returns (bool)
    {
        uint256 encodedBridgeCallData;
        uint256 totalInputValue;
        assembly {
            mstore(0x00, _interactionNonce)
            mstore(0x20, pendingDefiInteractions.slot)
            let interactionPtr := keccak256(0x00, 0x40)

            encodedBridgeCallData := sload(interactionPtr)
            totalInputValue := sload(add(interactionPtr, 0x01))
        }
        if (encodedBridgeCallData == 0) {
            revert INVALID_BRIDGE_CALL_DATA();
        }
        FullBridgeCallData memory fullBridgeCallData = getFullBridgeCallData(encodedBridgeCallData);

        (
            AztecTypes.AztecAsset memory inputAssetA,
            AztecTypes.AztecAsset memory inputAssetB,
            AztecTypes.AztecAsset memory outputAssetA,
            AztecTypes.AztecAsset memory outputAssetB
        ) = getAztecAssetTypes(fullBridgeCallData, _interactionNonce);

        // Extract the bridge address from the encodedBridgeCallData
        IDefiBridge bridgeContract;
        assembly {
            mstore(0x00, supportedBridges.slot)
            let bridgeSlot := keccak256(0x00, 0x20)

            bridgeContract := and(encodedBridgeCallData, 0xffffffff)
            bridgeContract := sload(add(bridgeSlot, sub(bridgeContract, 0x01)))
            bridgeContract := and(bridgeContract, ADDRESS_MASK)
        }
        if (address(bridgeContract) == address(0)) {
            revert INVALID_BRIDGE_ADDRESS();
        }

        // delete pendingDefiInteractions[interactionNonce]
        // N.B. only need to delete 1st slot value `encodedBridgeCallData`. Deleting vars costs gas post-London
        // setting encodedBridgeCallData to 0 is enough to cause future calls with this interaction nonce to fail
        pendingDefiInteractions[_interactionNonce].encodedBridgeCallData = 0;

        // Copy some variables to front of stack to get around stack too deep errors
        InteractionInputs memory inputs =
            InteractionInputs(totalInputValue, _interactionNonce, uint64(fullBridgeCallData.auxData));
        (uint256 outputValueA, uint256 outputValueB, bool interactionCompleted) = bridgeContract.finalise(
            inputAssetA, inputAssetB, outputAssetA, outputAssetB, inputs.interactionNonce, inputs.auxData
        );

        if (!interactionCompleted) {
            pendingDefiInteractions[inputs.interactionNonce].encodedBridgeCallData = encodedBridgeCallData;
            return false;
        }

        if (outputValueB > 0 && outputAssetB.assetType == AztecTypes.AztecAssetType.NOT_USED) {
            revert NONZERO_OUTPUT_VALUE_ON_NOT_USED_ASSET(outputValueB);
        }

        if (outputValueA == 0 && outputValueB == 0) {
            // issue refund.
            transferTokensAsync(address(bridgeContract), inputAssetA, inputs.totalInputValue, inputs.interactionNonce);
            transferTokensAsync(address(bridgeContract), inputAssetB, inputs.totalInputValue, inputs.interactionNonce);
        } else {
            // transfer output tokens to rollup contract
            transferTokensAsync(address(bridgeContract), outputAssetA, outputValueA, inputs.interactionNonce);
            transferTokensAsync(address(bridgeContract), outputAssetB, outputValueB, inputs.interactionNonce);
        }

        // compute defiInteractionHash and push it onto the asyncDefiInteractionHashes array
        bool result;
        assembly {
            // Load values from `input` (to get around stack too deep)
            let inputValue := mload(inputs)
            let nonce := mload(add(inputs, 0x20))
            result := iszero(and(eq(outputValueA, 0), eq(outputValueB, 0)))

            // Compute defi interaction hash
            let mPtr := mload(0x40)
            mstore(mPtr, encodedBridgeCallData)
            mstore(add(mPtr, 0x20), nonce)
            mstore(add(mPtr, 0x40), inputValue)
            mstore(add(mPtr, 0x60), outputValueA)
            mstore(add(mPtr, 0x80), outputValueB)
            mstore(add(mPtr, 0xa0), result)
            pop(staticcall(gas(), 0x2, mPtr, 0xc0, 0x00, 0x20))
            let defiInteractionHash := mod(mload(0x00), CIRCUIT_MODULUS)

            // Load sync and async array lengths from rollup state
            let state := sload(rollupState.slot)
            // asyncArrayLen = rollupState.numAsyncDefiInteractionHashes
            let asyncArrayLen := and(ARRAY_LENGTH_MASK, shr(ASYNCDEFIINTERACTIONHASHES_BIT_OFFSET, state))
            // defiArrayLen = rollupState.numDefiInteractionHashes
            let defiArrayLen := and(ARRAY_LENGTH_MASK, shr(DEFIINTERACTIONHASHES_BIT_OFFSET, state))

            // check that size of asyncDefiInteractionHashes isn't such that
            // adding 1 to it will make the next block's defiInteractionHashes length hit 512
            if gt(add(add(1, asyncArrayLen), defiArrayLen), 512) {
                mstore(0, ARRAY_OVERFLOW_SELECTOR)
                revert(0, 0x4)
            }

            // asyncDefiInteractionHashes[asyncArrayLen] = defiInteractionHash
            mstore(0x00, asyncArrayLen)
            mstore(0x20, asyncDefiInteractionHashes.slot)
            sstore(keccak256(0x00, 0x40), defiInteractionHash)

            // increase asyncDefiInteractionHashes.length by 1
            let oldState := and(not(shl(ASYNCDEFIINTERACTIONHASHES_BIT_OFFSET, ARRAY_LENGTH_MASK)), state)
            let newState := or(oldState, shl(ASYNCDEFIINTERACTIONHASHES_BIT_OFFSET, add(asyncArrayLen, 0x01)))

            sstore(rollupState.slot, newState)
        }
        emit DefiBridgeProcessed(
            encodedBridgeCallData,
            inputs.interactionNonce,
            inputs.totalInputValue,
            outputValueA,
            outputValueB,
            result,
            ""
            );

        return true;
    }

    /*----------------------------------------
      INTERNAL/PRIVATE MUTATING FUNCTIONS 
      ----------------------------------------*/

    /**
     * @notice A function which increasees pending deposit amount in the `userPendingDeposits` mapping
     * @dev Implemented in assembly in order to reduce compiled bytecode size and improve gas costs
     * @param _assetId asset ID which was assigned during asset registration
     * @param _owner address that can spend the deposited funds
     * @param _amount deposit token amount
     */
    function increasePendingDepositBalance(uint256 _assetId, address _owner, uint256 _amount)
        internal
        validateAssetIdIsNotVirtual(_assetId)
    {
        uint256 pending = userPendingDeposits[_assetId][_owner];

        if (rollupState.capped) {
            AssetCap memory cap = caps[_assetId];
            uint256 precision = 10 ** cap.precision;

            if (cap.pendingCap == 0 || pending + _amount > uint256(cap.pendingCap) * precision) {
                revert PENDING_CAP_SURPASSED();
            }

            if (cap.dailyCap == 0) {
                revert DAILY_CAP_SURPASSED();
            } else {
                // Increase the available amount, capped by dailyCap
                uint256 capVal = uint256(cap.dailyCap) * precision;
                uint256 rate = capVal / 1 days;
                cap.available += (rate * (block.timestamp - cap.lastUpdatedTimestamp)).toU128();
                if (cap.available > capVal) {
                    cap.available = capVal.toU128();
                }
                if (_amount > cap.available) {
                    revert DAILY_CAP_SURPASSED();
                }
                // Update available and timestamp
                cap.available -= _amount.toU128();
                cap.lastUpdatedTimestamp = uint32(block.timestamp);
                caps[_assetId] = cap;
            }
        }

        userPendingDeposits[_assetId][_owner] = pending + _amount;
    }

    /**
     * @notice A function which decreases pending deposit amount in the `userPendingDeposits` mapping
     * @dev Implemented in assembly in order to reduce compiled bytecode size and improve gas costs
     * @param _assetId asset ID which was assigned during asset registration
     * @param _owner address that owns the pending deposit
     * @param _amount amount of tokens to decrease pending by
     */
    function decreasePendingDepositBalance(uint256 _assetId, address _owner, uint256 _amount)
        internal
        validateAssetIdIsNotVirtual(_assetId)
    {
        bool insufficientDeposit = false;
        assembly {
            // userPendingDeposit = userPendingDeposits[_assetId][_owner]
            mstore(0x00, _assetId)
            mstore(0x20, userPendingDeposits.slot)
            mstore(0x20, keccak256(0x00, 0x40))
            mstore(0x00, _owner)
            let userPendingDepositSlot := keccak256(0x00, 0x40)
            let userPendingDeposit := sload(userPendingDepositSlot)

            insufficientDeposit := lt(userPendingDeposit, _amount)

            let newDeposit := sub(userPendingDeposit, _amount)

            sstore(userPendingDepositSlot, newDeposit)
        }

        if (insufficientDeposit) {
            revert INSUFFICIENT_DEPOSIT();
        }
    }

    /**
     * @notice A function that processes a rollup proof
     * @dev Processing a rollup proof consists of:
     *          1) Verifying the proof's correctness,
     *          2) using the provided proof data to update rollup state + merkle roots,
     *          3) validate/enacting any deposits/withdrawals,
     *          4) processing bridge calls.
     * @param _proofData decoded rollup proof data
     * @param _signatures ECDSA signatures from users authorizing deposit transactions
     * @param _numTxs the number of transactions in the block
     * @param _publicInputsHash the SHA256 hash of the proof's public inputs
     * @param _rollupBeneficiary The address to be paid any subsidy for bridge calls and rollup fees
     */
    function processRollupProof(
        bytes memory _proofData,
        bytes memory _signatures,
        uint256 _numTxs,
        uint256 _publicInputsHash,
        address _rollupBeneficiary
    ) internal {
        uint256 rollupId = verifyProofAndUpdateState(_proofData, _publicInputsHash);
        processDepositsAndWithdrawals(_proofData, _numTxs, _signatures);
        bytes32[] memory nextDefiHashes = processBridgeCalls(_proofData, _rollupBeneficiary);
        emit RollupProcessed(rollupId, nextDefiHashes, msg.sender);
    }

    /**
     * @notice A function which verifies zk proof and updates the contract's state variables
     * @dev encodedProofData is read from calldata passed into the transaction and differs from `_proofData`
     * @param _proofData decoded rollup proof data
     * @param _publicInputsHash a hash of public inputs (computed by `Decoder.sol`)
     * @return rollupId id of the rollup which is being processed
     */
    function verifyProofAndUpdateState(bytes memory _proofData, uint256 _publicInputsHash)
        internal
        returns (uint256 rollupId)
    {
        // Verify the rollup proof.
        //
        // We manually call the verifier contract via assembly to save on gas costs and to reduce contract bytecode size
        assembly {
            /**
             * Validate correctness of zk proof.
             *
             * 1st Item is to format verifier calldata.
             *
             */

            // The `encodedProofData` (in calldata) contains the concatenation of
            // encoded 'broadcasted inputs' and the actual zk proof data.
            // (The `boadcasted inputs` is converted into a 32-byte SHA256 hash, which is
            // validated to equal the first public inputs of the zk proof. This is done in `Decoder.sol`).
            // We need to identify the location in calldata that points to the start of the zk proof data.

            // Step 1: compute size of zk proof data and its calldata pointer.
            /**
             * Data layout for `bytes encodedProofData`...
             *
             *             0x00 : 0x20 : length of array
             *             0x20 : 0x20 + header : root rollup header data
             *             0x20 + header : 0x24 + header : X, the length of encoded inner join-split public inputs
             *             0x24 + header : 0x24 + header + X : (inner join-split public inputs)
             *             0x24 + header + X : 0x28 + header + X : Y, the length of the zk proof data
             *             0x28 + header + X : 0x28 + haeder + X + Y : zk proof data
             *
             *             We need to recover the numeric value of `0x28 + header + X` and `Y`
             *
             */
            // Begin by getting length of encoded inner join-split public inputs.
            // `calldataload(0x04)` points to start of bytes array. Add 0x24 to skip over length param and function signature.
            // The calldata param 4 bytes *after* the header is the length of the pub inputs array. However it is a packed 4-byte param.
            // To extract it, we subtract 24 bytes from the calldata pointer and mask off all but the 4 least significant bytes.
            let encodedInnerDataSize :=
                and(calldataload(add(add(calldataload(0x04), 0x24), sub(ROLLUP_HEADER_LENGTH, 0x18))), 0xffffffff)

            // add 8 bytes to skip over the two packed params that follow the rollup header data
            // broadcastedDataSize = inner join-split pubinput size + header size
            let broadcastedDataSize := add(add(ROLLUP_HEADER_LENGTH, 8), encodedInnerDataSize)

            // Compute zk proof data size by subtracting broadcastedDataSize from overall length of bytes encodedProofsData
            let zkProofDataSize := sub(calldataload(add(calldataload(0x04), 0x04)), broadcastedDataSize)

            // Compute calldata pointer to start of zk proof data by adding calldata offset to broadcastedDataSize
            // (+0x24 skips over function signature and length param of bytes encodedProofData)
            let zkProofDataPtr := add(broadcastedDataSize, add(calldataload(0x04), 0x24))

            // Step 2: Format calldata for verifier contract call.

            // Get free memory pointer - we copy calldata into memory starting here
            let dataPtr := mload(0x40)

            // We call the function `verify(bytes,uint256)`
            // The function signature is 0xac318c5d
            // Calldata map is:
            // 0x00 - 0x04 : 0xac318c5d
            // 0x04 - 0x24 : 0x40 (number of bytes between 0x04 and the start of the `proofData` array at 0x44)
            // 0x24 - 0x44 : publicInputsHash
            // 0x44 - .... : proofData
            mstore8(dataPtr, 0xac)
            mstore8(add(dataPtr, 0x01), 0x31)
            mstore8(add(dataPtr, 0x02), 0x8c)
            mstore8(add(dataPtr, 0x03), 0x5d)
            mstore(add(dataPtr, 0x04), 0x40)
            mstore(add(dataPtr, 0x24), _publicInputsHash)
            mstore(add(dataPtr, 0x44), zkProofDataSize) // length of zkProofData bytes array
            calldatacopy(add(dataPtr, 0x64), zkProofDataPtr, zkProofDataSize) // copy the zk proof data into memory

            // Step 3: Call our verifier contract. It does not return any values, but will throw an error if the proof is not valid
            // i.e. verified == false if proof is not valid
            let verifierAddress := and(sload(rollupState.slot), ADDRESS_MASK)
            if iszero(extcodesize(verifierAddress)) {
                mstore(0, INVALID_ADDRESS_NO_CODE_SELECTOR)
                revert(0, 0x4)
            }
            let proof_verified := staticcall(gas(), verifierAddress, dataPtr, add(zkProofDataSize, 0x64), 0x00, 0x00)

            // Check the proof is valid!
            if iszero(proof_verified) {
                returndatacopy(0, 0, returndatasize())
                revert(0, returndatasize())
            }
        }

        // Validate and update state hash
        rollupId = validateAndUpdateMerkleRoots(_proofData);
    }

    /**
     * @notice Extracts roots from public inputs and validate that they are inline with current contract `rollupState`
     * @param _proofData decoded rollup proof data
     * @return rollup id
     * @dev To make the circuits happy, we want to only insert at the next subtree. The subtrees that we are using are
     *      28 leafs in size. They could be smaller but we just want them to be of same size for circuit related
     *      reasons.
     *          When we have the case that the `storedDataSize % numDataLeaves == 0`, we are perfectly dividing. This
     *      means that the incoming rollup matches perfectly with a boundry of the next subtree.
     *          When this is not the case, we have to compute an offset that we then apply so that the full state can
     *      be build with a bunch of same-sized trees (when the rollup is not full we insert a tree with some zero
     *      leaves). This offset can be computed as `numDataLeaves - (storedDataSize % numDataLeaves)` and is,
     *      essentially, how big a "space" we should leave so that the currently inserted subtree ends exactly at
     *      the subtree boundry. The value is always >= 0. In the function below we won’t hit the zero case, because
     *      that would be cought by the "if-branch".
     *
     *      Example: We have just had 32 rollups of size 28 (`storedDataSize = 896`). Now there is a small rollup with
     *      only 6 transactions. We are not perfectly dividing, hence we compute the offset as `6 - 896 % 6 = 4`.
     *      The start index is `896 + 4 = 900`. With the added leaves, the stored data size now becomes `906`.
     *          Now, comes another full rollup (28 txs). We compute `906 % 28 = 10`. The value is non-zero which means
     *      that we don’t perfectly divide and have to compute an offset `28 - 906 % 28 = 18`. The start index is
     *      `906 + 18 = 924`. Notice that `924 % 28 == 0`, so this will land us exactly at a location where everything
     *      in the past could have been subtrees of size 28.
     */
    function validateAndUpdateMerkleRoots(bytes memory _proofData) internal returns (uint256) {
        (uint256 rollupId, bytes32 oldStateHash, bytes32 newStateHash, uint32 numDataLeaves, uint32 dataStartIndex) =
            computeRootHashes(_proofData);

        if (oldStateHash != rollupStateHash) {
            revert INCORRECT_STATE_HASH(oldStateHash, newStateHash);
        }

        unchecked {
            uint32 storedDataSize = rollupState.datasize;
            // Ensure we are inserting at the next subtree boundary.
            if (storedDataSize % numDataLeaves == 0) {
                if (dataStartIndex != storedDataSize) {
                    revert INCORRECT_DATA_START_INDEX(dataStartIndex, storedDataSize);
                }
            } else {
                uint256 expected = storedDataSize + numDataLeaves - (storedDataSize % numDataLeaves);
                if (dataStartIndex != expected) {
                    revert INCORRECT_DATA_START_INDEX(dataStartIndex, expected);
                }
            }

            rollupStateHash = newStateHash;
            rollupState.datasize = dataStartIndex + numDataLeaves;
        }
        return rollupId;
    }

    /**
     * @notice A function which processes deposits and withdrawls
     * @param _proofData decoded rollup proof data
     * @param _numTxs number of transactions rolled up in the proof
     * @param _signatures byte array of secp256k1 ECDSA signatures, authorising a transfer of tokens
     */
    function processDepositsAndWithdrawals(bytes memory _proofData, uint256 _numTxs, bytes memory _signatures)
        internal
    {
        uint256 sigIndex = 0x00;
        uint256 proofDataPtr;
        uint256 end;
        assembly {
            // add 0x20 to skip over 1st member of the bytes type (the length field).
            // Also skip over the rollup header.
            proofDataPtr := add(ROLLUP_HEADER_LENGTH, add(_proofData, 0x20))

            // compute the position of proofDataPtr after we iterate through every transaction
            end := add(proofDataPtr, mul(_numTxs, TX_PUBLIC_INPUT_LENGTH))
        }

        // This is a bit of a hot loop, we iterate over every tx to determine whether to process deposits or withdrawals.
        while (proofDataPtr < end) {
            // extract the minimum information we need to determine whether to skip this iteration
            uint256 publicValue;
            assembly {
                publicValue := mload(add(proofDataPtr, 0xa0))
            }
            if (publicValue > 0) {
                uint256 proofId;
                uint256 assetId;
                address publicOwner;
                assembly {
                    proofId := mload(proofDataPtr)
                    assetId := mload(add(proofDataPtr, 0xe0))
                    publicOwner := mload(add(proofDataPtr, 0xc0))
                }

                if (proofId == 1) {
                    // validate user has approved deposit
                    bytes32 digest;
                    assembly {
                        // compute the tx id to check if user has approved tx
                        digest := keccak256(proofDataPtr, TX_PUBLIC_INPUT_LENGTH)
                    }
                    // check if there is an existing entry in depositProofApprovals
                    // if there is, no further work required.
                    // we don't need to clear `depositProofApprovals[publicOwner][digest]` because proofs cannot be re-used.
                    // A single proof describes the creation of 2 output notes and the addition of 2 input note nullifiers
                    // (both of these nullifiers can be categorised as "fake". They may not map to existing notes but are still inserted in the nullifier set)
                    // Replaying the proof will fail to satisfy the rollup circuit's non-membership check on the input nullifiers.
                    // We avoid resetting `depositProofApprovals` because that would cost additional gas post-London hard fork.
                    if (!depositProofApprovals[publicOwner][digest]) {
                        // extract and validate signature
                        // we can create a bytes memory container for the signature without allocating new memory,
                        // by overwriting the previous 32 bytes in the `signatures` array with the 'length' of our synthetic byte array (96)
                        // we store the memory we overwrite in `temp`, so that we can restore it
                        bytes memory signature;
                        uint256 temp;
                        assembly {
                            // set `signature` to point to 32 bytes less than the desired `r, s, v` values in `signatures`
                            signature := add(_signatures, sigIndex)
                            // cache the memory we're about to overwrite
                            temp := mload(signature)
                            // write in a 96-byte 'length' parameter into the `signature` bytes array
                            mstore(signature, 0x60)
                        }

                        bytes32 hashedMessage = RollupProcessorLibrary.getSignedMessageForTxId(digest);

                        RollupProcessorLibrary.validateShieldSignatureUnpacked(hashedMessage, signature, publicOwner);
                        // restore the memory we overwrote
                        assembly {
                            mstore(signature, temp)
                            sigIndex := add(sigIndex, 0x60)
                        }
                    }
                    decreasePendingDepositBalance(assetId, publicOwner, publicValue);
                }

                if (proofId == 2) {
                    withdraw(publicValue, publicOwner, assetId);
                }
            }
            // don't check for overflow, would take > 2^200 iterations of this loop for that to happen!
            unchecked {
                proofDataPtr += TX_PUBLIC_INPUT_LENGTH;
            }
        }
    }

    /**
     * @notice A function which pulls tokens from a bridge
     * @dev Calls `transferFrom` if asset is of type ERC20. If asset is ETH we validate a payment has been made
     *      against the provided interaction nonce. This function is used by `processAsyncDefiInteraction`.
     * @param _bridge address of bridge contract we're transferring tokens from
     * @param _asset the AztecAsset being transferred
     * @param _outputValue the expected value transferred
     * @param _interactionNonce the defi interaction nonce of the interaction
     */
    function transferTokensAsync(
        address _bridge,
        AztecTypes.AztecAsset memory _asset,
        uint256 _outputValue,
        uint256 _interactionNonce
    ) internal {
        if (_outputValue == 0) {
            return;
        }
        if (_asset.assetType == AztecTypes.AztecAssetType.ETH) {
            if (_outputValue > ethPayments[_interactionNonce]) {
                revert INSUFFICIENT_ETH_PAYMENT();
            }
            ethPayments[_interactionNonce] = 0;
        } else if (_asset.assetType == AztecTypes.AztecAssetType.ERC20) {
            address tokenAddress = _asset.erc20Address;
            TokenTransfers.safeTransferFrom(tokenAddress, _bridge, address(this), _outputValue);
        }
    }

    /**
     * @notice A function which transfers fees to the `_feeReceiver`
     * @dev Note: function will not revert if underlying transfers fails
     * @param _proofData decoded rollup proof data
     * @param _feeReceiver fee beneficiary as described by the rollup provider
     */
    function transferFee(bytes memory _proofData, address _feeReceiver) internal {
        for (uint256 i = 0; i < NUMBER_OF_ASSETS;) {
            uint256 txFee = extractTotalTxFee(_proofData, i);
            if (txFee > 0) {
                uint256 assetId = extractFeeAssetId(_proofData, i);
                if (assetId == ETH_ASSET_ID) {
                    // We explicitly do not throw if this call fails, as this opens up the possiblity of griefing
                    // attacks --> engineering a failed fee would invalidate an entire rollup block. As griefing could
                    // be done by consuming all gas in the `_feeReceiver` fallback only 50K gas is forwarded. We are
                    // forwarding a bit more gas than in the withdraw function because this code will only be hit
                    // at most once each rollup-block and we want to give the provider a bit more flexibility.
                    assembly {
                        pop(call(50000, _feeReceiver, txFee, 0, 0, 0, 0))
                    }
                } else {
                    address assetAddress = getSupportedAsset(assetId);
                    TokenTransfers.transferToDoNotBubbleErrors(
                        assetAddress, _feeReceiver, txFee, assetGasLimits[assetId]
                    );
                }
            }
            unchecked {
                ++i;
            }
        }
    }

    /**
     * @notice Internal utility function which withdraws funds from the contract to a receiver address
     * @param _withdrawValue - value being withdrawn from the contract
     * @param _receiver - address receiving public ERC20 tokens
     * @param _assetId - ID of the asset for which a withdrawal is being performed
     * @dev The function doesn't throw if the inner call fails, as this opens up the possiblity of griefing attacks
     *      -> engineering a failed withdrawal would invalidate an entire rollup block.
     *      A griefing attack could be done by consuming all gas in the `_receiver` fallback and for this reason we
     *      only forward 30K gas. This still allows the recipient to handle accounting if recipient is a contract.
     *      The user should ensure their withdrawal will succeed or they will lose the funds.
     */
    function withdraw(uint256 _withdrawValue, address _receiver, uint256 _assetId) internal {
        if (_receiver == address(0)) {
            revert WITHDRAW_TO_ZERO_ADDRESS();
        }
        if (_assetId == 0) {
            assembly {
                pop(call(30000, _receiver, _withdrawValue, 0, 0, 0, 0))
            }
            // payable(_receiver).call{gas: 30000, value: _withdrawValue}('');
        } else {
            address assetAddress = getSupportedAsset(_assetId);
            TokenTransfers.transferToDoNotBubbleErrors(
                assetAddress, _receiver, _withdrawValue, assetGasLimits[_assetId]
            );
        }
    }

    /*----------------------------------------
      PUBLIC/EXTERNAL NON-MUTATING FUNCTIONS 
      ----------------------------------------*/

    /**
     * @notice Get implementation's version number
     * @return version version number of the implementation
     */
    function getImplementationVersion() public view virtual returns (uint8 version) {
        return 2;
    }

    /**
     * @notice Get true if the contract is paused, false otherwise
     * @return isPaused - True if paused, false otherwise
     */
    function paused() external view override (IRollupProcessor) returns (bool isPaused) {
        return rollupState.paused;
    }

    /**
     * @notice Gets the number of filled entries in the data tree
     * @return dataSize number of filled entries in the data tree (equivalent to the number of notes created on L2)
     */
    function getDataSize() public view override (IRollupProcessor) returns (uint256 dataSize) {
        return rollupState.datasize;
    }

    /**
     * @notice Returns true if deposits are capped, false otherwise
     * @return capped - True if deposits are capped, false otherwise
     */
    function getCapped() public view override (IRollupProcessorV2) returns (bool capped) {
        return rollupState.capped;
    }

    /**
     * @notice Gets the number of pending defi interactions that have resolved but have not yet been added into the
     *         DeFi tree
     * @return - the number of pending interactions
     * @dev This value can never exceed 512. This limit is set in order to prevent griefing attacks - `processRollup`
     *      iterates through `asyncDefiInteractionHashes` and copies their values into `defiInteractionHashes`. Loop
     *      is bounded to < 512 so that tx does not exceed block gas limit.
     */
    function getPendingDefiInteractionHashesLength() public view override (IRollupProcessor) returns (uint256) {
        return rollupState.numAsyncDefiInteractionHashes + rollupState.numDefiInteractionHashes;
    }

    /**
     * @notice Gets the address of the PLONK verification smart contract
     * @return - address of the verification smart contract
     */
    function verifier() public view override (IRollupProcessor) returns (address) {
        return address(rollupState.verifier);
    }

    /**
     * @notice Gets the number of supported bridges
     * @return - the number of supported bridges
     */
    function getSupportedBridgesLength() external view override (IRollupProcessor) returns (uint256) {
        return supportedBridges.length;
    }

    /**
     * @notice Gets the bridge contract address for a given bridgeAddressId
     * @param _bridgeAddressId identifier used to denote a particular bridge
     * @return - the address of the matching bridge contract
     */
    function getSupportedBridge(uint256 _bridgeAddressId) public view override (IRollupProcessor) returns (address) {
        return supportedBridges[_bridgeAddressId - 1];
    }

    /**
     * @notice Gets the number of supported assets
     * @return - the number of supported assets
     */
    function getSupportedAssetsLength() external view override (IRollupProcessor) returns (uint256) {
        return supportedAssets.length;
    }

    /**
     * @notice Gets the ERC20 token address of a supported asset for a given `_assetId`
     * @param _assetId identifier used to denote a particular asset
     * @return - the address of the matching asset
     */
    function getSupportedAsset(uint256 _assetId)
        public
        view
        override (IRollupProcessor)
        validateAssetIdIsNotVirtual(_assetId)
        returns (address)
    {
        // If assetId == ETH_ASSET_ID (i.e. 0), this represents native ETH.
        // ERC20 token asset id values start at 1
        if (_assetId == ETH_ASSET_ID) {
            return address(0x0);
        }
        address result = supportedAssets[_assetId - 1];
        if (result == address(0)) {
            revert INVALID_ASSET_ADDRESS();
        }
        return result;
    }

    /**
     * @notice Gets the status of the escape hatch.
     * @return True if escape hatch is open, false otherwise
     * @return The number of blocks until the next opening/closing of escape hatch
     */
    function getEscapeHatchStatus() public view override (IRollupProcessor) returns (bool, uint256) {
        uint256 blockNum = block.number;

        bool isOpen = blockNum % escapeBlockUpperBound >= escapeBlockLowerBound;
        uint256 blocksRemaining = 0;
        if (isOpen) {
            if (block.timestamp < uint256(lastRollupTimeStamp) + delayBeforeEscapeHatch) {
                isOpen = false;
            }
            // num blocks escape hatch will remain open for
            blocksRemaining = escapeBlockUpperBound - (blockNum % escapeBlockUpperBound);
        } else {
            // num blocks until escape hatch will be opened
            blocksRemaining = escapeBlockLowerBound - (blockNum % escapeBlockUpperBound);
        }
        return (isOpen, blocksRemaining);
    }

    /**
     * @notice Gets the number of defi interaction hashes
     * @dev A defi interaction hash represents a defi interaction that has resolved, but whose
     *      result data has not yet been added into the Aztec Defi Merkle tree. This step is needed in order to convert
     *      L2 Defi claim notes into L2 value notes.
     * @return - the number of pending defi interaction hashes
     */
    function getDefiInteractionHashesLength() public view override (IRollupProcessor) returns (uint256) {
        return rollupState.numDefiInteractionHashes;
    }

    /**
     * @notice Gets the number of asynchronous defi interaction hashes
     * @dev A defi interaction hash represents an asynchronous defi interaction that has resolved, but whose interaction
     *      result data has not yet been added into the Aztec Defi Merkle tree. This step is needed in order to convert
     *      L2 Defi claim notes into L2 value notes.
     * @return - the number of pending async defi interaction hashes
     */
    function getAsyncDefiInteractionHashesLength() public view override (IRollupProcessor) returns (uint256) {
        return rollupState.numAsyncDefiInteractionHashes;
    }

    /*----------------------------------------
      INTERNAL/PRIVATE NON-MUTATING FUNCTIONS
      ----------------------------------------*/

    /**
     * @notice A function which constructs a FullBridgeCallData struct based on values from `_encodedBridgeCallData`
     * @param _encodedBridgeCallData a bit-array that contains data describing a specific bridge call
     *
     * Structure of the bit array is as follows (starting at the least significant bit):
     * | bit range | parameter       | description |
     * | 0 - 32    | bridgeAddressId | The address ID. Bridge address = `supportedBridges[bridgeAddressId]` |
     * | 32 - 62   | inputAssetIdA   | First input asset ID. |
     * | 62 - 92   | inputAssetIdB   | Second input asset ID. Must be 0 if bridge does not have a 2nd input asset. |
     * | 92 - 122  | outputAssetIdA  | First output asset ID. |
     * | 122 - 152 | outputAssetIdB  | Second output asset ID. Must be 0 if bridge does not have a 2nd output asset. |
     * | 152 - 184 | bitConfig       | Bit-array that contains boolean bridge settings. |
     * | 184 - 248 | auxData         | 64 bits of custom data to be passed to the bridge contract. Structure of auxData
     *                                 is defined/checked by the bridge contract. |
     *
     * Structure of the `bitConfig` parameter is as follows
     * | bit | parameter               | description |
     * | 0   | secondInputInUse        | Does the bridge have a second input asset? |
     * | 1   | secondOutputInUse       | Does the bridge have a second output asset? |
     *
     * @dev Note: Virtual assets are assets that don't have an ERC20 token analogue and exist solely as notes within
     *            the Aztec network. They can be created/spent within bridge calls. They are used to enable bridges
     *            to track internally-defined data without having to mint a new token on-chain. An example use of
     *            a virtual asset would be a virtual loan asset that tracks an outstanding debt that must be repaid
     *            to recover a collateral deposited into the bridge.
     *
     * @return fullBridgeCallData a struct that contains information defining a specific bridge call
     */
    function getFullBridgeCallData(uint256 _encodedBridgeCallData)
        internal
        view
        returns (FullBridgeCallData memory fullBridgeCallData)
    {
        assembly {
            mstore(fullBridgeCallData, and(_encodedBridgeCallData, MASK_THIRTY_TWO_BITS)) // bridgeAddressId
            mstore(
                add(fullBridgeCallData, 0x40),
                and(shr(INPUT_ASSET_ID_A_SHIFT, _encodedBridgeCallData), MASK_THIRTY_BITS)
            ) // inputAssetIdA
            mstore(
                add(fullBridgeCallData, 0x60),
                and(shr(INPUT_ASSET_ID_B_SHIFT, _encodedBridgeCallData), MASK_THIRTY_BITS)
            ) // inputAssetIdB
            mstore(
                add(fullBridgeCallData, 0x80),
                and(shr(OUTPUT_ASSET_ID_A_SHIFT, _encodedBridgeCallData), MASK_THIRTY_BITS)
            ) // outputAssetIdA
            mstore(
                add(fullBridgeCallData, 0xa0),
                and(shr(OUTPUT_ASSET_ID_B_SHIFT, _encodedBridgeCallData), MASK_THIRTY_BITS)
            ) // outputAssetIdB
            mstore(
                add(fullBridgeCallData, 0xc0), and(shr(AUX_DATA_SHIFT, _encodedBridgeCallData), MASK_SIXTY_FOUR_BITS)
            ) // auxData

            mstore(
                add(fullBridgeCallData, 0xe0),
                and(shr(add(INPUT_ASSET_ID_A_SHIFT, VIRTUAL_ASSET_ID_FLAG_SHIFT), _encodedBridgeCallData), 1)
            ) // firstInputVirtual (30th bit of inputAssetIdA) == 1
            mstore(
                add(fullBridgeCallData, 0x100),
                and(shr(add(INPUT_ASSET_ID_B_SHIFT, VIRTUAL_ASSET_ID_FLAG_SHIFT), _encodedBridgeCallData), 1)
            ) // secondInputVirtual (30th bit of inputAssetIdB) == 1
            mstore(
                add(fullBridgeCallData, 0x120),
                and(shr(add(OUTPUT_ASSET_ID_A_SHIFT, VIRTUAL_ASSET_ID_FLAG_SHIFT), _encodedBridgeCallData), 1)
            ) // firstOutputVirtual (30th bit of outputAssetIdA) == 1
            mstore(
                add(fullBridgeCallData, 0x140),
                and(shr(add(OUTPUT_ASSET_ID_B_SHIFT, VIRTUAL_ASSET_ID_FLAG_SHIFT), _encodedBridgeCallData), 1)
            ) // secondOutputVirtual (30th bit of outputAssetIdB) == 1
            let bitConfig := and(shr(BITCONFIG_SHIFT, _encodedBridgeCallData), MASK_THIRTY_TWO_BITS)
            // bitConfig = bit mask that contains bridge ID settings
            // bit 0 = second input asset in use?
            // bit 1 = second output asset in use?
            mstore(add(fullBridgeCallData, 0x160), eq(and(bitConfig, 1), 1)) // secondInputInUse (bitConfig & 1) == 1
            mstore(add(fullBridgeCallData, 0x180), eq(and(shr(1, bitConfig), 1), 1)) // secondOutputInUse ((bitConfig >> 1) & 1) == 1
        }
        fullBridgeCallData.bridgeAddress = supportedBridges[fullBridgeCallData.bridgeAddressId - 1];
        fullBridgeCallData.bridgeGasLimit = bridgeGasLimits[fullBridgeCallData.bridgeAddressId];

        // potential conflicting states that are explicitly ruled out by circuit constraints:
        if (!fullBridgeCallData.secondInputInUse && fullBridgeCallData.inputAssetIdB > 0) {
            revert INCONSISTENT_BRIDGE_CALL_DATA();
        }
        if (!fullBridgeCallData.secondOutputInUse && fullBridgeCallData.outputAssetIdB > 0) {
            revert INCONSISTENT_BRIDGE_CALL_DATA();
        }
        if (
            fullBridgeCallData.secondInputInUse
                && (fullBridgeCallData.inputAssetIdA == fullBridgeCallData.inputAssetIdB)
        ) {
            revert BRIDGE_WITH_IDENTICAL_INPUT_ASSETS(fullBridgeCallData.inputAssetIdA);
        }
        // Outputs can both be virtual. In that case, their asset ids will both be 2 ** 29.
        bool secondOutputReal = fullBridgeCallData.secondOutputInUse && !fullBridgeCallData.secondOutputVirtual;
        if (secondOutputReal && fullBridgeCallData.outputAssetIdA == fullBridgeCallData.outputAssetIdB) {
            revert BRIDGE_WITH_IDENTICAL_OUTPUT_ASSETS(fullBridgeCallData.outputAssetIdA);
        }
    }

    /**
     * @notice Gets the four input/output assets associated with a specific bridge call
     * @param _fullBridgeCallData a struct that contains information defining a specific bridge call
     * @param _interactionNonce interaction nonce of a corresponding bridge call
     * @dev `_interactionNonce` param is here because it is used as an ID of output virtual asset
     *
     * @return inputAssetA the first input asset
     * @return inputAssetB the second input asset
     * @return outputAssetA the first output asset
     * @return outputAssetB the second output asset
     */
    function getAztecAssetTypes(FullBridgeCallData memory _fullBridgeCallData, uint256 _interactionNonce)
        internal
        view
        returns (
            AztecTypes.AztecAsset memory inputAssetA,
            AztecTypes.AztecAsset memory inputAssetB,
            AztecTypes.AztecAsset memory outputAssetA,
            AztecTypes.AztecAsset memory outputAssetB
        )
    {
        if (_fullBridgeCallData.firstInputVirtual) {
            // asset id is a nonce of the interaction in which the virtual asset was created
            inputAssetA.id = _fullBridgeCallData.inputAssetIdA - VIRTUAL_ASSET_ID_FLAG;
            inputAssetA.erc20Address = address(0x0);
            inputAssetA.assetType = AztecTypes.AztecAssetType.VIRTUAL;
        } else {
            inputAssetA.id = _fullBridgeCallData.inputAssetIdA;
            inputAssetA.erc20Address = getSupportedAsset(_fullBridgeCallData.inputAssetIdA);
            inputAssetA.assetType = inputAssetA.erc20Address == address(0x0)
                ? AztecTypes.AztecAssetType.ETH
                : AztecTypes.AztecAssetType.ERC20;
        }
        if (_fullBridgeCallData.firstOutputVirtual) {
            // use nonce as asset id.
            outputAssetA.id = _interactionNonce;
            outputAssetA.erc20Address = address(0x0);
            outputAssetA.assetType = AztecTypes.AztecAssetType.VIRTUAL;
        } else {
            outputAssetA.id = _fullBridgeCallData.outputAssetIdA;
            outputAssetA.erc20Address = getSupportedAsset(_fullBridgeCallData.outputAssetIdA);
            outputAssetA.assetType = outputAssetA.erc20Address == address(0x0)
                ? AztecTypes.AztecAssetType.ETH
                : AztecTypes.AztecAssetType.ERC20;
        }

        if (_fullBridgeCallData.secondInputVirtual) {
            // asset id is a nonce of the interaction in which the virtual asset was created
            inputAssetB.id = _fullBridgeCallData.inputAssetIdB - VIRTUAL_ASSET_ID_FLAG;
            inputAssetB.erc20Address = address(0x0);
            inputAssetB.assetType = AztecTypes.AztecAssetType.VIRTUAL;
        } else if (_fullBridgeCallData.secondInputInUse) {
            inputAssetB.id = _fullBridgeCallData.inputAssetIdB;
            inputAssetB.erc20Address = getSupportedAsset(_fullBridgeCallData.inputAssetIdB);
            inputAssetB.assetType = inputAssetB.erc20Address == address(0x0)
                ? AztecTypes.AztecAssetType.ETH
                : AztecTypes.AztecAssetType.ERC20;
        } else {
            inputAssetB.id = 0;
            inputAssetB.erc20Address = address(0x0);
            inputAssetB.assetType = AztecTypes.AztecAssetType.NOT_USED;
        }

        if (_fullBridgeCallData.secondOutputVirtual) {
            // use nonce as asset id.
            outputAssetB.id = _interactionNonce;
            outputAssetB.erc20Address = address(0x0);
            outputAssetB.assetType = AztecTypes.AztecAssetType.VIRTUAL;
        } else if (_fullBridgeCallData.secondOutputInUse) {
            outputAssetB.id = _fullBridgeCallData.outputAssetIdB;
            outputAssetB.erc20Address = getSupportedAsset(_fullBridgeCallData.outputAssetIdB);
            outputAssetB.assetType = outputAssetB.erc20Address == address(0x0)
                ? AztecTypes.AztecAssetType.ETH
                : AztecTypes.AztecAssetType.ERC20;
        } else {
            outputAssetB.id = 0;
            outputAssetB.erc20Address = address(0x0);
            outputAssetB.assetType = AztecTypes.AztecAssetType.NOT_USED;
        }
    }

    /**
     * @notice Gets the length of the defi interaction hashes array and the number of pending interactions
     *
     * @return defiInteractionHashesLength the complete length of the defi interaction array
     * @return numPendingInteractions the current number of pending defi interactions
     * @dev `numPendingInteractions` is capped at `NUMBER_OF_BRIDGE_CALLS`
     */
    function getDefiHashesLengthsAndNumPendingInteractions()
        internal
        view
        returns (uint256 defiInteractionHashesLength, uint256 numPendingInteractions)
    {
        assembly {
            // retrieve the total length of the defi interactions array and also the number of pending interactions to a maximum of NUMBER_OF_BRIDGE_CALLS
            let state := sload(rollupState.slot)
            {
                defiInteractionHashesLength := and(ARRAY_LENGTH_MASK, shr(DEFIINTERACTIONHASHES_BIT_OFFSET, state))
                numPendingInteractions := defiInteractionHashesLength
                if gt(numPendingInteractions, NUMBER_OF_BRIDGE_CALLS) {
                    numPendingInteractions := NUMBER_OF_BRIDGE_CALLS
                }
            }
        }
    }

    /**
     * @notice Gets the set of hashes that comprise the current pending interactions and nextExpectedHash
     *
     * @return hashes the set of valid (i.e. non-zero) hashes that comprise the pending interactions
     * @return nextExpectedHash the hash of all hashes (including zero hashes) that comprise the pending interactions
     */
    function getPendingAndNextExpectedHashes()
        internal
        view
        returns (bytes32[] memory hashes, bytes32 nextExpectedHash)
    {
        /**
         * ----------------------------------------
         * Compute nextExpectedHash
         * -----------------------------------------
         *
         * The `defiInteractionHashes` mapping emulates an array that represents the
         * set of defi interactions from previous blocks that have been resolved.
         *
         * We need to take the interaction result data from each of the above defi interactions,
         * and add that data into the Aztec L2 merkle tree that contains defi interaction results
         * (the "Defi Tree". Its merkle root is one of the inputs to the storage variable `rollupStateHash`)
         *
         * It is the rollup provider's responsibility to perform these additions.
         * In the current block being processed, the rollup provider must take these pending interaction results,
         * create commitments to each result and insert each commitment into the next empty leaf of the defi tree.
         *
         * The following code validates that this has happened! This is how:
         *
         * Part 1: What are we checking?
         *
         * The rollup circuit will receive, as a private input from the rollup provider, the pending defi interaction
         * results
         * (`encodedBridgeCallData`, `totalInputValue`, `totalOutputValueA`, `totalOutputValueB`, `result`)
         * The rollup circuit will compute the SHA256 hash of each interaction result (the defiInteractionHash)
         * Finally the SHA256 hash of `NUMBER_OF_BRIDGE_CALLS` of these defiInteractionHash values is computed.
         * (if there are fewer than `NUMBER_OF_BRIDGE_CALLS` pending defi interaction results, the SHA256 hash of
         * an empty defi interaction result is used instead. i.e. all variable values are set to 0)
         * The computed SHA256 hash, the `pendingDefiInteractionHash`, is one of the broadcasted values that forms
         * the `publicInputsHash` public input to the rollup circuit.
         * When verifying a rollup proof, this smart contract will compute `publicInputsHash` from the input calldata.
         * The PLONK Verifier smart contract will then validate that our computed value for `publicInputHash` matches
         * the value used when generating the rollup proof.
         *
         * TLDR of the above: our proof data contains a variable called `pendingDefiInteractionHash`, which is
         * the CLAIMED VALUE of SHA256 hashing the SHA256 hashes of the defi interactions that have resolved but whose
         * data has not yet been added into the defi tree.
         *
         * Part 2: How do we check `pendingDefiInteractionHash` is correct???
         *
         * This contract will call `DefiBridgeProxy.convert` (via delegatecall) on every new defi interaction present
         * in the block. The return values from the bridge proxy contract are used to construct a defi interaction
         * result. Its hash is then computed and stored in `defiInteractionHashes`.
         *
         * N.B. It's very important that DefiBridgeProxy does not call selfdestruct, or makes a delegatecall out to
         *      a contract that can selfdestruct :o
         *
         * Similarly, when async defi interactions resolve, the interaction result is stored in
         * `asyncDefiInteractionHashes`. At the end of the processBridgeCalls function, the contents of the async array
         * is copied into `defiInteractionHashes` (i.e. async interaction results are delayed by 1 rollup block.
         * This is to prevent griefing attacks where the rollup state changes between the time taken for a rollup tx
         * to be constructed and the rollup tx to be mined)
         *
         * We use the contents of `defiInteractionHashes` to reconstruct `pendingDefiInteractionHash`, and validate it
         * matches the value present in calldata and therefore the value used in the rollup circuit when this block's
         * rollup proof was constructed. This validates that all of the required defi interaction results were added
         * into the defi tree by the rollup provider (the circuit logic enforces this, we just need to check the rollup
         * provider used the correct inputs)
         */
        (uint256 defiInteractionHashesLength, uint256 numPendingInteractions) =
            getDefiHashesLengthsAndNumPendingInteractions();
        uint256 offset = defiInteractionHashesLength - numPendingInteractions;
        assembly {
            // allocate the output array of hashes
            hashes := mload(0x40)
            let hashData := add(hashes, 0x20)
            // update the free memory pointer to point past the end of our array
            // our array will consume 32 bytes for the length field plus NUMBER_OF_BRIDGE_BYTES for all of the hashes
            mstore(0x40, add(hashes, add(NUMBER_OF_BRIDGE_BYTES, 0x20)))
            // set the length of hashes to only include the non-zero hash values
            // although this function will write all of the hashes into our allocated memory, we only want to return the non-zero hashes
            mstore(hashes, numPendingInteractions)

            // Prepare the reusable part of the defi interaction hashes slot computation
            mstore(0x20, defiInteractionHashes.slot)
            let i := 0

            // Iterate over numPendingInteractions (will be between 0 and NUMBER_OF_BRIDGE_CALLS)
            // Load defiInteractionHashes[offset + i] and store in memory
            // in order to compute SHA2 hash (nextExpectedHash)
            for {} lt(i, numPendingInteractions) { i := add(i, 0x01) } {
                // hashData[i] = defiInteractionHashes[offset + i]
                mstore(0x00, add(offset, i))
                mstore(add(hashData, mul(i, 0x20)), sload(keccak256(0x00, 0x40)))
            }

            // If numPendingInteractions < NUMBER_OF_BRIDGE_CALLS, continue iterating up to NUMBER_OF_BRIDGE_CALLS, this time
            // inserting the "zero hash", the result of sha256(emptyDefiInteractionResult)
            for {} lt(i, NUMBER_OF_BRIDGE_CALLS) { i := add(i, 0x01) } {
                // hashData[i] = DEFI_RESULT_ZERO_HASH
                mstore(add(hashData, mul(i, 0x20)), DEFI_RESULT_ZERO_HASH)
            }
            pop(staticcall(gas(), 0x2, hashData, NUMBER_OF_BRIDGE_BYTES, 0x00, 0x20))
            nextExpectedHash := mod(mload(0x00), CIRCUIT_MODULUS)
        }
    }

    /**
     * @notice A function that processes bridge calls.
     * @dev 1. pop NUMBER_OF_BRIDGE_CALLS (if available) interaction hashes off of `defiInteractionHashes`,
     *         validate their hash (calculated at the end of the previous rollup and stored as
     *         nextExpectedDefiInteractionsHash) equals `numPendingInteractions` (this validates that rollup block
     *         has added these interaction results into the L2 data tree)
     *      2. iterate over rollup block's new defi interactions (up to NUMBER_OF_BRIDGE_CALLS). Trigger interactions
     *         by calling DefiBridgeProxy contract. Record results in either `defiInteractionHashes` (for synchrohnous
     *         txns) or, for async txns, the `pendingDefiInteractions` mapping
     *      3. copy the contents of `asyncInteractionHashes` into `defiInteractionHashes` && clear
     *         `asyncInteractionHashes`
     *      4. calculate the next value of nextExpectedDefiInteractionsHash from the new set of defiInteractionHashes
     * @param _proofData decoded rollup proof data
     * @param _rollupBeneficiary the address that should be paid any subsidy for processing a bridge call
     * @return nextExpectedHashes the set of non-zero hashes that comprise the current pending defi interactions
     */
    function processBridgeCalls(bytes memory _proofData, address _rollupBeneficiary)
        internal
        returns (bytes32[] memory nextExpectedHashes)
    {
        uint256 defiInteractionHashesLength;
        // Verify that nextExpectedDefiInteractionsHash equals the value given in the rollup
        // Then remove the set of pending hashes
        {
            // Extract the claimed value of previousDefiInteractionHash present in the proof data
            bytes32 providedDefiInteractionsHash = extractPrevDefiInteractionHash(_proofData);

            // Validate the stored interactionHash matches the value used when making the rollup proof!
            if (providedDefiInteractionsHash != prevDefiInteractionsHash) {
                revert INCORRECT_PREVIOUS_DEFI_INTERACTION_HASH(providedDefiInteractionsHash, prevDefiInteractionsHash);
            }
            uint256 numPendingInteractions;
            (defiInteractionHashesLength, numPendingInteractions) = getDefiHashesLengthsAndNumPendingInteractions();
            // numPendingInteraction equals the number of interactions expected to be in the given rollup
            // this is the length of the defiInteractionHashes array, capped at the NUM_BRIDGE_CALLS as per the following
            // numPendingInteractions = min(defiInteractionsHashesLength, numberOfBridgeCalls)

            // Reduce DefiInteractionHashes.length by numPendingInteractions
            defiInteractionHashesLength -= numPendingInteractions;

            assembly {
                // Update DefiInteractionHashes.length in storage
                let state := sload(rollupState.slot)
                let oldState := and(not(shl(DEFIINTERACTIONHASHES_BIT_OFFSET, ARRAY_LENGTH_MASK)), state)
                let newState := or(oldState, shl(DEFIINTERACTIONHASHES_BIT_OFFSET, defiInteractionHashesLength))
                sstore(rollupState.slot, newState)
            }
        }
        uint256 interactionNonce = getRollupId(_proofData) * NUMBER_OF_BRIDGE_CALLS;

        // ### Process bridge calls
        uint256 proofDataPtr;
        assembly {
            proofDataPtr := add(_proofData, BRIDGE_CALL_DATAS_OFFSET)
        }
        BridgeResult memory bridgeResult;
        assembly {
            bridgeResult := mload(0x40)
            mstore(0x40, add(bridgeResult, 0x80))
        }
        for (uint256 i = 0; i < NUMBER_OF_BRIDGE_CALLS;) {
            uint256 encodedBridgeCallData;
            assembly {
                encodedBridgeCallData := mload(proofDataPtr)
            }
            if (encodedBridgeCallData == 0) {
                // no more bridges to call
                break;
            }
            uint256 totalInputValue;
            assembly {
                totalInputValue := mload(add(proofDataPtr, mul(0x20, NUMBER_OF_BRIDGE_CALLS)))
            }
            if (totalInputValue == 0) {
                revert ZERO_TOTAL_INPUT_VALUE();
            }

            FullBridgeCallData memory fullBridgeCallData = getFullBridgeCallData(encodedBridgeCallData);

            (
                AztecTypes.AztecAsset memory inputAssetA,
                AztecTypes.AztecAsset memory inputAssetB,
                AztecTypes.AztecAsset memory outputAssetA,
                AztecTypes.AztecAsset memory outputAssetB
            ) = getAztecAssetTypes(fullBridgeCallData, interactionNonce);
            assembly {
                // call the following function of DefiBridgeProxy via delegatecall...
                //     function convert(
                //          address bridgeAddress,
                //          AztecTypes.AztecAsset calldata inputAssetA,
                //          AztecTypes.AztecAsset calldata inputAssetB,
                //          AztecTypes.AztecAsset calldata outputAssetA,
                //          AztecTypes.AztecAsset calldata outputAssetB,
                //          uint256 totalInputValue,
                //          uint256 interactionNonce,
                //          uint256 auxInputData,
                //          uint256 ethPaymentsSlot,
                //          address rollupBeneficary
                //     )

                // Construct the calldata we send to DefiBridgeProxy
                // mPtr = memory pointer. Set to free memory location (0x40)
                let mPtr := mload(0x40)
                // first 4 bytes is the function signature
                mstore(mPtr, DEFI_BRIDGE_PROXY_CONVERT_SELECTOR)
                mPtr := add(mPtr, 0x04)

                let bridgeAddress := mload(add(fullBridgeCallData, 0x20))
                mstore(mPtr, bridgeAddress)
                mstore(add(mPtr, 0x20), mload(inputAssetA))
                mstore(add(mPtr, 0x40), mload(add(inputAssetA, 0x20)))
                mstore(add(mPtr, 0x60), mload(add(inputAssetA, 0x40)))
                mstore(add(mPtr, 0x80), mload(inputAssetB))
                mstore(add(mPtr, 0xa0), mload(add(inputAssetB, 0x20)))
                mstore(add(mPtr, 0xc0), mload(add(inputAssetB, 0x40)))
                mstore(add(mPtr, 0xe0), mload(outputAssetA))
                mstore(add(mPtr, 0x100), mload(add(outputAssetA, 0x20)))
                mstore(add(mPtr, 0x120), mload(add(outputAssetA, 0x40)))
                mstore(add(mPtr, 0x140), mload(outputAssetB))
                mstore(add(mPtr, 0x160), mload(add(outputAssetB, 0x20)))
                mstore(add(mPtr, 0x180), mload(add(outputAssetB, 0x40)))
                mstore(add(mPtr, 0x1a0), totalInputValue)
                mstore(add(mPtr, 0x1c0), interactionNonce)

                let auxData := mload(add(fullBridgeCallData, 0xc0))
                mstore(add(mPtr, 0x1e0), auxData)
                mstore(add(mPtr, 0x200), ethPayments.slot)
                mstore(add(mPtr, 0x220), _rollupBeneficiary)

                // Call the bridge proxy via delegatecall!
                // We want the proxy to share state with the rollup processor, as the proxy is the entity
                // sending/recovering tokens from the bridge contracts. We wrap this logic in a delegatecall so that
                // if the call fails (i.e. the bridge interaction fails), we can unwind bridge-interaction specific
                // state changes without reverting the entire transaction.
                let bridgeProxy := sload(defiBridgeProxy.slot)
                if iszero(extcodesize(bridgeProxy)) {
                    mstore(0, INVALID_ADDRESS_NO_CODE_SELECTOR)
                    revert(0, 0x4)
                }
                let success :=
                    delegatecall(
                        mload(add(fullBridgeCallData, 0x1a0)), // fullBridgeCallData.bridgeGasLimit
                        bridgeProxy,
                        sub(mPtr, 0x04),
                        0x244,
                        0,
                        0
                    )
                returndatacopy(mPtr, 0, returndatasize())

                switch success
                case 1 {
                    mstore(bridgeResult, mload(mPtr)) // outputValueA
                    mstore(add(bridgeResult, 0x20), mload(add(mPtr, 0x20))) // outputValueB
                    mstore(add(bridgeResult, 0x40), mload(add(mPtr, 0x40))) // isAsync
                    mstore(add(bridgeResult, 0x60), 1) // success
                }
                default {
                    // If the call failed, mark this interaction as failed. No tokens have been exchanged, users can
                    // use the "claim" circuit to recover the initial tokens they sent to the bridge
                    mstore(bridgeResult, 0) // outputValueA
                    mstore(add(bridgeResult, 0x20), 0) // outputValueB
                    mstore(add(bridgeResult, 0x40), 0) // isAsync
                    mstore(add(bridgeResult, 0x60), 0) // success
                }
            }

            if (!fullBridgeCallData.secondOutputInUse) {
                bridgeResult.outputValueB = 0;
            }

            // emit events and update state
            assembly {
                // if interaction is Async, update pendingDefiInteractions
                // if interaction is synchronous, compute the interaction hash and add to defiInteractionHashes
                switch mload(add(bridgeResult, 0x40))
                // switch isAsync
                case 1 {
                    let mPtr := mload(0x40)
                    // emit AsyncDefiBridgeProcessed(indexed encodedBridgeCallData, indexed interactionNonce, totalInputValue)
                    {
                        mstore(mPtr, totalInputValue)
                        log3(mPtr, 0x20, ASYNC_BRIDGE_PROCESSED_SIGHASH, encodedBridgeCallData, interactionNonce)
                    }
                    // pendingDefiInteractions[interactionNonce] = PendingDefiBridgeInteraction(encodedBridgeCallData, totalInputValue)
                    mstore(0x00, interactionNonce)
                    mstore(0x20, pendingDefiInteractions.slot)
                    let pendingDefiInteractionsSlotBase := keccak256(0x00, 0x40)

                    sstore(pendingDefiInteractionsSlotBase, encodedBridgeCallData)
                    sstore(add(pendingDefiInteractionsSlotBase, 0x01), totalInputValue)
                }
                default {
                    let mPtr := mload(0x40)
                    // prepare the data required to publish the DefiBridgeProcessed event, we will only publish it if
                    // isAsync == false
                    // async interactions that have failed, have their isAsync property modified to false above
                    // emit DefiBridgeProcessed(indexed encodedBridgeCallData, indexed interactionNonce, totalInputValue, outputValueA, outputValueB, success)

                    {
                        mstore(mPtr, totalInputValue)
                        mstore(add(mPtr, 0x20), mload(bridgeResult)) // outputValueA
                        mstore(add(mPtr, 0x40), mload(add(bridgeResult, 0x20))) // outputValueB
                        mstore(add(mPtr, 0x60), mload(add(bridgeResult, 0x60))) // success
                        mstore(add(mPtr, 0x80), 0xa0) // position in event data block of `bytes` object

                        if mload(add(bridgeResult, 0x60)) {
                            mstore(add(mPtr, 0xa0), 0)
                            log3(mPtr, 0xc0, DEFI_BRIDGE_PROCESSED_SIGHASH, encodedBridgeCallData, interactionNonce)
                        }
                        if iszero(mload(add(bridgeResult, 0x60))) {
                            mstore(add(mPtr, 0xa0), returndatasize())
                            let size := returndatasize()
                            let remainder := mul(iszero(iszero(size)), sub(32, mod(size, 32)))
                            returndatacopy(add(mPtr, 0xc0), 0, size)
                            mstore(add(mPtr, add(0xc0, size)), 0)
                            log3(
                                mPtr,
                                add(0xc0, add(size, remainder)),
                                DEFI_BRIDGE_PROCESSED_SIGHASH,
                                encodedBridgeCallData,
                                interactionNonce
                            )
                        }
                    }
                    // compute defiInteractionnHash
                    mstore(mPtr, encodedBridgeCallData)
                    mstore(add(mPtr, 0x20), interactionNonce)
                    mstore(add(mPtr, 0x40), totalInputValue)
                    mstore(add(mPtr, 0x60), mload(bridgeResult)) // outputValueA
                    mstore(add(mPtr, 0x80), mload(add(bridgeResult, 0x20))) // outputValueB
                    mstore(add(mPtr, 0xa0), mload(add(bridgeResult, 0x60))) // success
                    pop(staticcall(gas(), 0x2, mPtr, 0xc0, 0x00, 0x20))
                    let defiInteractionHash := mod(mload(0x00), CIRCUIT_MODULUS)

                    // defiInteractionHashes[defiInteractionHashesLength] = defiInteractionHash;
                    mstore(0x00, defiInteractionHashesLength)
                    mstore(0x20, defiInteractionHashes.slot)
                    sstore(keccak256(0x00, 0x40), defiInteractionHash)

                    // Increase the length of defiInteractionHashes by 1
                    defiInteractionHashesLength := add(defiInteractionHashesLength, 0x01)
                }

                // advance interactionNonce and proofDataPtr
                interactionNonce := add(interactionNonce, 0x01)
                proofDataPtr := add(proofDataPtr, 0x20)
            }
            unchecked {
                ++i;
            }
        }

        assembly {
            /**
             * Cleanup
             *
             * 1. Copy asyncDefiInteractionHashes into defiInteractionHashes
             * 2. Update defiInteractionHashes.length
             * 2. Clear asyncDefiInteractionHashes.length
             */
            let state := sload(rollupState.slot)

            let asyncDefiInteractionHashesLength :=
                and(ARRAY_LENGTH_MASK, shr(ASYNCDEFIINTERACTIONHASHES_BIT_OFFSET, state))

            // Validate we are not overflowing our 1024 array size
            let arrayOverflow :=
                gt(add(asyncDefiInteractionHashesLength, defiInteractionHashesLength), ARRAY_LENGTH_MASK)

            // Throw an error if defiInteractionHashesLength > ARRAY_LENGTH_MASK (i.e. is >= 1024)
            // should never hit this! If block `i` generates synchronous txns,
            // block 'i + 1' must process them.
            // Only way this array size hits 1024 is if we produce a glut of async interaction results
            // between blocks. HOWEVER we ensure that async interaction callbacks fail if they would increase
            // defiInteractionHashes length to be >= 512
            // Still, can't hurt to check...
            if arrayOverflow {
                mstore(0, ARRAY_OVERFLOW_SELECTOR)
                revert(0, 0x4)
            }

            // Now, copy async hashes into defiInteractionHashes

            // Cache the free memory pointer
            let freePtr := mload(0x40)

            // Prepare the reusable parts of slot computation
            mstore(0x20, defiInteractionHashes.slot)
            mstore(0x60, asyncDefiInteractionHashes.slot)
            for { let i := 0 } lt(i, asyncDefiInteractionHashesLength) { i := add(i, 1) } {
                // defiInteractionHashesLength[defiInteractionHashesLength + i] = asyncDefiInteractionHashes[i]
                mstore(0x00, add(defiInteractionHashesLength, i))
                mstore(0x40, i)
                sstore(keccak256(0x00, 0x40), sload(keccak256(0x40, 0x40)))
            }
            // Restore the free memory pointer
            mstore(0x40, freePtr)

            // clear defiInteractionHashesLength in state
            state := and(not(shl(DEFIINTERACTIONHASHES_BIT_OFFSET, ARRAY_LENGTH_MASK)), state)

            // write new defiInteractionHashesLength in state
            state :=
                or(
                    shl(
                        DEFIINTERACTIONHASHES_BIT_OFFSET, add(asyncDefiInteractionHashesLength, defiInteractionHashesLength)
                    ),
                    state
                )

            // clear asyncDefiInteractionHashesLength in state
            state := and(not(shl(ASYNCDEFIINTERACTIONHASHES_BIT_OFFSET, ARRAY_LENGTH_MASK)), state)

            // write new state
            sstore(rollupState.slot, state)
        }

        // now we want to extract the next set of pending defi interaction hashes and calculate their hash to store
        // for the next rollup
        (bytes32[] memory hashes, bytes32 nextExpectedHash) = getPendingAndNextExpectedHashes();
        nextExpectedHashes = hashes;
        prevDefiInteractionsHash = nextExpectedHash;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/AccessControl.sol)

pragma solidity ^0.8.0;

import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `_msgSender()` is missing `role`.
     * Overriding this function changes the behavior of the {onlyRole} modifier.
     *
     * Format of the revert message is described in {_checkRole}.
     *
     * _Available since v4.6._
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(account),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * May emit a {RoleGranted} event.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator,
        Rounding rounding
    ) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10**64) {
                value /= 10**64;
                result += 64;
            }
            if (value >= 10**32) {
                value /= 10**32;
                result += 32;
            }
            if (value >= 10**16) {
                value /= 10**16;
                result += 16;
            }
            if (value >= 10**8) {
                value /= 10**8;
                result += 8;
            }
            if (value >= 10**4) {
                value /= 10**4;
                result += 4;
            }
            if (value >= 10**2) {
                value /= 10**2;
                result += 2;
            }
            if (value >= 10**1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: setting the version to 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized != type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Internal function that returns the initialized version. Returns `_initialized`
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Internal function that returns the initialized version. Returns `_initializing`
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}

// 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 AddressUpgradeable {
    /**
     * @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://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.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 functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

// SPDX-License-Identifier: 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 {
    /*----------------------------------------
      MUTATING FUNCTIONS
      ----------------------------------------*/

    function pause() external;

    function unpause() external;

    function setRollupProvider(address _provider, bool _valid) external;

    function setVerifier(address _verifier) external;

    function setAllowThirdPartyContracts(bool _allowThirdPartyContracts) external;

    function setDefiBridgeProxy(address _defiBridgeProxy) external;

    function setSupportedAsset(address _token, uint256 _gasLimit) external;

    function setSupportedBridge(address _bridge, uint256 _gasLimit) external;

    function processRollup(bytes calldata _encodedProofData, bytes calldata _signatures) external;

    function receiveEthFromBridge(uint256 _interactionNonce) external payable;

    function approveProof(bytes32 _proofHash) external;

    function depositPendingFunds(uint256 _assetId, uint256 _amount, address _owner, bytes32 _proofHash)
        external
        payable;

    function offchainData(uint256 _rollupId, uint256 _chunk, uint256 _totalChunks, bytes calldata _offchainTxData)
        external;

    function processAsyncDefiInteraction(uint256 _interactionNonce) external returns (bool);

    /*----------------------------------------
      NON-MUTATING FUNCTIONS
      ----------------------------------------*/

    function rollupStateHash() external view returns (bytes32);

    function userPendingDeposits(uint256 _assetId, address _user) external view returns (uint256);

    function defiBridgeProxy() external view returns (address);

    function prevDefiInteractionsHash() external view returns (bytes32);

    function paused() external view returns (bool);

    function verifier() external view returns (address);

    function getDataSize() external view returns (uint256);

    function getPendingDefiInteractionHashesLength() external view returns (uint256);

    function getDefiInteractionHashesLength() external view returns (uint256);

    function getAsyncDefiInteractionHashesLength() external view returns (uint256);

    function getSupportedBridge(uint256 _bridgeAddressId) external view returns (address);

    function getSupportedBridgesLength() external view returns (uint256);

    function getSupportedAssetsLength() external view returns (uint256);

    function getSupportedAsset(uint256 _assetId) external view returns (address);

    function getEscapeHatchStatus() external view returns (bool, uint256);

    function assetGasLimits(uint256 _bridgeAddressId) external view returns (uint256);

    function bridgeGasLimits(uint256 _bridgeAddressId) external view returns (uint256);

    function allowThirdPartyContracts() external view returns (bool);
}

// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec
pragma solidity >=0.8.4;

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

// @dev For documentation of the functions within this interface see RollupProcessorV2 contract
interface IRollupProcessorV2 is IRollupProcessor {
    function getCapped() external view returns (bool);

    function defiInteractionHashes(uint256) external view returns (bytes32);
}

File 14 of 20 : 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;
    }
}

// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec
pragma solidity >=0.8.4;

library RollupProcessorLibrary {
    error SIGNATURE_ADDRESS_IS_ZERO();
    error SIGNATURE_RECOVERY_FAILED();
    error INVALID_SIGNATURE();

    /**
     * Extracts the address of the signer with ECDSA. Performs checks on `s` and `v` to
     * to prevent signature malleability based attacks
     * @param digest - Hashed data being signed over.
     * @param signature - ECDSA signature over the secp256k1 elliptic curve.
     * @param signer - Address that signs the signature.
     */
    function validateSignature(bytes32 digest, bytes memory signature, address signer) internal view {
        bool result;
        address recoveredSigner = address(0x0);
        if (signer == address(0x0)) {
            revert SIGNATURE_ADDRESS_IS_ZERO();
        }

        // prepend "\x19Ethereum Signed Message:\n32" to the digest to create the signed message
        bytes32 message;
        assembly {
            mstore(0, "\x19Ethereum Signed Message:\n32")
            mstore(add(0, 28), digest)
            message := keccak256(0, 60)
        }
        assembly {
            let mPtr := mload(0x40)
            let byteLength := mload(signature)

            // store the signature digest
            mstore(mPtr, message)

            // load 'v' - we need it for a condition check
            // add 0x60 to jump over 3 words - length of bytes array, r and s
            let v := shr(248, mload(add(signature, 0x60))) // bitshifting, to resemble padLeft
            let s := mload(add(signature, 0x40))

            /**
             * Original memory map for input to precompile
             *
             * signature : signature + 0x20            message
             * signature + 0x20 : signature + 0x40     r
             * signature + 0x40 : signature + 0x60     s
             * signature + 0x60 : signature + 0x80     v
             * Desired memory map for input to precompile
             *
             * signature : signature + 0x20            message
             * signature + 0x20 : signature + 0x40     v
             * signature + 0x40 : signature + 0x60     r
             * signature + 0x60 : signature + 0x80     s
             */

            // store s
            mstore(add(mPtr, 0x60), s)
            // store r
            mstore(add(mPtr, 0x40), mload(add(signature, 0x20)))
            // store v
            mstore(add(mPtr, 0x20), v)
            result :=
                and(
                    and(
                        // validate s is in lower half order
                        lt(s, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A1),
                        and(
                            // validate signature length == 0x41
                            eq(byteLength, 0x41),
                            // validate v == 27 or v == 28
                            or(eq(v, 27), eq(v, 28))
                        )
                    ),
                    // validate call to ecrecover precompile succeeds
                    staticcall(gas(), 0x01, mPtr, 0x80, mPtr, 0x20)
                )

            // save the recoveredSigner only if the first word in signature is not `message` anymore
            switch eq(message, mload(mPtr))
            case 0 { recoveredSigner := mload(mPtr) }
            mstore(mPtr, byteLength) // and put the byte length back where it belongs

            // validate that recoveredSigner is not address(0x00)
            result := and(result, not(iszero(recoveredSigner)))
        }
        if (!result) {
            revert SIGNATURE_RECOVERY_FAILED();
        }
        if (recoveredSigner != signer) {
            revert INVALID_SIGNATURE();
        }
    }

    /**
     * Extracts the address of the signer with ECDSA. Performs checks on `s` and `v` to
     * to prevent signature malleability based attacks
     * This 'Unpacked' version expects 'signature' to be a 96-byte array.
     * i.e. the `v` parameter occupies a full 32 bytes of memory, not 1 byte
     * @param hashedMessage - Hashed data being signed over. This function only works if the message has been pre formated to EIP https://eips.ethereum.org/EIPS/eip-191
     * @param signature - ECDSA signature over the secp256k1 elliptic curve.
     * @param signer - Address that signs the signature.
     */
    function validateShieldSignatureUnpacked(bytes32 hashedMessage, bytes memory signature, address signer)
        internal
        view
    {
        bool result;
        address recoveredSigner = address(0x0);
        if (signer == address(0x0)) {
            revert SIGNATURE_ADDRESS_IS_ZERO();
        }
        assembly {
            // There's a little trick we can pull. We expect `signature` to be a byte array, of length 0x60, with
            // 'v', 'r' and 's' located linearly in memory. Preceeding this is the length parameter of `signature`.
            // We *replace* the length param with the signature msg to get a memory block formatted for the precompile
            // load length as a temporary variable
            // N.B. we mutate the signature by re-ordering r, s, and v!
            let byteLength := mload(signature)

            // store the signature digest
            mstore(signature, hashedMessage)

            // load 'v' - we need it for a condition check
            // add 0x60 to jump over 3 words - length of bytes array, r and s
            let v := mload(add(signature, 0x60))
            let s := mload(add(signature, 0x40))

            /**
             * Original memory map for input to precompile
             *
             * signature : signature + 0x20            message
             * signature + 0x20 : signature + 0x40     r
             * signature + 0x40 : signature + 0x60     s
             * signature + 0x60 : signature + 0x80     v
             * Desired memory map for input to precompile
             *
             * signature : signature + 0x20            message
             * signature + 0x20 : signature + 0x40     v
             * signature + 0x40 : signature + 0x60     r
             * signature + 0x60 : signature + 0x80     s
             */

            // move s to v position
            mstore(add(signature, 0x60), s)
            // move r to s position
            mstore(add(signature, 0x40), mload(add(signature, 0x20)))
            // move v to r position
            mstore(add(signature, 0x20), v)
            result :=
                and(
                    and(
                        // validate s is in lower half order
                        lt(s, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A1),
                        and(
                            // validate signature length == 0x60 (unpacked)
                            eq(byteLength, 0x60),
                            // validate v == 27 or v == 28
                            or(eq(v, 27), eq(v, 28))
                        )
                    ),
                    // validate call to ecrecover precompile succeeds
                    staticcall(gas(), 0x01, signature, 0x80, signature, 0x20)
                )

            // save the recoveredSigner only if the first word in signature is not `message` anymore
            switch eq(hashedMessage, mload(signature))
            case 0 { recoveredSigner := mload(signature) }
            mstore(signature, byteLength) // and put the byte length back where it belongs

            // validate that recoveredSigner is not address(0x00)
            result := and(result, not(iszero(recoveredSigner)))
        }
        if (!result) {
            revert SIGNATURE_RECOVERY_FAILED();
        }
        if (recoveredSigner != signer) {
            revert INVALID_SIGNATURE();
        }
    }

    /**
     * Extracts the address of the signer with ECDSA. Performs checks on `s` and `v` to
     * to prevent signature malleability based attacks
     * This 'Unpacked' version expects 'signature' to be a 96-byte array.
     * i.e. the `v` parameter occupies a full 32 bytes of memory, not 1 byte
     * @param digest - Hashed data being signed over.
     * @param signature - ECDSA signature over the secp256k1 elliptic curve.
     * @param signer - Address that signs the signature.
     */
    function validateUnpackedSignature(bytes32 digest, bytes memory signature, address signer) internal view {
        bool result;
        address recoveredSigner = address(0x0);
        if (signer == address(0x0)) {
            revert SIGNATURE_ADDRESS_IS_ZERO();
        }

        // prepend "\x19Ethereum Signed Message:\n32" to the digest to create the signed message
        bytes32 message;
        assembly {
            mstore(0, "\x19Ethereum Signed Message:\n32")
            mstore(28, digest)
            message := keccak256(0, 60)
        }
        assembly {
            // There's a little trick we can pull. We expect `signature` to be a byte array, of length 0x60, with
            // 'v', 'r' and 's' located linearly in memory. Preceeding this is the length parameter of `signature`.
            // We *replace* the length param with the signature msg to get a memory block formatted for the precompile
            // load length as a temporary variable
            // N.B. we mutate the signature by re-ordering r, s, and v!
            let byteLength := mload(signature)

            // store the signature digest
            mstore(signature, message)

            // load 'v' - we need it for a condition check
            // add 0x60 to jump over 3 words - length of bytes array, r and s
            let v := mload(add(signature, 0x60))
            let s := mload(add(signature, 0x40))

            /**
             * Original memory map for input to precompile
             *
             * signature : signature + 0x20            message
             * signature + 0x20 : signature + 0x40     r
             * signature + 0x40 : signature + 0x60     s
             * signature + 0x60 : signature + 0x80     v
             * Desired memory map for input to precompile
             *
             * signature : signature + 0x20            message
             * signature + 0x20 : signature + 0x40     v
             * signature + 0x40 : signature + 0x60     r
             * signature + 0x60 : signature + 0x80     s
             */

            // move s to v position
            mstore(add(signature, 0x60), s)
            // move r to s position
            mstore(add(signature, 0x40), mload(add(signature, 0x20)))
            // move v to r position
            mstore(add(signature, 0x20), v)
            result :=
                and(
                    and(
                        // validate s is in lower half order
                        lt(s, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A1),
                        and(
                            // validate signature length == 0x60 (unpacked)
                            eq(byteLength, 0x60),
                            // validate v == 27 or v == 28
                            or(eq(v, 27), eq(v, 28))
                        )
                    ),
                    // validate call to ecrecover precompile succeeds
                    staticcall(gas(), 0x01, signature, 0x80, signature, 0x20)
                )

            // save the recoveredSigner only if the first word in signature is not `message` anymore
            switch eq(message, mload(signature))
            case 0 { recoveredSigner := mload(signature) }
            mstore(signature, byteLength) // and put the byte length back where it belongs

            // validate that recoveredSigner is not address(0x00)
            result := and(result, not(iszero(recoveredSigner)))
        }
        if (!result) {
            revert SIGNATURE_RECOVERY_FAILED();
        }
        if (recoveredSigner != signer) {
            revert INVALID_SIGNATURE();
        }
    }

    /**
     * Convert a bytes32 into an ASCII encoded hex string
     * @param input bytes32 variable
     * @return result hex-encoded string
     */
    function toHexString(bytes32 input) public pure returns (string memory result) {
        if (uint256(input) == 0x00) {
            assembly {
                result := mload(0x40)
                mstore(result, 0x40)
                mstore(add(result, 0x20), 0x3030303030303030303030303030303030303030303030303030303030303030)
                mstore(add(result, 0x40), 0x3030303030303030303030303030303030303030303030303030303030303030)
                mstore(0x40, add(result, 0x60))
            }
            return result;
        }
        assembly {
            result := mload(0x40)
            let table := add(result, 0x60)

            // Store lookup table that maps an integer from 0 to 99 into a 2-byte ASCII equivalent
            // Store lookup table that maps an integer from 0 to ff into a 2-byte ASCII equivalent
            mstore(add(table, 0x1e), 0x3030303130323033303430353036303730383039306130623063306430653066)
            mstore(add(table, 0x3e), 0x3130313131323133313431353136313731383139316131623163316431653166)
            mstore(add(table, 0x5e), 0x3230323132323233323432353236323732383239326132623263326432653266)
            mstore(add(table, 0x7e), 0x3330333133323333333433353336333733383339336133623363336433653366)
            mstore(add(table, 0x9e), 0x3430343134323433343434353436343734383439346134623463346434653466)
            mstore(add(table, 0xbe), 0x3530353135323533353435353536353735383539356135623563356435653566)
            mstore(add(table, 0xde), 0x3630363136323633363436353636363736383639366136623663366436653666)
            mstore(add(table, 0xfe), 0x3730373137323733373437353736373737383739376137623763376437653766)
            mstore(add(table, 0x11e), 0x3830383138323833383438353836383738383839386138623863386438653866)
            mstore(add(table, 0x13e), 0x3930393139323933393439353936393739383939396139623963396439653966)
            mstore(add(table, 0x15e), 0x6130613161326133613461356136613761386139616161626163616461656166)
            mstore(add(table, 0x17e), 0x6230623162326233623462356236623762386239626162626263626462656266)
            mstore(add(table, 0x19e), 0x6330633163326333633463356336633763386339636163626363636463656366)
            mstore(add(table, 0x1be), 0x6430643164326433643464356436643764386439646164626463646464656466)
            mstore(add(table, 0x1de), 0x6530653165326533653465356536653765386539656165626563656465656566)
            mstore(add(table, 0x1fe), 0x6630663166326633663466356636663766386639666166626663666466656666)
            /**
             * Convert `input` into ASCII.
             *
             * Slice 2 base-10  digits off of the input, use to index the ASCII lookup table.
             *
             * We start from the least significant digits, write results into mem backwards,
             * this prevents us from overwriting memory despite the fact that each mload
             * only contains 2 byteso f useful data.
             *
             */

            let base := input
            function slice(v, tableptr) {
                mstore(0x1e, mload(add(tableptr, shl(1, and(v, 0xff)))))
                mstore(0x1c, mload(add(tableptr, shl(1, and(shr(8, v), 0xff)))))
                mstore(0x1a, mload(add(tableptr, shl(1, and(shr(16, v), 0xff)))))
                mstore(0x18, mload(add(tableptr, shl(1, and(shr(24, v), 0xff)))))
                mstore(0x16, mload(add(tableptr, shl(1, and(shr(32, v), 0xff)))))
                mstore(0x14, mload(add(tableptr, shl(1, and(shr(40, v), 0xff)))))
                mstore(0x12, mload(add(tableptr, shl(1, and(shr(48, v), 0xff)))))
                mstore(0x10, mload(add(tableptr, shl(1, and(shr(56, v), 0xff)))))
                mstore(0x0e, mload(add(tableptr, shl(1, and(shr(64, v), 0xff)))))
                mstore(0x0c, mload(add(tableptr, shl(1, and(shr(72, v), 0xff)))))
                mstore(0x0a, mload(add(tableptr, shl(1, and(shr(80, v), 0xff)))))
                mstore(0x08, mload(add(tableptr, shl(1, and(shr(88, v), 0xff)))))
                mstore(0x06, mload(add(tableptr, shl(1, and(shr(96, v), 0xff)))))
                mstore(0x04, mload(add(tableptr, shl(1, and(shr(104, v), 0xff)))))
                mstore(0x02, mload(add(tableptr, shl(1, and(shr(112, v), 0xff)))))
                mstore(0x00, mload(add(tableptr, shl(1, and(shr(120, v), 0xff)))))
            }

            mstore(result, 0x40)
            slice(base, table)
            mstore(add(result, 0x40), mload(0x1e))
            base := shr(128, base)
            slice(base, table)
            mstore(add(result, 0x20), mload(0x1e))
            mstore(0x40, add(result, 0x60))
        }
    }

    function getSignedMessageForTxId(bytes32 txId) internal pure returns (bytes32 hashedMessage) {
        // we know this string length is 64 bytes
        string memory txIdHexString = toHexString(txId);

        assembly {
            let mPtr := mload(0x40)
            mstore(add(mPtr, 32), "\x19Ethereum Signed Message:\n210")
            mstore(add(mPtr, 61), "Signing this message will allow ")
            mstore(add(mPtr, 93), "your pending funds to be spent i")
            mstore(add(mPtr, 125), "n Aztec transaction:\n\n0x")
            mstore(add(mPtr, 149), mload(add(txIdHexString, 0x20)))
            mstore(add(mPtr, 181), mload(add(txIdHexString, 0x40)))
            mstore(add(mPtr, 213), "\n\nIMPORTANT: Only sign the messa")
            mstore(add(mPtr, 245), "ge if you trust the client")
            hashedMessage := keccak256(add(mPtr, 32), 239)
        }
    }
}

// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec
pragma solidity >=0.8.4;

/**
 * ----------------------------------------
 *  PROOF DATA SPECIFICATION
 * ----------------------------------------
 * Our input "proof data" is represented as a single byte array - we use custom encoding to encode the
 * data associated with a rollup block. The encoded structure is as follows (excluding the length param of the bytes type):
 *
 *    | byte range      | num bytes        | name                             | description |
 *    | ---             | ---              | ---                              | ---         |
 *    | 0x00  - 0x20    | 32               | rollupId                         | Unique rollup block identifier. Equivalent to block number |
 *    | 0x20  - 0x40    | 32               | rollupSize                       | Max number of transactions in the block |
 *    | 0x40  - 0x60    | 32               | dataStartIndex                   | Position of the next empty slot in the Aztec data tree |
 *    | 0x60  - 0x80    | 32               | oldDataRoot                      | Root of the data tree prior to rollup block's state updates |
 *    | 0x80  - 0xa0    | 32               | newDataRoot                      | Root of the data tree after rollup block's state updates |
 *    | 0xa0  - 0xc0    | 32               | oldNullRoot                      | Root of the nullifier tree prior to rollup block's state updates |
 *    | 0xc0  - 0xe0    | 32               | newNullRoot                      | Root of the nullifier tree after rollup block's state updates |
 *    | 0xe0  - 0x100   | 32               | oldDataRootsRoot                 | Root of the tree of data tree roots prior to rollup block's state updates |
 *    | 0x100 - 0x120   | 32               | newDataRootsRoot                 | Root of the tree of data tree roots after rollup block's state updates |
 *    | 0x120 - 0x140   | 32               | oldDefiRoot                      | Root of the defi tree prior to rollup block's state updates |
 *    | 0x140 - 0x160   | 32               | newDefiRoot                      | Root of the defi tree after rollup block's state updates |
 *    | 0x160 - 0x560   | 1024             | encodedBridgeCallDatas[NUMBER_OF_BRIDGE_CALLS]   | Size-32 array of encodedBridgeCallDatas for bridges being called in this block. If encodedBridgeCallData == 0, no bridge is called |
 *    | 0x560 - 0x960   | 1024             | depositSums[NUMBER_OF_BRIDGE_CALLS] | Size-32 array of deposit values being sent to bridges which are called in this block |
 *    | 0x960 - 0xb60   | 512              | assetIds[NUMBER_OF_ASSETS]         | Size-16 array of assetIds which correspond to assets being used to pay fees in this block |
 *    | 0xb60 - 0xd60   | 512              | txFees[NUMBER_OF_ASSETS]           | Size-16 array of transaction fees paid to the rollup beneficiary, denominated in each assetId |
 *    | 0xd60 - 0x1160  | 1024             | interactionNotes[NUMBER_OF_BRIDGE_CALLS] | Size-32 array of defi interaction result commitments that must be inserted into the defi tree at this rollup block |
 *    | 0x1160 - 0x1180 | 32               | prevDefiInteractionHash          | A SHA256 hash of the data used to create each interaction result commitment. Used to validate correctness of interactionNotes |
 *    | 0x1180 - 0x11a0 | 32               | rollupBeneficiary                | The address that the fees from this rollup block should be sent to. Prevents a rollup proof being taken from the transaction pool and having its fees redirected |
 *    | 0x11a0 - 0x11c0 | 32               | numRollupTxs                     | Number of "inner rollup" proofs used to create the block proof. "inner rollup" circuits process 3-28 user txns, the outer rollup circuit processes 1-28 inner rollup proofs. |
 *    | 0x11c0 - 0x11c4 | 4                | numRealTxs                       | Number of transactions in the rollup excluding right-padded padding proofs |
 *    | 0x11c4 - 0x11c8 | 4                | encodedInnerTxData.length        | Number of bytes of encodedInnerTxData |
 *    | 0x11c8 - end    | encodedInnerTxData.length | encodedInnerTxData      | Encoded inner transaction data. Contains encoded form of the broadcasted data associated with each tx in the rollup block |
 *
 */

/**
 * --------------------------------------------
 *  DETERMINING THE NUMBER OF REAL TRANSACTIONS
 * --------------------------------------------
 * The `rollupSize` parameter describes the MAX number of txns in a block.
 * However the block may not be full.
 * Incomplete blocks will be padded with "padding" transactions that represent empty txns.
 *
 * The amount of end padding is not explicitly defined in `proofData`. It is derived.
 * The encodedInnerTxData does not include tx data for the txns associated with this end padding.
 * (it does include any padding transactions that are not part of the end padding, which can sometimes happen)
 * When decoded, the transaction data for each transaction is a fixed size (256 bytes)
 * Number of real transactions = rollupSize - (decoded tx data size / 256)
 *
 * The decoded transaction data associated with padding transactions is 256 zero bytes.
 *
 */

/**
 * @title Decoder
 * @dev contains functions for decoding/extracting the encoded proof data passed in as calldata,
 * as well as computing the SHA256 hash of the decoded data (publicInputsHash).
 * The publicInputsHash is used to ensure the data passed in as calldata matches the data used within the rollup circuit
 */
contract Decoder {
    /*----------------------------------------
      CONSTANTS
      ----------------------------------------*/
    uint256 internal constant NUMBER_OF_ASSETS = 16; // max number of assets in a block
    uint256 internal constant NUMBER_OF_BRIDGE_CALLS = 32; // max number of bridge calls in a block
    uint256 internal constant NUMBER_OF_BRIDGE_BYTES = 1024; // NUMBER_OF_BRIDGE_CALLS * 32
    uint256 internal constant NUMBER_OF_PUBLIC_INPUTS_PER_TX = 8; // number of ZK-SNARK "public inputs" per join-split/account/claim transaction
    uint256 internal constant TX_PUBLIC_INPUT_LENGTH = 256; // byte-length of NUMBER_OF_PUBLIC_INPUTS_PER_TX. NUMBER_OF_PUBLIC_INPUTS_PER_TX * 32;
    uint256 internal constant ROLLUP_NUM_HEADER_INPUTS = 142; // 58; // number of ZK-SNARK "public inputs" that make up the rollup header 14 + (NUMBER_OF_BRIDGE_CALLS * 3) + (NUMBER_OF_ASSETS * 2);
    uint256 internal constant ROLLUP_HEADER_LENGTH = 4544; // 1856; // ROLLUP_NUM_HEADER_INPUTS * 32;

    // ENCODED_PROOF_DATA_LENGTH_OFFSET = byte offset into the rollup header such that `numRealTransactions` occupies
    // the least significant 4 bytes of the 32-byte word being pointed to.
    // i.e. ROLLUP_HEADER_LENGTH - 28
    uint256 internal constant NUM_REAL_TRANSACTIONS_OFFSET = 4516;

    // ENCODED_PROOF_DATA_LENGTH_OFFSET = byte offset into the rollup header such that `encodedInnerProofData.length` occupies
    // the least significant 4 bytes of the 32-byte word being pointed to.
    // i.e. ROLLUP_HEADER_LENGTH - 24
    uint256 internal constant ENCODED_PROOF_DATA_LENGTH_OFFSET = 4520;

    // offset we add to `proofData` to point to the encodedBridgeCallDatas
    uint256 internal constant BRIDGE_CALL_DATAS_OFFSET = 0x180;

    // offset we add to `proofData` to point to prevDefiInteractionhash
    uint256 internal constant PREVIOUS_DEFI_INTERACTION_HASH_OFFSET = 4480; // ROLLUP_HEADER_LENGTH - 0x40

    // offset we add to `proofData` to point to rollupBeneficiary
    uint256 internal constant ROLLUP_BENEFICIARY_OFFSET = 4512; // ROLLUP_HEADER_LENGTH - 0x20

    // CIRCUIT_MODULUS = group order of the BN254 elliptic curve. All arithmetic gates in our ZK-SNARK circuits are evaluated modulo this prime.
    // Is used when computing the public inputs hash - our SHA256 hash outputs are reduced modulo CIRCUIT_MODULUS
    uint256 internal constant CIRCUIT_MODULUS =
        21888242871839275222246405745257275088548364400416034343698204186575808495617;

    // SHA256 hashes
    uint256 internal constant PADDING_ROLLUP_HASH_SIZE_1 =
        0x22dd983f8337d97d56071f7986209ab2ee6039a422242e89126701c6ee005af0;
    uint256 internal constant PADDING_ROLLUP_HASH_SIZE_2 =
        0x076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f36560;
    uint256 internal constant PADDING_ROLLUP_HASH_SIZE_4 =
        0x2f0c70a5bf5460465e9902f9c96be324e8064e762a5de52589fdb97cbce3c6ee;
    uint256 internal constant PADDING_ROLLUP_HASH_SIZE_8 =
        0x240ed0de145447ff0ceff2aa477f43e0e2ed7f3543ee3d8832f158ec76b183a9;
    uint256 internal constant PADDING_ROLLUP_HASH_SIZE_16 =
        0x1c52c159b4dae66c3dcf33b44d4d61ead6bc4d260f882ac6ba34dccf78892ca4;
    uint256 internal constant PADDING_ROLLUP_HASH_SIZE_32 =
        0x0df0e06ab8a02ce2ff08babd7144ab23ca2e99ddf318080cf88602eeb8913d44;
    uint256 internal constant PADDING_ROLLUP_HASH_SIZE_64 =
        0x1f83672815ac9b3ca31732d641784035834e96b269eaf6a2e759bf4fcc8e5bfd;

    uint256 internal constant ADDRESS_MASK = 0x00_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff;

    /*----------------------------------------
      ERROR TAGS
      ----------------------------------------*/
    error ENCODING_BYTE_INVALID();
    error INVALID_ROLLUP_TOPOLOGY();

    /*----------------------------------------
      DECODING FUNCTIONS
      ----------------------------------------*/
    /**
     * In `bytes proofData`, transaction data is appended after the rollup header data
     * Each transaction is described by 8 'public inputs' used to create a user transaction's ZK-SNARK proof
     * (i.e. there are 8 public inputs for each of the "join-split", "account" and "claim" circuits)
     * The public inputs are represented in calldata according to the following specification:
     *
     * | public input idx | calldata size (bytes) | variable description                         |
     * | 0                | 1                     | proofId - transaction type identifier        |
     * | 1                | 32                    | encrypted form of 1st output note            |
     * | 2                | 32                    | encrypted form of 2nd output note            |
     * | 3                | 32                    | nullifier of 1st input note                  |
     * | 4                | 32                    | nullifier of 2nd input note                  |
     * | 5                | 32                    | amount being deposited or withdrawn          |
     * | 6                | 20                    | address of depositor or withdraw destination |
     * | 7                | 4                     | assetId used in transaction                  |
     *
     * The following table maps proofId values to transaction types
     *
     *
     * | proofId | tx type     | description |
     * | ---     | ---         | ---         |
     * | 0       | padding     | empty transaction. Rollup blocks have a fixed number of txns. If number of real txns is less than block size, padding txns make up the difference |
     * | 1       | deposit     | deposit Eth/tokens into Aztec in exchange for encrypted Aztec notes |
     * | 2       | withdraw    | exchange encrypted Aztec notes for Eth/tokens sent to a public address |
     * | 3       | send        | private send |
     * | 4       | account     | creates an Aztec account |
     * | 5       | defiDeposit | deposit Eth/tokens into a L1 smart contract via a Defi bridge contract |
     * | 6       | defiClaim   | convert proceeds of defiDeposit tx back into encrypted Aztec notes |
     *
     * Most of the above transaction types do not use the full set of 8 public inputs (i.e. some are zero).
     * To save on calldata costs, we encode each transaction into the smallest payload possible.
     * In `decodeProof`, the encoded transaction data is decoded and written into memory
     *
     * As part of the decoding algorithms we must convert the 20-byte `publicOwner` and 4-byte `assetId` fields
     * into 32-byte EVM words
     *
     * The following functions perform transaction-specific decoding. The `proofId` field is decoded prior to calling these functions
     */

    /**
     * @notice Decodes a padding tx
     * @param _inPtr location in calldata of the encoded transaction
     * @return - a location in calldata of the next encoded transaction
     *
     * @dev Encoded padding tx consists of 1 byte, the `proofId`
     *      The `proofId` has been written into memory before we called this function so there is nothing to copy
     *      Advance the calldatapointer by 1 byte to move to the next transaction
     */
    function paddingTx(uint256 _inPtr, uint256) internal pure returns (uint256) {
        unchecked {
            return (_inPtr + 0x1);
        }
    }

    /**
     * @notice Decodes a deposit or a withdraw tx
     * @param _inPtr location in calldata of the encoded transaction
     * @param _outPtr location in memory to write the decoded transaction to
     * @return - location in calldata of the next encoded transaction
     *
     * @dev The deposit tx uses all 8 public inputs. All calldata is copied into memory.
     */
    function depositOrWithdrawTx(uint256 _inPtr, uint256 _outPtr) internal pure returns (uint256) {
        // Copy deposit calldata into memory
        assembly {
            // start copying into `outPtr + 0x20`, as `outPtr` points to `proofId`, which has already been written into memory
            calldatacopy(add(_outPtr, 0x20), add(_inPtr, 0x20), 0xa0) // noteCommitment{1, 2}, nullifier{1,2}, publicValue; 32*5 bytes
            calldatacopy(add(_outPtr, 0xcc), add(_inPtr, 0xc0), 0x14) // convert 20-byte `publicOwner` calldata variable into 32-byte EVM word
            calldatacopy(add(_outPtr, 0xfc), add(_inPtr, 0xd4), 0x4) // convert 4-byte `assetId` variable into 32-byte EVM word
        }
        // advance calldata ptr by 185 bytes
        unchecked {
            return (_inPtr + 0xb9);
        }
    }

    /**
     * @notice Decodes a send-type tx
     * @param _inPtr location in calldata of the encoded transaction
     * @param _outPtr location in memory to write the decoded transaction to
     * @return - location in calldata of the next encoded transaction
     *
     * @dev The send tx has 0-values for `publicValue`, `publicOwner` and `assetId`
     *      No need to copy anything into memory for these fields as memory defaults to 0
     */
    function sendTx(uint256 _inPtr, uint256 _outPtr) internal pure returns (uint256) {
        assembly {
            calldatacopy(add(_outPtr, 0x20), add(_inPtr, 0x20), 0x80) // noteCommitment{1, 2}, nullifier{1,2}; 32*4 bytes
        }
        unchecked {
            return (_inPtr + 0x81);
        }
    }

    /**
     * @notice Decodes an account creation tx
     * @param _inPtr location in calldata of the encoded transaction
     * @param _outPtr location in memory to write the decoded transaction to
     * @return - location in calldata of the next encoded transaction
     *
     * @dev The account tx has 0-values for `nullifier2`, `publicValue`, `publicOwner` and `assetId`
     *      No need to copy anything into memory for these fields as memory defaults to 0
     */
    function accountTx(uint256 _inPtr, uint256 _outPtr) internal pure returns (uint256) {
        assembly {
            calldatacopy(add(_outPtr, 0x20), add(_inPtr, 0x20), 0x80) // noteCommitment{1, 2}, nullifier{1,2}; 32*4 bytes
        }
        unchecked {
            return (_inPtr + 0x81);
        }
    }

    /**
     * @notice Decodes a defi deposit or claim tx
     * @param _inPtr location in calldata of the encoded transaction
     * @param _outPtr location in memory to write the decoded transaction to
     * @return - location in calldata of the next encoded transaction
     *
     * @dev The defi deposit/claim tx has 0-values for `publicValue`, `publicOwner` and `assetId`
     *      No need to copy anything into memory for these fields as memory defaults to 0
     */
    function defiDepositOrClaimTx(uint256 _inPtr, uint256 _outPtr) internal pure returns (uint256) {
        assembly {
            calldatacopy(add(_outPtr, 0x20), add(_inPtr, 0x20), 0x80) // noteCommitment{1, 2}, nullifier{1,2}; 32*4 bytes
        }
        unchecked {
            return (_inPtr + 0x81);
        }
    }

    /**
     * @notice Throws an error and reverts.
     * @dev If we hit this, there is a transaction whose proofId is invalid (i.e. not 0 to 7).
     */
    function invalidTx(uint256, uint256) internal pure returns (uint256) {
        revert ENCODING_BYTE_INVALID();
    }

    /**
     * @notice Decodes the rollup block's proof data
     * @dev This function converts the proof data into a representation we can work with in memory
     *      In particular, encoded transaction calldata is decoded and written into memory
     *      The rollup header is copied from calldata into memory as well
     * @return proofData a memory pointer to the decoded proof data
     * @return numTxs number of transactions in the rollup, excluding end-padding transactions
     * @return publicInputsHash sha256 hash of the public inputs
     *
     * @dev The `publicInputsHash` is a sha256 hash of the public inputs associated with each transaction in the rollup.
     *      It is used to validate the correctness of the data being fed into the rollup circuit.
     *
     *      (There is a bit of nomenclature abuse here. Processing a public input in the verifier algorithm costs 150 gas,
     *      which adds up very quickly. Instead of this, we sha256 hash what used to be the "public" inputs and only set
     *      the hash to be public. We then make the old "public" inputs private in the rollup circuit, and validate their
     *      correctness by checking that their sha256 hash matches what we compute in the decodeProof function!
     */
    function decodeProof() internal view returns (bytes memory proofData, uint256 numTxs, uint256 publicInputsHash) {
        // declare some variables that will be set inside asm blocks
        uint256 dataSize; // size of our decoded transaction data, in bytes
        uint256 outPtr; // memory pointer to where we will write our decoded transaction data
        uint256 inPtr; // calldata pointer into our proof data
        uint256 rollupSize; // max number of transactions in the rollup block
        uint256 decodedTxDataStart;

        {
            uint256 tailInPtr; // calldata pointer to the end of our proof data

            /**
             * Let's build a function table!
             *
             * To decode our tx data, we need to iterate over every encoded transaction and call its
             * associated decoding function. If we did this via a `switch` statement this would be VERY expensive,
             * due to the large number of JUMPI instructions that would be called.
             *
             * Instead, we use function pointers.
             * The `proofId` field in our encoded proof data is an integer from 0-6,
             * we can use `proofId` to index a table of function pointers for our respective decoding functions.
             * This is much faster as there is no conditional branching!
             */
            function(uint256, uint256) pure returns (uint256) callfunc; // we're going to use `callfunc` as a function pointer
            // `functionTable` is a pointer to a table in memory, containing function pointers
            // Step 1: reserve memory for functionTable
            uint256 functionTable;
            assembly {
                functionTable := mload(0x40)
                mstore(0x40, add(functionTable, 0x100)) // reserve 256 bytes for function pointers
            }
            {
                // Step 2: copy function pointers into local variables so that inline asm code can access them
                function(uint256, uint256) pure returns (uint256) t0 = paddingTx;
                function(uint256, uint256) pure returns (uint256) t1 = depositOrWithdrawTx;
                function(uint256, uint256) pure returns (uint256) t3 = sendTx;
                function(uint256, uint256) pure returns (uint256) t4 = accountTx;
                function(uint256, uint256) pure returns (uint256) t5 = defiDepositOrClaimTx;
                function(uint256, uint256) pure returns (uint256) t7 = invalidTx;

                // Step 3: write function pointers into the table!
                assembly {
                    mstore(functionTable, t0)
                    mstore(add(functionTable, 0x20), t1)
                    mstore(add(functionTable, 0x40), t1)
                    mstore(add(functionTable, 0x60), t3)
                    mstore(add(functionTable, 0x80), t4)
                    mstore(add(functionTable, 0xa0), t5)
                    mstore(add(functionTable, 0xc0), t5)
                    mstore(add(functionTable, 0xe0), t7) // a proofId of 7 is not a valid transaction type, set to invalidTx
                }
            }
            uint256 decodedTransactionDataSize;
            assembly {
                // Add encoded proof data size to dataSize, minus the 4 bytes of encodedInnerProofData.length.
                // Set inPtr to point to the length parameter of `bytes calldata proofData`
                inPtr := add(calldataload(0x04), 0x4) // `proofData = first input parameter. Calldata offset to proofData will be at 0x04. Add 0x04 to account for function signature.

                // Advance inPtr to point to the start of `proofData`
                inPtr := add(inPtr, 0x20)

                numTxs := and(calldataload(add(inPtr, NUM_REAL_TRANSACTIONS_OFFSET)), 0xffffffff)
                // Get encoded inner proof data size.
                // Add ENCODED_PROOF_DATA_LENGTH_OFFSET to inPtr to point to the correct variable in our header block,
                // mask off all but 4 least significant bytes as this is a packed 32-bit variable.
                let encodedInnerDataSize := and(calldataload(add(inPtr, ENCODED_PROOF_DATA_LENGTH_OFFSET)), 0xffffffff)

                // Load up the rollup size from `proofData`
                rollupSize := calldataload(add(inPtr, 0x20))

                // Compute the number of bytes our decoded proof data will take up.
                // i.e. num total txns in the rollup (including padding) * number of public inputs per transaction
                let decodedInnerDataSize := mul(rollupSize, TX_PUBLIC_INPUT_LENGTH)

                // We want `dataSize` to equal: rollup header length + decoded tx length (excluding padding blocks)
                let numInnerRollups := calldataload(add(inPtr, sub(ROLLUP_HEADER_LENGTH, 0x20)))
                let numTxsPerRollup := div(rollupSize, numInnerRollups)

                let numFilledBlocks := div(numTxs, numTxsPerRollup)
                numFilledBlocks := add(numFilledBlocks, iszero(eq(mul(numFilledBlocks, numTxsPerRollup), numTxs)))

                decodedTransactionDataSize := mul(mul(numFilledBlocks, numTxsPerRollup), TX_PUBLIC_INPUT_LENGTH)
                dataSize := add(ROLLUP_HEADER_LENGTH, decodedTransactionDataSize)

                // Allocate memory for `proofData`.
                proofData := mload(0x40)
                // Set free mem ptr to `dataSize` + 0x20 (to account for the 0x20 bytes for the length param of proofData)
                // This allocates memory whose size is equal to the rollup header size, plus the data required for
                // each transaction's decoded tx data (256 bytes * number of non-padding blocks).
                // Only reserve memory for blocks that contain non-padding proofs. These "padding" blocks don't need to be
                // stored in memory as we don't need their data for any computations.
                mstore(0x40, add(proofData, add(dataSize, 0x20)))

                // Set `outPtr` to point to the `proofData` length parameter
                outPtr := proofData
                // Write `dataSize` into `proofData.length`
                mstore(outPtr, dataSize)
                // Advance `outPtr` to point to start of `proofData`
                outPtr := add(outPtr, 0x20)

                // Copy rollup header data to `proofData`.
                calldatacopy(outPtr, inPtr, ROLLUP_HEADER_LENGTH)
                // Advance `outPtr` to point to the end of the header data (i.e. the start of the decoded inner transaction data)
                outPtr := add(outPtr, ROLLUP_HEADER_LENGTH)

                // Advance `inPtr` to point to the start of our encoded inner transaction data.
                // Add (ROLLUP_HEADER_LENGTH + 0x08) to skip over the packed (numRealTransactions, encodedProofData.length) parameters
                inPtr := add(inPtr, add(ROLLUP_HEADER_LENGTH, 0x08))

                // Set `tailInPtr` to point to the end of our encoded transaction data
                tailInPtr := add(inPtr, encodedInnerDataSize)
                // Set `decodedTxDataStart` pointer
                decodedTxDataStart := outPtr
            }
            /**
             * Start of decoding algorithm
             *
             * Iterate over every encoded transaction, load out the first byte (`proofId`) and use it to
             * jump to the relevant transaction's decoding function
             */
            assembly {
                // Subtract 31 bytes off of `inPtr`, so that the first byte of the encoded transaction data
                // is located at the least significant byte of calldataload(inPtr)
                // also adjust `tailInPtr` as we compare `inPtr` against `tailInPtr`
                inPtr := sub(inPtr, 0x1f)
                tailInPtr := sub(tailInPtr, 0x1f)
            }
            unchecked {
                for (; tailInPtr > inPtr;) {
                    assembly {
                        // For each tx, the encoding byte determines how we decode the tx calldata
                        // The encoding byte can take values from 0 to 7; we want to turn these into offsets that can index our function table.
                        // 1. Access encoding byte via `calldataload(inPtr)`. The least significant byte is our encoding byte. Mask off all but the 3 least sig bits
                        // 2. Shift left by 5 bits. This is equivalent to multiplying the encoding byte by 32.
                        // 3. The result will be 1 of 8 offset values (0x00, 0x20, ..., 0xe0) which we can use to retrieve the relevant function pointer from `functionTable`
                        let encoding := and(calldataload(inPtr), 7)
                        // Store `proofId` at `outPtr`.
                        mstore(outPtr, encoding) // proofId

                        // Use `proofId` to extract the relevant function pointer from `functionTable`
                        callfunc := mload(add(functionTable, shl(5, encoding)))
                    }
                    // Call the decoding function. Return value will be next required value of inPtr
                    inPtr = callfunc(inPtr, outPtr);
                    // advance outPtr by the size of a decoded transaction
                    outPtr += TX_PUBLIC_INPUT_LENGTH;
                }
            }
        }

        /**
         * Compute the public inputs hash
         *
         * We need to take our decoded proof data and compute its SHA256 hash.
         * This hash is fed into our rollup proof as a public input.
         * If the hash does not match the SHA256 hash computed within the rollup circuit
         * on the equivalent parameters, the proof will reject.
         * This check ensures that the transaction data present in calldata are equal to
         * the transaction data values present in the rollup ZK-SNARK circuit.
         *
         * One complication is the structure of the SHA256 hash.
         * We slice transactions into chunks equal to the number of transactions in the "inner rollup" circuit
         * (a rollup circuit verifies multiple "inner rollup" circuits, which each verify 3-28 private user transactions.
         *  This tree structure helps parallelise proof construction)
         * We then SHA256 hash each transaction *chunk*
         * Finally we SHA256 hash the above SHA256 hashes to get our public input hash!
         *
         * We do the above instead of a straight hash of all of the transaction data,
         * because it's faster to parallelise proof construction if the majority of the SHA256 hashes are computed in
         * the "inner rollup" circuit and not the main rollup circuit.
         */
        // Step 1: compute the hashes that constitute the inner proofs data
        bool invalidRollupTopology;
        assembly {
            // We need to figure out how many rollup proofs are in this tx and how many user transactions are in each rollup
            let numRollupTxs := mload(add(proofData, ROLLUP_HEADER_LENGTH))
            let numJoinSplitsPerRollup := div(rollupSize, numRollupTxs)
            let rollupDataSize := mul(mul(numJoinSplitsPerRollup, NUMBER_OF_PUBLIC_INPUTS_PER_TX), 32)

            // Compute the number of inner rollups that don't contain padding proofs
            let numNotEmptyInnerRollups := div(numTxs, numJoinSplitsPerRollup)
            numNotEmptyInnerRollups :=
                add(numNotEmptyInnerRollups, iszero(eq(mul(numNotEmptyInnerRollups, numJoinSplitsPerRollup), numTxs)))
            // Compute the number of inner rollups that only contain padding proofs!
            // For these "empty" inner rollups, we don't need to compute their public inputs hash directly,
            // we can use a precomputed value
            let numEmptyInnerRollups := sub(numRollupTxs, numNotEmptyInnerRollups)

            let proofdataHashPtr := mload(0x40)
            // Copy the header data into the `proofdataHash`
            // Header start is at calldataload(0x04) + 0x24 (+0x04 to skip over func signature, +0x20 to skip over byte array length param)
            calldatacopy(proofdataHashPtr, add(calldataload(0x04), 0x24), ROLLUP_HEADER_LENGTH)

            // Update pointer
            proofdataHashPtr := add(proofdataHashPtr, ROLLUP_HEADER_LENGTH)

            // Compute the endpoint for the `proofdataHashPtr` (used as a loop boundary condition)
            let endPtr := add(proofdataHashPtr, mul(numNotEmptyInnerRollups, 0x20))
            // Iterate over the public inputs of each inner rollup proof and compute their SHA256 hash

            // better solution here is ... iterate over number of non-padding rollup blocks
            // and hash those
            // for padding rollup blocks...just append the zero hash
            for {} lt(proofdataHashPtr, endPtr) { proofdataHashPtr := add(proofdataHashPtr, 0x20) } {
                // address(0x02) is the SHA256 precompile address
                if iszero(staticcall(gas(), 0x02, decodedTxDataStart, rollupDataSize, 0x00, 0x20)) {
                    revert(0x00, 0x00)
                }

                mstore(proofdataHashPtr, mod(mload(0x00), CIRCUIT_MODULUS))
                decodedTxDataStart := add(decodedTxDataStart, rollupDataSize)
            }

            // If there are empty inner rollups, we can use a precomputed hash
            // of their public inputs instead of computing it directly.
            if iszero(iszero(numEmptyInnerRollups)) {
                let zeroHash
                switch numJoinSplitsPerRollup
                case 32 { zeroHash := PADDING_ROLLUP_HASH_SIZE_32 }
                case 16 { zeroHash := PADDING_ROLLUP_HASH_SIZE_16 }
                case 64 { zeroHash := PADDING_ROLLUP_HASH_SIZE_64 }
                case 1 { zeroHash := PADDING_ROLLUP_HASH_SIZE_1 }
                case 2 { zeroHash := PADDING_ROLLUP_HASH_SIZE_2 }
                case 4 { zeroHash := PADDING_ROLLUP_HASH_SIZE_4 }
                case 8 { zeroHash := PADDING_ROLLUP_HASH_SIZE_8 }
                default { invalidRollupTopology := true }

                endPtr := add(endPtr, mul(numEmptyInnerRollups, 0x20))
                for {} lt(proofdataHashPtr, endPtr) { proofdataHashPtr := add(proofdataHashPtr, 0x20) } {
                    mstore(proofdataHashPtr, zeroHash)
                }
            }
            // Compute SHA256 hash of header data + inner public input hashes
            let startPtr := mload(0x40)
            if iszero(staticcall(gas(), 0x02, startPtr, sub(proofdataHashPtr, startPtr), 0x00, 0x20)) {
                revert(0x00, 0x00)
            }
            publicInputsHash := mod(mload(0x00), CIRCUIT_MODULUS)
        }
        if (invalidRollupTopology) {
            revert INVALID_ROLLUP_TOPOLOGY();
        }
    }

    /**
     * @notice Extracts the `rollupId` param from the decoded proof data
     * @dev This represents the rollupId of the next valid rollup block
     * @param _proofData the decoded proof data
     * @return nextRollupId the expected id of the next rollup block
     */
    function getRollupId(bytes memory _proofData) internal pure returns (uint256 nextRollupId) {
        assembly {
            nextRollupId := mload(add(_proofData, 0x20))
        }
    }

    /**
     * @notice Decodes the input merkle roots of `proofData` and computes rollupId && sha3 hash of roots && dataStartIndex
     * @dev The rollup's state is uniquely defined by the following variables:
     *          * The next empty location in the data root tree (rollupId + 1)
     *          * The next empty location in the data tree (dataStartIndex + rollupSize)
     *          * The root of the data tree
     *          * The root of the nullifier set
     *          * The root of the data root tree (tree containing all previous roots of the data tree)
     *          * The root of the defi tree
     *      Instead of storing all of these variables in storage (expensive!), we store a keccak256 hash of them.
     *      To validate the correctness of a block's state transition, we must perform the following:
     *          * Use proof broadcasted inputs to reconstruct the "old" state hash
     *          * Use proof broadcasted inputs to reconstruct the "new" state hash
     *          * Validate that the old state hash matches what is in storage
     *          * Set the old state hash to the new state hash
     *      N.B. we still store `dataSize` as a separate storage var as `proofData does not contain all
     *           neccessary information to reconstruct its old value.
     * @param _proofData cryptographic proofData associated with a rollup
     * @return rollupId
     * @return oldStateHash
     * @return newStateHash
     * @return numDataLeaves
     * @return dataStartIndex
     */
    function computeRootHashes(bytes memory _proofData)
        internal
        pure
        returns (
            uint256 rollupId,
            bytes32 oldStateHash,
            bytes32 newStateHash,
            uint32 numDataLeaves,
            uint32 dataStartIndex
        )
    {
        assembly {
            let dataStart := add(_proofData, 0x20) // jump over first word, it's length of data
            numDataLeaves := shl(1, mload(add(dataStart, 0x20))) // rollupSize * 2 (2 notes per tx)
            dataStartIndex := mload(add(dataStart, 0x40))

            // validate numDataLeaves && dataStartIndex are uint32s
            if or(gt(numDataLeaves, 0xffffffff), gt(dataStartIndex, 0xffffffff)) { revert(0, 0) }
            rollupId := mload(dataStart)

            let mPtr := mload(0x40)

            mstore(mPtr, rollupId) // old nextRollupId
            mstore(add(mPtr, 0x20), mload(add(dataStart, 0x60))) // oldDataRoot
            mstore(add(mPtr, 0x40), mload(add(dataStart, 0xa0))) // oldNullRoot
            mstore(add(mPtr, 0x60), mload(add(dataStart, 0xe0))) // oldRootRoot
            mstore(add(mPtr, 0x80), mload(add(dataStart, 0x120))) // oldDefiRoot
            oldStateHash := keccak256(mPtr, 0xa0)

            mstore(mPtr, add(rollupId, 0x01)) // new nextRollupId
            mstore(add(mPtr, 0x20), mload(add(dataStart, 0x80))) // newDataRoot
            mstore(add(mPtr, 0x40), mload(add(dataStart, 0xc0))) // newNullRoot
            mstore(add(mPtr, 0x60), mload(add(dataStart, 0x100))) // newRootRoot
            mstore(add(mPtr, 0x80), mload(add(dataStart, 0x140))) // newDefiRoot
            newStateHash := keccak256(mPtr, 0xa0)
        }
    }

    /**
     * @notice Extract the `prevDefiInteractionHash` from the proofData's rollup header
     * @param _proofData decoded rollup proof data
     * @return prevDefiInteractionHash the defiInteractionHash of the previous rollup block
     */
    function extractPrevDefiInteractionHash(bytes memory _proofData)
        internal
        pure
        returns (bytes32 prevDefiInteractionHash)
    {
        assembly {
            prevDefiInteractionHash := mload(add(_proofData, PREVIOUS_DEFI_INTERACTION_HASH_OFFSET))
        }
    }

    /**
     * @notice Extracts the address we pay the rollup fee to from the proofData's rollup header
     * @dev Rollup beneficiary address is included as part of the ZK-SNARK circuit data, so that the rollup provider
     *      can explicitly define who should get the fee when they are generating the ZK-SNARK proof (instead of
     *      simply sending the fee to msg.sender).
     *      This prevents front-running attacks where an attacker can take somebody else's rollup proof from out of
     *      the tx pool and replay it, stealing the fee.
     * @param _proofData byte array of our input proof data
     * @return rollupBeneficiary the address we pay this rollup block's fee to
     */
    function extractRollupBeneficiary(bytes memory _proofData) internal pure returns (address rollupBeneficiary) {
        assembly {
            rollupBeneficiary := mload(add(_proofData, ROLLUP_BENEFICIARY_OFFSET))
            // Validate `rollupBeneficiary` is an address
            if gt(rollupBeneficiary, ADDRESS_MASK) { revert(0, 0) }
        }
    }

    /**
     * @notice Extracts an `assetId` in which a fee is going to be paid from a rollup block
     * @dev The rollup block contains up to 16 different assets, which can be recovered from the rollup header data.
     * @param _proofData byte array of our input proof data
     * @param _idx index of the asset we want (assetId = header.assetIds[_idx])
     * @return assetId 30-bit identifier of an asset. The ERC20 token address is obtained via the mapping `supportedAssets[assetId]`,
     */
    function extractFeeAssetId(bytes memory _proofData, uint256 _idx) internal pure returns (uint256 assetId) {
        assembly {
            assetId :=
                mload(
                    add(add(add(_proofData, BRIDGE_CALL_DATAS_OFFSET), mul(0x40, NUMBER_OF_BRIDGE_CALLS)), mul(0x20, _idx))
                )
            // Validate `assetId` is a uint32!
            if gt(assetId, 0xffffffff) { revert(0, 0) }
        }
    }

    /**
     * @notice Extracts the transaction fee for a given asset which is to be paid to the rollup beneficiary
     * @dev The total fee is the sum of the individual fees paid by each transaction in the rollup block.
     *      This sum is computed directly in the rollup circuit, and is present in the rollup header data.
     * @param _proofData byte array of decoded rollup proof data
     * @param _idx The index of the asset the fee is denominated in
     * @return totalTxFee total rollup block transaction fee for a given asset
     */
    function extractTotalTxFee(bytes memory _proofData, uint256 _idx) internal pure returns (uint256 totalTxFee) {
        assembly {
            totalTxFee := mload(add(add(add(_proofData, 0x380), mul(0x40, NUMBER_OF_BRIDGE_CALLS)), mul(0x20, _idx)))
        }
    }
}

// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec
pragma solidity >=0.8.4;

import {AztecTypes} from "rollup-encoder/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 set _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
     *      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.
     * @return interactionComplete A flag indicating whether an async interaction was successfully completed/finalised.
     * @dev This function should use the `BridgeBase.onlyRollup()` modifier to ensure it can only be called from
     *      the `RollupProcessor.processAsyncDefiInteraction(uint256 _interactionNonce)` method.
     *
     */
    function finalise(
        AztecTypes.AztecAsset calldata _inputAssetA,
        AztecTypes.AztecAsset calldata _inputAssetB,
        AztecTypes.AztecAsset calldata _outputAssetA,
        AztecTypes.AztecAsset calldata _outputAssetB,
        uint256 _interactionNonce,
        uint64 _auxData
    ) external payable returns (uint256 outputValueA, uint256 outputValueB, bool interactionComplete);
}

// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec
pragma solidity >=0.8.4;

interface IVerifier {
    function verify(bytes memory _serializedProof, uint256 _publicInputsHash) external returns (bool);

    function getVerificationKeyHash() external pure returns (bytes32);
}

File 19 of 20 : SafeCast.sol
// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec.
pragma solidity >=0.8.4;

library SafeCast {
    error SAFE_CAST_OVERFLOW();

    function toU128(uint256 a) internal pure returns (uint128) {
        if (a > type(uint128).max) revert SAFE_CAST_OVERFLOW();
        return uint128(a);
    }
}

// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec
pragma solidity >=0.8.4;

/**
 * @title TokenTransfers
 * @dev Provides functions to safely call `transfer` and `transferFrom` methods on ERC20 tokens,
 * as well as the ability to call `transfer` and `transferFrom` without bubbling up errors
 */
library TokenTransfers {
    error INVALID_ADDRESS_NO_CODE();

    bytes4 private constant INVALID_ADDRESS_NO_CODE_SELECTOR = 0x21409272; // bytes4(keccak256('INVALID_ADDRESS_NO_CODE()'));
    bytes4 private constant TRANSFER_SELECTOR = 0xa9059cbb; // bytes4(keccak256('transfer(address,uint256)'));
    bytes4 private constant TRANSFER_FROM_SELECTOR = 0x23b872dd; // bytes4(keccak256('transferFrom(address,address,uint256)'));

    /**
     * @dev Safely call ERC20.transfer, handles tokens that do not throw on transfer failure or do not return transfer result
     * @param tokenAddress Where does the token live?
     * @param to Who are we sending tokens to?
     * @param amount How many tokens are we transferring?
     */
    function safeTransferTo(address tokenAddress, address to, uint256 amount) internal {
        // The ERC20 token standard states that:
        // 1. failed transfers must throw
        // 2. the result of the transfer (success/fail) is returned as a boolean
        // Some token contracts don't implement the spec correctly and will do one of the following:
        // 1. Contract does not throw if transfer fails, instead returns false
        // 2. Contract throws if transfer fails, but does not return any boolean value
        // We can check for these by evaluating the following:
        // | call succeeds? (c) | return value (v) | returndatasize == 0 (r)| interpreted result |
        // | ---                | ---              | ---                    | ---                |
        // | false              | false            | false                  | transfer fails     |
        // | false              | false            | true                   | transfer fails     |
        // | false              | true             | false                  | transfer fails     |
        // | false              | true             | true                   | transfer fails     |
        // | true               | false            | false                  | transfer fails     |
        // | true               | false            | true                   | transfer succeeds  |
        // | true               | true             | false                  | transfer succeeds  |
        // | true               | true             | true                   | transfer succeeds  |
        //
        // i.e. failure state = !(c && (r || v))
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, TRANSFER_SELECTOR)
            mstore(add(ptr, 0x4), to)
            mstore(add(ptr, 0x24), amount)
            if iszero(extcodesize(tokenAddress)) {
                mstore(0, INVALID_ADDRESS_NO_CODE_SELECTOR)
                revert(0, 0x4)
            }
            let call_success := call(gas(), tokenAddress, 0, ptr, 0x44, 0x00, 0x20)
            let result_success := or(iszero(returndatasize()), and(mload(0), 1))
            if iszero(and(call_success, result_success)) {
                returndatacopy(0, 0, returndatasize())
                revert(0, returndatasize())
            }
        }
    }

    /**
     * @dev Safely call ERC20.transferFrom, handles tokens that do not throw on transfer failure or do not return transfer result
     * @param tokenAddress Where does the token live?
     * @param source Who are we transferring tokens from
     * @param target Who are we transferring tokens to?
     * @param amount How many tokens are being transferred?
     */
    function safeTransferFrom(address tokenAddress, address source, address target, uint256 amount) internal {
        assembly {
            // call tokenAddress.transferFrom(source, target, value)
            let mPtr := mload(0x40)
            mstore(mPtr, TRANSFER_FROM_SELECTOR)
            mstore(add(mPtr, 0x04), source)
            mstore(add(mPtr, 0x24), target)
            mstore(add(mPtr, 0x44), amount)
            if iszero(extcodesize(tokenAddress)) {
                mstore(0, INVALID_ADDRESS_NO_CODE_SELECTOR)
                revert(0, 0x4)
            }
            let call_success := call(gas(), tokenAddress, 0, mPtr, 0x64, 0x00, 0x20)
            let result_success := or(iszero(returndatasize()), and(mload(0), 1))
            if iszero(and(call_success, result_success)) {
                returndatacopy(0, 0, returndatasize())
                revert(0, returndatasize())
            }
        }
    }

    /**
     * @dev Calls ERC(tokenAddress).transfer(to, amount). Errors are ignored! Use with caution!
     * @param tokenAddress Where does the token live?
     * @param to Who are we sending to?
     * @param amount How many tokens are being transferred?
     * @param gasToSend Amount of gas to send the contract. If value is 0, function uses gas() instead
     */
    function transferToDoNotBubbleErrors(address tokenAddress, address to, uint256 amount, uint256 gasToSend)
        internal
    {
        assembly {
            let callGas := gas()
            if gasToSend { callGas := gasToSend }
            let ptr := mload(0x40)
            mstore(ptr, TRANSFER_SELECTOR)
            mstore(add(ptr, 0x4), to)
            mstore(add(ptr, 0x24), amount)
            pop(call(callGas, tokenAddress, 0, ptr, 0x44, 0x00, 0x00))
        }
    }

    /**
     * @dev Calls ERC(tokenAddress).transferFrom(source, target, amount). Errors are ignored! Use with caution!
     * @param tokenAddress Where does the token live?
     * @param source Who are we transferring tokens from
     * @param target Who are we transferring tokens to?
     * @param amount How many tokens are being transferred?
     * @param gasToSend Amount of gas to send the contract. If value is 0, function uses gas() instead
     */
    function transferFromDoNotBubbleErrors(
        address tokenAddress,
        address source,
        address target,
        uint256 amount,
        uint256 gasToSend
    ) internal {
        assembly {
            let callGas := gas()
            if gasToSend { callGas := gasToSend }
            let mPtr := mload(0x40)
            mstore(mPtr, TRANSFER_FROM_SELECTOR)
            mstore(add(mPtr, 0x04), source)
            mstore(add(mPtr, 0x24), target)
            mstore(add(mPtr, 0x44), amount)
            pop(call(callGas, tokenAddress, 0, mPtr, 0x64, 0x00, 0x00))
        }
    }
}

Settings
{
  "remappings": [
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "@uniswap/v2-core/=lib/v2-core/",
    "@uniswap/v2-periphery/=lib/v2-periphery/",
    "core/=src/core/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "mocks/=src/test/mocks/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
    "periphery/=src/periphery/",
    "rollup-encoder/=lib/rollup-encoder/src/",
    "v2-core/=lib/v2-core/contracts/",
    "v2-periphery/=lib/v2-periphery/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 2000
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"uint256","name":"_escapeBlockLowerBound","type":"uint256"},{"internalType":"uint256","name":"_escapeBlockUpperBound","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ARRAY_OVERFLOW","type":"error"},{"inputs":[{"internalType":"uint256","name":"inputAssetId","type":"uint256"}],"name":"BRIDGE_WITH_IDENTICAL_INPUT_ASSETS","type":"error"},{"inputs":[{"internalType":"uint256","name":"outputAssetId","type":"uint256"}],"name":"BRIDGE_WITH_IDENTICAL_OUTPUT_ASSETS","type":"error"},{"inputs":[],"name":"DAILY_CAP_SURPASSED","type":"error"},{"inputs":[],"name":"DEPOSIT_TOKENS_WRONG_PAYMENT_TYPE","type":"error"},{"inputs":[],"name":"ENCODING_BYTE_INVALID","type":"error"},{"inputs":[],"name":"INCONSISTENT_BRIDGE_CALL_DATA","type":"error"},{"inputs":[{"internalType":"uint256","name":"providedIndex","type":"uint256"},{"internalType":"uint256","name":"expectedIndex","type":"uint256"}],"name":"INCORRECT_DATA_START_INDEX","type":"error"},{"inputs":[{"internalType":"bytes32","name":"providedDefiInteractionHash","type":"bytes32"},{"internalType":"bytes32","name":"expectedDefiInteractionHash","type":"bytes32"}],"name":"INCORRECT_PREVIOUS_DEFI_INTERACTION_HASH","type":"error"},{"inputs":[{"internalType":"bytes32","name":"oldStateHash","type":"bytes32"},{"internalType":"bytes32","name":"newStateHash","type":"bytes32"}],"name":"INCORRECT_STATE_HASH","type":"error"},{"inputs":[],"name":"INSUFFICIENT_DEPOSIT","type":"error"},{"inputs":[],"name":"INSUFFICIENT_ETH_PAYMENT","type":"error"},{"inputs":[],"name":"INSUFFICIENT_TOKEN_APPROVAL","type":"error"},{"inputs":[],"name":"INVALID_ADDRESS_NO_CODE","type":"error"},{"inputs":[],"name":"INVALID_ASSET_ADDRESS","type":"error"},{"inputs":[],"name":"INVALID_ASSET_GAS","type":"error"},{"inputs":[],"name":"INVALID_ASSET_ID","type":"error"},{"inputs":[],"name":"INVALID_BRIDGE_ADDRESS","type":"error"},{"inputs":[],"name":"INVALID_BRIDGE_CALL_DATA","type":"error"},{"inputs":[],"name":"INVALID_BRIDGE_GAS","type":"error"},{"inputs":[],"name":"INVALID_ESCAPE_BOUNDS","type":"error"},{"inputs":[],"name":"INVALID_PROVIDER","type":"error"},{"inputs":[],"name":"INVALID_ROLLUP_TOPOLOGY","type":"error"},{"inputs":[],"name":"INVALID_SIGNATURE","type":"error"},{"inputs":[],"name":"LOCKED_NO_REENTER","type":"error"},{"inputs":[],"name":"MSG_VALUE_WRONG_AMOUNT","type":"error"},{"inputs":[{"internalType":"uint256","name":"outputValue","type":"uint256"}],"name":"NONZERO_OUTPUT_VALUE_ON_NOT_USED_ASSET","type":"error"},{"inputs":[],"name":"NOT_PAUSED","type":"error"},{"inputs":[],"name":"PAUSED","type":"error"},{"inputs":[],"name":"PENDING_CAP_SURPASSED","type":"error"},{"inputs":[],"name":"PROOF_VERIFICATION_FAILED","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"PUBLIC_INPUTS_HASH_VERIFICATION_FAILED","type":"error"},{"inputs":[],"name":"SAFE_CAST_OVERFLOW","type":"error"},{"inputs":[],"name":"SIGNATURE_ADDRESS_IS_ZERO","type":"error"},{"inputs":[],"name":"SIGNATURE_RECOVERY_FAILED","type":"error"},{"inputs":[],"name":"THIRD_PARTY_CONTRACTS_FLAG_NOT_SET","type":"error"},{"inputs":[],"name":"WITHDRAW_TO_ZERO_ADDRESS","type":"error"},{"inputs":[],"name":"ZERO_TOTAL_INPUT_VALUE","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"AllowThirdPartyContractsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":true,"internalType":"address","name":"assetAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"assetGasLimit","type":"uint256"}],"name":"AssetAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pendingCap","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dailyCap","type":"uint256"}],"name":"AssetCapUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"encodedBridgeCallData","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalInputValue","type":"uint256"}],"name":"AsyncDefiBridgeProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"bridgeAddressId","type":"uint256"},{"indexed":true,"internalType":"address","name":"bridgeAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"bridgeGasLimit","type":"uint256"}],"name":"BridgeAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isCapped","type":"bool"}],"name":"CappedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"encodedBridgeCallData","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalInputValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalOutputValueA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalOutputValueB","type":"uint256"},{"indexed":false,"internalType":"bool","name":"result","type":"bool"},{"indexed":false,"internalType":"bytes","name":"errorReason","type":"bytes"}],"name":"DefiBridgeProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"defiBridgeProxy","type":"address"}],"name":"DefiBridgeProxyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"delay","type":"uint32"}],"name":"DelayBeforeEscapeHatchUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":true,"internalType":"address","name":"depositorAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"depositValue","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rollupId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chunk","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalChunks","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"OffchainData","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rollupId","type":"uint256"},{"indexed":false,"internalType":"bytes32[]","name":"nextExpectedDefiHashes","type":"bytes32[]"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"RollupProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"providerAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"valid","type":"bool"}],"name":"RollupProviderUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"verifierAddress","type":"address"}],"name":"VerifierUpdated","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EMERGENCY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LISTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OWNER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RESUME_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowThirdPartyContracts","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proofHash","type":"bytes32"}],"name":"approveProof","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"assetGasLimits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"asyncDefiInteractionHashes","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"bridgeGasLimits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"caps","outputs":[{"internalType":"uint128","name":"available","type":"uint128"},{"internalType":"uint32","name":"lastUpdatedTimestamp","type":"uint32"},{"internalType":"uint32","name":"pendingCap","type":"uint32"},{"internalType":"uint32","name":"dailyCap","type":"uint32"},{"internalType":"uint8","name":"precision","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defiBridgeProxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"defiInteractionHashes","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delayBeforeEscapeHatch","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"bytes32","name":"_proofHash","type":"bytes32"}],"name":"depositPendingFunds","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"depositProofApprovals","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"escapeBlockLowerBound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"escapeBlockUpperBound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ethPayments","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAsyncDefiInteractionHashesLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCapped","outputs":[{"internalType":"bool","name":"capped","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDataSize","outputs":[{"internalType":"uint256","name":"dataSize","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDefiInteractionHashesLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEscapeHatchStatus","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getImplementationVersion","outputs":[{"internalType":"uint8","name":"version","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPendingDefiInteractionHashesLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetId","type":"uint256"}],"name":"getSupportedAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSupportedAssetsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bridgeAddressId","type":"uint256"}],"name":"getSupportedBridge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSupportedBridgesLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastRollupTimeStamp","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rollupId","type":"uint256"},{"internalType":"uint256","name":"_chunk","type":"uint256"},{"internalType":"uint256","name":"_totalChunks","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"offchainData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"isPaused","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pendingDefiInteractions","outputs":[{"internalType":"uint256","name":"encodedBridgeCallData","type":"uint256"},{"internalType":"uint256","name":"totalInputValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"prevDefiInteractionsHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_interactionNonce","type":"uint256"}],"name":"processAsyncDefiInteraction","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"_signatures","type":"bytes"}],"name":"processRollup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_interactionNonce","type":"uint256"}],"name":"receiveEthFromBridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rollupProviders","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rollupStateHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_allowThirdPartyContracts","type":"bool"}],"name":"setAllowThirdPartyContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetId","type":"uint256"},{"internalType":"uint32","name":"_pendingCap","type":"uint32"},{"internalType":"uint32","name":"_dailyCap","type":"uint32"},{"internalType":"uint8","name":"_precision","type":"uint8"}],"name":"setAssetCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isCapped","type":"bool"}],"name":"setCapped","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_defiBridgeProxy","type":"address"}],"name":"setDefiBridgeProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_delay","type":"uint32"}],"name":"setDelayBeforeEscapeHatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_provider","type":"address"},{"internalType":"bool","name":"_valid","type":"bool"}],"name":"setRollupProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_gasLimit","type":"uint256"}],"name":"setSupportedAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bridge","type":"address"},{"internalType":"uint256","name":"_gasLimit","type":"uint256"}],"name":"setSupportedBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_verifier","type":"address"}],"name":"setVerifier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"userPendingDeposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"verifier","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60c06040523480156200001157600080fd5b506040516200610d3803806200610d83398101604081905262000034916200014e565b811580620000425750808210155b15620000615760405163b37657e760e01b815260040160405180910390fd5b6200006b6200008d565b6002805460ff60e81b1916600160e81b17905560809190915260a05262000173565b600054610100900460ff1615620000fa5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116146200014c576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b600080604083850312156200016257600080fd5b505080516020909101519092909150565b60805160a051615f4a620001c360003960008181610b7801528181612acf01528181612b2e01528181612b590152612b8901526000818161098201528181612aab0152612bb40152615f4a6000f3fe6080604052600436106103975760003560e01c80638666c0a9116101dc578063c37c656d11610102578063dcefed85116100a0578063e58378bb1161006f578063e58378bb14610c72578063f21c69bb14610ca6578063f81cccbe14610cd3578063fb0ce18514610cf357600080fd5b8063dcefed8514610bd1578063deb26b9414610bfe578063e0d16c3214610c32578063e393635514610c5257600080fd5b8063cd12bf62116100dc578063cd12bf6214610b19578063d547741f14610b46578063d8ba363714610b66578063db1533aa14610b9a57600080fd5b8063c37c656d14610a21578063c4a7a35f14610ad4578063caa3455314610af957600080fd5b8063a2b096e41161017a578063b3a07b9811610149578063b3a07b98146109a4578063bc327e40146109c4578063be71f8a4146109e0578063c0fd22b714610a0c57600080fd5b8063a2b096e41461090e578063a33dc5e71461092e578063a8d1eae71461095b578063b045009c1461097057600080fd5b806391dfe78f116101b657806391dfe78f14610899578063999e3614146108b95780639b60ae2b146108da578063a217fddf146108f957600080fd5b80638666c0a9146107ea5780638afceb391461080a57806391d148541461085357600080fd5b806336ce0a92116102c1578063781e04321161025f5780637ff48afb1161022e5780637ff48afb1461078d5780638129fc1c146107a05780638188f468146107b55780638456cb59146107d557600080fd5b8063781e0432146106fa5780637ba3e7ae146107355780637baf71181461074b5780637d036b271461076b57600080fd5b80635ad1def31161029b5780635ad1def31461066b5780635c975abb1461069b57806360a8b18a146106ba5780636a0214a9146106da57600080fd5b806336ce0a92146105fe5780633f4ba83a146106365780635437988d1461064b57600080fd5b806320825443116103395780632b7ac3f3116103085780632b7ac3f31461056c5780632de03aa11461058a5780632f2ff15d146105be57806336568abe146105de57600080fd5b806320825443146104b557806320a23dd3146104d557806320df435914610507578063248a9ca31461053b57600080fd5b80630ceee68c116103755780630ceee68c146104215780630d698f6f1461045957806312a536231461047b5780631ab9c6031461049f57600080fd5b806301ffc9a71461039c57806302f6ccd4146103d157806303561119146103f4575b600080fd5b3480156103a857600080fd5b506103bc6103b736600461575f565b610d13565b60405190151581526020015b60405180910390f35b3480156103dd57600080fd5b506103e6610dac565b6040519081526020016103c8565b34801561040057600080fd5b506103e661040f3660046157a1565b600e6020526000908152604090205481565b34801561042d57600080fd5b50600a54610441906001600160a01b031681565b6040516001600160a01b0390911681526020016103c8565b34801561046557600080fd5b506104796104743660046157c8565b610df0565b005b6104796104893660046157a1565b6000908152600d60205260409020805434019055565b3480156104ab57600080fd5b506103e660095481565b3480156104c157600080fd5b506104796104d036600461582e565b610f39565b3480156104e157600080fd5b506011546104f29063ffffffff1681565b60405163ffffffff90911681526020016103c8565b34801561051357600080fd5b506103e67fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b2681565b34801561054757600080fd5b506103e66105563660046157a1565b6000908152600160208190526040909120015490565b34801561057857600080fd5b506002546001600160a01b0316610441565b34801561059657600080fd5b506103e67f2fc10cc8ae19568712f7a176fb4978616a610650813c9d05326c34abb62749c781565b3480156105ca57600080fd5b506104796105d93660046158a6565b610fad565b3480156105ea57600080fd5b506104796105f93660046158a6565b610fd8565b34801561060a57600080fd5b506103e66106193660046158a6565b600760209081526000928352604080842090915290825290205481565b34801561064257600080fd5b50610479611069565b34801561065757600080fd5b506104796106663660046158d2565b611186565b34801561067757600080fd5b506103bc6106863660046158d2565b600b6020526000908152604090205460ff1681565b3480156106a757600080fd5b50600254600160e81b900460ff166103bc565b3480156106c657600080fd5b506104416106d53660046157a1565b611297565b3480156106e657600080fd5b506104796106f5366004615901565b611343565b34801561070657600080fd5b506103bc61071536600461591c565b600860209081526000928352604080842090915290825290205460ff1681565b34801561074157600080fd5b506103e660105481565b34801561075757600080fd5b50600254600160c01b900461ffff166103e6565b34801561077757600080fd5b50600254600160a01b900463ffffffff166103e6565b61047961079b366004615946565b61142b565b3480156107ac57600080fd5b50610479611693565b3480156107c157600080fd5b506103bc6107d03660046157a1565b611ae9565b3480156107e157600080fd5b5061047961238f565b3480156107f657600080fd5b5061047961080536600461591c565b61249a565b34801561081657600080fd5b5061083e6108253660046157a1565b600c602052600090815260409020805460019091015482565b604080519283526020830191909152016103c8565b34801561085f57600080fd5b506103bc61086e3660046158a6565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156108a557600080fd5b506104796108b4366004615983565b6126c4565b3480156108c557600080fd5b50600a546103bc90600160a01b900460ff1681565b3480156108e657600080fd5b50600254600160f01b900460ff166103bc565b34801561090557600080fd5b506103e6600081565b34801561091a57600080fd5b506104796109293660046157c8565b6127ad565b34801561093a57600080fd5b506103e66109493660046157a1565b60066020526000908152604090205481565b34801561096757600080fd5b506004546103e6565b34801561097c57600080fd5b506103e67f000000000000000000000000000000000000000000000000000000000000000081565b3480156109b057600080fd5b506104796109bf3660046159ba565b612891565b3480156109d057600080fd5b50604051600281526020016103c8565b3480156109ec57600080fd5b506109f5612aa4565b6040805192151583526020830191909152016103c8565b348015610a1857600080fd5b506003546103e6565b348015610a2d57600080fd5b50610a93610a3c3660046157a1565b6012602052600090815260409020546001600160801b0381169063ffffffff7001000000000000000000000000000000008204811691600160a01b8104821691600160c01b8204169060ff600160e01b9091041685565b604080516001600160801b03909616865263ffffffff94851660208701529284169285019290925291909116606083015260ff16608082015260a0016103c8565b348015610ae057600080fd5b506011546104f290640100000000900463ffffffff1681565b348015610b0557600080fd5b50610479610b143660046158d2565b612be5565b348015610b2557600080fd5b506103e6610b343660046157a1565b60056020526000908152604090205481565b348015610b5257600080fd5b50610479610b613660046158a6565b612ce3565b348015610b7257600080fd5b506103e67f000000000000000000000000000000000000000000000000000000000000000081565b348015610ba657600080fd5b506002547a010000000000000000000000000000000000000000000000000000900461ffff166103e6565b348015610bdd57600080fd5b506103e6610bec3660046157a1565b600d6020526000908152604090205481565b348015610c0a57600080fd5b506103e67ff94103142c1baabe9ac2b5d1487bf783de9e69cfeea9a72f5c9c94afd7877b8c81565b348015610c3e57600080fd5b50610441610c4d3660046157a1565b612d09565b348015610c5e57600080fd5b50610479610c6d3660046157a1565b612d43565b348015610c7e57600080fd5b506103e67fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e81565b348015610cb257600080fd5b506103e6610cc13660046157a1565b600f6020526000908152604090205481565b348015610cdf57600080fd5b50610479610cee366004615a0f565b612d8e565b348015610cff57600080fd5b50610479610d0e36600461591c565b612f23565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610da657507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b600254600090610de79061ffff7a0100000000000000000000000000000000000000000000000000008204811691600160c01b900416615a91565b61ffff16905090565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e610e1a8161312e565b600060028054600160e01b900460ff1690811115610e3a57610e3a615ab7565b14610e5857604051631e7b117d60e01b815260040160405180910390fd5b60028054819060ff60e01b1916600160e01b820217905550600254600160f01b900460ff1615158215151415610e8d57610f1a565b8115610ea9576011805463ffffffff19164263ffffffff161790555b60028054831515600160f01b027fff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9091161790556040517f99895cad53cbbff374fbe3c76182ad42a6cb1c0c7306d3b6651786e7154ccbe690610f1190841515815260200190565b60405180910390a15b600280546000919060ff60e01b1916600160e01b835b02179055505050565b600254600160e81b900460ff1615610f6457604051632a6ab56360e21b815260040160405180910390fd5b60408051858152602081018590523381830152905186917fb92710e3fad9222f817fcd828bd1ce3612ad0cd1c8bd5f3a3f4b8d85c4444621919081900360600190a25050505050565b60008281526001602081905260409091200154610fc98161312e565b610fd3838361313b565b505050565b6001600160a01b038116331461105b5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b61106582826131c2565b5050565b600254600160e81b900460ff166110ac576040517f395fbd0500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f2fc10cc8ae19568712f7a176fb4978616a610650813c9d05326c34abb62749c76110d68161312e565b600060028054600160e01b900460ff16908111156110f6576110f6615ab7565b1461111457604051631e7b117d60e01b815260040160405180910390fd5b600280547fffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160e11b1790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1506002805460ff60e01b19169055565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e6111b08161312e565b600060028054600160e01b900460ff16908111156111d0576111d0615ab7565b146111ee57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0382163b611229576040516310a0493960e11b815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0384169081179091556040517fd24015cc99cc1700cafca3042840a1d8ac1e3964fd2e0e37ea29c654056ee32790600090a2600280546000919060ff60e01b1916600160e01b83610f30565b600081631fffffff8111156112bf57604051630104ef3360e21b815260040160405180910390fd5b826112cd576000915061133d565b600060036112dc600186615acd565b815481106112ec576112ec615ae4565b6000918252602090912001546001600160a01b031690508061133a576040517ffc3be2bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b91505b50919050565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e61136d8161312e565b600060028054600160e01b900460ff169081111561138d5761138d615ab7565b146113ab57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b179055601180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff1664010000000063ffffffff8516908102919091179091556040519081527f536948e5a71b8ffbb707a6903b99b812c8c291a711ed188e54d36505127d1c3590602001610f11565b600254600160e81b900460ff161561145657604051632a6ab56360e21b815260040160405180910390fd5b600060028054600160e01b900460ff169081111561147657611476615ab7565b1461149457604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b179055831580156114b55750823414155b156114ec576040517ff2be5ced00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83158015906114fa57503415155b15611531576040517fd08ba85b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61153c848385613245565b801561154b5761154b81612d43565b816001600160a01b0316847feaa18152488ce5959073c9c79c88ca90b3d96c00de1f118cfaad664c3dab06b98560405161158791815260200190565b60405180910390a383156116725760006115a085611297565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815233600482015230602482015290915084906001600160a01b0383169063dd62ed3e90604401602060405180830381865afa158015611608573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162c9190615afa565b1015611664576040517f7bf8af0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611670813330876135f6565b505b600280546000919060ff60e01b1916600160e01b835b021790555050505050565b6002600054610100900460ff161580156116b4575060005460ff8083169116105b6117265760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401611052565b806000806101000a81548160ff021916908360ff1602179055506001600060016101000a81548160ff02191690831515021790555060016002600001601e6101000a81548160ff02191690831515021790555042601160006101000a81548163ffffffff021916908363ffffffff1602179055506040518060a00160405280683635c9adc5dea000006001600160801b031681526020014263ffffffff168152602001600663ffffffff1681526020016103e863ffffffff168152602001601260ff168152506012600080815260200190815260200160002060008201518160000160006101000a8154816001600160801b0302191690836001600160801b0316021790555060208201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001601c6101000a81548160ff021916908360ff1602179055509050506040518060a0016040528069d3c21bcecceda10000006001600160801b031681526020014263ffffffff16815260200161277463ffffffff168152602001620f424063ffffffff168152602001601260ff16815250601260006001815260200190815260200160002060008201518160000160006101000a8154816001600160801b0302191690836001600160801b0316021790555060208201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001601c6101000a81548160ff021916908360ff1602179055509050507f2c87e4aece114a15933668e808bd3756196c2fb05a4902851081ed8584f8690e600060066103e8604051611a3c939291909283526020830191909152604082015260600190565b60405180910390a160408051600181526127746020820152620f42408183015290517f2c87e4aece114a15933668e808bd3756196c2fb05a4902851081ed8584f8690e9181900360600190a1600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b600254600090600160e81b900460ff1615611b1757604051632a6ab56360e21b815260040160405180910390fd5b600254600160e01b900460ff166001816002811115611b3857611b38615ab7565b1415611f3c576000838152600c60205260409020805460019091015481611b8b576040517f973e3ae300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611b9683613675565b9050600080600080611ba8858b6138e5565b60046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19a63ffffffff8c160154939750919550935091506001600160a01b031680611c21576040517fbb65988600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600c60008d815260200190815260200160002060000181905550600060405180606001604052808981526020018d81526020018860c0015167ffffffffffffffff1681525090506000806000846001600160a01b0316639b07d3428a8a8a8a89602001518a604001516040518763ffffffff1660e01b8152600401611cad96959493929190615b58565b6060604051808303816000875af1158015611ccc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf09190615bb2565b92509250925080611d26575050506020908101516000908152600c90915260408120989098555095975061133d95505050505050565b600082118015611d4b5750600086604001516003811115611d4957611d49615ab7565b145b15611d85576040517f26e939c600000000000000000000000000000000000000000000000000000000815260048101839052602401611052565b82158015611d91575081155b15611dc357611daa858a86600001518760200151613bcb565b611dbe858986600001518760200151613bcb565b611de3565b611dd38588858760200151613bcb565b611de38587848760200151613bcb565b6000845160208601516000851460008714161592506040518f81528160208201528260408201528660608201528560808201528360a08201526020600060c08360025afa505050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600051066002548060c01c6103ff168160d01c6103ff166102008183600101011115611e8357632c52558760e11b60005260046000fd5b50600081815260056020908152604080832095909555600190920160c090811b7ffffffffffffffc00ffffffffffffffffffffffffffffffffffffffffffffffff909416939093176002558882015189518551908152928301899052938201879052841515606083015260a0608083018190528201528f917f692cf5822a02f5edf084dc7249b3a06293621e069f11975ed70908ed10ed2e2c910160405180910390a360019e505050505050505050505050505061133d565b6000816002811115611f5057611f50615ab7565b1415612376576002805460ff60e01b1916600160e01b1790556000838152600c6020526040902080546001919091015481611fb7576040517f973e3ae300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611fc283613675565b9050600080600080611fd4858b6138e5565b60046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19a63ffffffff8c160154939750919550935091506001600160a01b03168061204d576040517fbb65988600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600c60008d815260200190815260200160002060000181905550600060405180606001604052808981526020018d81526020018860c0015167ffffffffffffffff1681525090506000806000846001600160a01b0316639b07d3428a8a8a8a89602001518a604001516040518763ffffffff1660e01b81526004016120d996959493929190615b58565b6060604051808303816000875af11580156120f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211c9190615bb2565b92509250925080612152575050506020908101516000908152600c90915260408120989098555095975061236495505050505050565b600082118015612177575060008660400151600381111561217557612175615ab7565b145b156121b1576040517f26e939c600000000000000000000000000000000000000000000000000000000815260048101839052602401611052565b821580156121bd575081155b156121ef576121d6858a86600001518760200151613bcb565b6121ea858986600001518760200151613bcb565b61220f565b6121ff8588858760200151613bcb565b61220f8587848760200151613bcb565b6000845160208601516000851460008714161592506040518f81528160208201528260408201528660608201528560808201528360a08201526020600060c08360025afa505050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600051066002548060c01c6103ff168160d01c6103ff1661020081836001010111156122af57632c52558760e11b60005260046000fd5b50600081815260056020908152604080832095909555600190920160c090811b7ffffffffffffffc00ffffffffffffffffffffffffffffffffffffffffffffffff909416939093176002558882015189518551908152928301899052938201879052841515606083015260a0608083018190528201528f917f692cf5822a02f5edf084dc7249b3a06293621e069f11975ed70908ed10ed2e2c910160405180910390a360019e50505050505050505050505050505b6002805460ff60e01b1916905561133d565b604051631e7b117d60e01b815260040160405180910390fd5b600254600160e81b900460ff16156123ba57604051632a6ab56360e21b815260040160405180910390fd5b7fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b266123e48161312e565b600060028054600160e01b900460ff169081111561240457612404615ab7565b1461242257604051631e7b117d60e01b815260040160405180910390fd5b600280547fffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167d0102000000000000000000000000000000000000000000000000000000001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200161116e565b600254600160e81b900460ff16156124c557604051632a6ab56360e21b815260040160405180910390fd5b3360009081527f65ab7acc1bb8390bd4d3ba8eb4987cf212c814cedeacf3ad4b0583b29d65f538602052604090205460ff1615801561250e5750600a54600160a01b900460ff16155b15612545576040517f11d74fb800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060028054600160e01b900460ff169081111561256557612565615ab7565b1461258357604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0382163b6125be576040516310a0493960e11b815260040160405180910390fd5b6188b88110806125d05750624c4b4081115b15612607576040517f037bbe6d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480546001810182557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03851690811790915590546000818152600f6020908152604091829020859055905184815291929183917f0e62be7fe47a9095143143f8ee61bab3ade27b661223fed33e16122ffe1f284d91015b60405180910390a350600280546000919060ff60e01b1916600160e01b83610f30565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e6126ee8161312e565b600060028054600160e01b900460ff169081111561270e5761270e615ab7565b1461272c57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0383166000818152600b6020908152604091829020805460ff1916861515908117909155825190815291517f46359ce9dbb6c7f9a375b44072210287916d3de725fc8927a8e762047e4a84249281900390910190a250506002805460ff60e01b1916905550565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e6127d78161312e565b600060028054600160e01b900460ff16908111156127f7576127f7615ab7565b1461281557604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b179055600a8054831515600160a01b81027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff909216919091179091556040519081527fad6b1fc8881be24fc1ad35119b136f0026a4496e6251980e325ddcf86dab394390602001610f11565b7ff94103142c1baabe9ac2b5d1487bf783de9e69cfeea9a72f5c9c94afd7877b8c6128bb8161312e565b600060028054600160e01b900460ff16908111156128db576128db615ab7565b146128f957604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556040805160a081019091528061293b61292685600a615ccf565b6129369063ffffffff8816615cde565b613c86565b6001600160801b03908116825263ffffffff4281166020808501919091528882166040808601829052898416606080880182905260ff8b81166080998a015260008f8152601287528490208a5181548c8901518d8801518e8701519e909d0151909416600160e01b0260ff60e01b199d8b16600160c01b027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9d8c16600160a01b029d909d167fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff95909b167001000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff1990921692909b169190911717919091169690961797909717979097169490941790925582518a815290810191909152908101929092527f2c87e4aece114a15933668e808bd3756196c2fb05a4902851081ed8584f8690e910160405180910390a150506002805460ff60e01b19169055505050565b60008043817f0000000000000000000000000000000000000000000000000000000000000000612af47f000000000000000000000000000000000000000000000000000000000000000084615d13565b1015905060008115612b8457601154612b1d9063ffffffff640100000000820481169116615d27565b421015612b2957600091505b612b537f000000000000000000000000000000000000000000000000000000000000000084615d13565b612b7d907f0000000000000000000000000000000000000000000000000000000000000000615acd565b9050612bdb565b612bae7f000000000000000000000000000000000000000000000000000000000000000084615d13565b612bd8907f0000000000000000000000000000000000000000000000000000000000000000615acd565b90505b9094909350915050565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e612c0f8161312e565b600060028054600160e01b900460ff1690811115612c2f57612c2f615ab7565b14612c4d57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0382163b612c88576040516310a0493960e11b815260040160405180910390fd5b600a805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0384169081179091556040519081527fc4fc5cbf094d63a6fb20dc7cb9b0236e7dba8c04667182ec259a00a74f95901890602001610f11565b60008281526001602081905260409091200154612cff8161312e565b610fd383836131c2565b60006004612d18600184615acd565b81548110612d2857612d28615ae4565b6000918252602090912001546001600160a01b031692915050565b600254600160e81b900460ff1615612d6e57604051632a6ab56360e21b815260040160405180910390fd5b336000526008602052604060002060205280600052600160406000205550565b600254600160e81b900460ff1615612db957604051632a6ab56360e21b815260040160405180910390fd5b600060028054600160e01b900460ff1690811115612dd957612dd9615ab7565b14612df757604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e01b179055336000908152600b602052604090205460ff1615612e4f57600254600160f01b900460ff1615612e4a576011805463ffffffff19164263ffffffff161790555b612e95565b6000612e59612aa4565b50905080612e93576040517f83633aab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b6000806000612ea2613ccd565b9250925092506000612eb384614069565b9050612efa8487878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250889250879150869050614088565b612f0484826140f2565b5050600280546000935090915060ff60e01b1916600160e01b83611688565b600254600160e81b900460ff1615612f4e57604051632a6ab56360e21b815260040160405180910390fd5b3360009081527f65ab7acc1bb8390bd4d3ba8eb4987cf212c814cedeacf3ad4b0583b29d65f538602052604090205460ff16158015612f975750600a54600160a01b900460ff16155b15612fce576040517f11d74fb800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060028054600160e01b900460ff1690811115612fee57612fee615ab7565b1461300c57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0382163b613047576040516310a0493960e11b815260040160405180910390fd5b61d6d881108061305957506216e36081115b15613090576040517f11e80d6c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380546001810182557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03851690811790915590546000818152600e6020908152604091829020859055905184815291929183917f85ac039d1da307b778050ca29271ac915424bac011342c9452960f6679b18ff091016126a1565b6131388133614177565b50565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff166110655760008281526001602081815260408084206001600160a01b0386168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff16156110655760008281526001602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b82631fffffff81111561326b57604051630104ef3360e21b815260040160405180910390fd5b60008481526007602090815260408083206001600160a01b0387168452909152902054600254600160f01b900460ff16156135be576000858152601260209081526040808320815160a08101835290546001600160801b038116825263ffffffff7001000000000000000000000000000000008204811694830194909452600160a01b8104841692820192909252600160c01b8204909216606083015260ff600160e01b909104166080820181905290919061332890600a615ccf565b9050816040015163ffffffff1660001480613360575080826040015163ffffffff166133549190615cde565b61335e8685615d27565b115b15613397576040517ffb1837c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015163ffffffff166133d8576040517fd014828600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081836060015163ffffffff166133f09190615cde565b905060006134016201518083615d3f565b9050613426846020015163ffffffff164261341c9190615acd565b6129369083615cde565b84518590613435908390615d53565b6001600160801b0390811690915285511683101590506134645761345882613c86565b6001600160801b031684525b83516001600160801b03168711156134a8576040517fd014828600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6134b187613c86565b845185906134c0908390615d75565b6001600160801b0390811690915263ffffffff428116602080890191825260008e81526012909152604090819020895181549351928b015160608c015160808d015160ff16600160e01b0260ff60e01b19918816600160c01b027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff938916600160a01b02939093167fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff969098167001000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff199097169390981692909217949094179290921693909317919091171691909117905550505050505b6135c88382615d27565b60009586526007602090815260408088206001600160a01b0390971688529590529390942092909255505050565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152836004820152826024820152816044820152843b613645576310a0493960e11b60005260046000fd5b602060006064836000895af190506001600051163d151780821661366d573d6000803e3d6000fd5b505050505050565b604080516101c081018252600060208083018290526101a083019190915263ffffffff8416808352633fffffff9185901c821693830193909352603e84901c81166060830152605c84901c81166080830152607a84901c1660a082015267ffffffffffffffff60b884901c1660c08201526001603d84901c811660e0830152605b84901c8116610100830152607984901c8116610120830152609784901c8116610140830152609884901c81168114610160830152609984901c81168114610180830152909160049161374791615acd565b8154811061375757613757615ae4565b60009182526020808320909101546001600160a01b03168382015282518252600f905260409020546101a082015261016081015115801561379c575060008160600151115b156137d3576040517f3448066300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061018001511580156137ea575060008160a00151115b15613821576040517f3448066300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806101600151801561383a575080606001518160400151145b156138795780604001516040517f760558e800000000000000000000000000000000000000000000000000000000815260040161105291815260200190565b600081610180015180156138905750816101400151155b90508080156138a657508160a001518260800151145b1561133d5781608001516040517ff23e3f9500000000000000000000000000000000000000000000000000000000815260040161105291815260200190565b61390660408051606081018252600080825260208201819052909182015290565b61392760408051606081018252600080825260208201819052909182015290565b61394860408051606081018252600080825260208201819052909182015290565b61396960408051606081018252600080825260208201819052909182015290565b8560e001511561399c57632000000086604001516139879190615acd565b845260006020850152600360408501526139fa565b6040860180518552516139ae90611297565b6001600160a01b031660208501819052156139ca5760026139cd565b60015b846040019060038111156139e3576139e3615ab7565b908160038111156139f6576139f6615ab7565b9052505b85610120015115613a1b578482526000602083015260036040830152613a79565b608086018051835251613a2d90611297565b6001600160a01b03166020830181905215613a49576002613a4c565b60015b82604001906003811115613a6257613a62615ab7565b90816003811115613a7557613a75615ab7565b9052505b85610100015115613ac35763200000008660600151613a989190615acd565b8352600060208401526040830160035b90816003811115613abb57613abb615ab7565b905250613b27565b85610160015115613b1557606086018051845251613ae090611297565b6001600160a01b03166020840181905215613afc576002613aff565b60015b83604001906003811115613aa857613aa8615ab7565b60008084526020840181905260408401525b85610140015115613b5e57848152600060208201526040810160035b90816003811115613b5657613b56615ab7565b905250613bc2565b85610180015115613bb05760a086018051825251613b7b90611297565b6001600160a01b03166020820181905215613b97576002613b9a565b60015b81604001906003811115613b4357613b43615ab7565b60008082526020820181905260408201525b92959194509250565b81613bd557613c80565b600183604001516003811115613bed57613bed615ab7565b1415613c4f576000818152600d6020526040902054821115613c3b576040517fcbbf6eca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600d6020526040812055613c80565b600283604001516003811115613c6757613c67615ab7565b1415613c80576020830151613c7e818630866135f6565b505b50505050565b60006001600160801b03821115613cc9576040517f7a781de100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090565b6040805161010080820183526141ec82526141f360208084018290528385019190915261421e606084018190526080840181905260a0840181905260c084015261423360e084015283516111c46004359081013560448201359081046111c883013563ffffffff908116828104808402821415019092029096028481016111e0019098526111c08881018086529498919760009795968a0195602486019589948594615755949391926111cc013590911690888a376111c098909801976111a9888101988a97509091010193505b86841115613dd15760078735168089528060051b830151935050613dc387898563ffffffff16565b965061010088019750613d9b565b505050506111c088810151604051600092828604808c048082028d1415019384900393909261010084029260043560240182376111c08101905060208202810191505b81811015613e635760206000848960025afa613e2f57600080fd5b6000517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000019006815295820195602001613e14565b8415613fe057600092508360208114613eaf5760108114613ed75760408114613eff5760018114613f275760028114613f4f5760048114613f775760088114613f9f5760019650613fc3565b7f0df0e06ab8a02ce2ff08babd7144ab23ca2e99ddf318080cf88602eeb8913d449350613fc3565b7f1c52c159b4dae66c3dcf33b44d4d61ead6bc4d260f882ac6ba34dccf78892ca49350613fc3565b7f1f83672815ac9b3ca31732d641784035834e96b269eaf6a2e759bf4fcc8e5bfd9350613fc3565b7f22dd983f8337d97d56071f7986209ab2ee6039a422242e89126701c6ee005af09350613fc3565b7f076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f365609350613fc3565b7f2f0c70a5bf5460465e9902f9c96be324e8064e762a5de52589fdb97cbce3c6ee9350613fc3565b7f240ed0de145447ff0ceff2aa477f43e0e2ed7f3543ee3d8832f158ec76b183a993505b5060208502820191505b81811015613fe057828152602001613fcd565b6040519450602060008683038760025afa613ffa57600080fd5b50505050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600051069650801561405e576040517f3259ec1e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050909192565b6111a08101516001600160a01b0381111561408357600080fd5b919050565b60006140948684614267565b90506140a1868587614338565b60006140ad8784614400565b9050817f14054a15b39bfd65ec00fc6d15c7e5f9cbc1dc6f452cbefa359b4da61ad89fb682336040516140e1929190615d9d565b60405180910390a250505050505050565b60005b6010811015610fd3576000614111848360200201610b80015190565b9050801561416e576000614125858461493e565b90508061413e57600080600080858861c350f15061416c565b600061414982611297565b905061416a818685600e60008781526020019081526020016000205461495a565b505b505b506001016140f5565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff16611065576141aa816149aa565b6141b58360206149bc565b6040516020016141c6929190615e1d565b60408051601f198184030181529082905262461bcd60e51b825261105291600401615e9e565b5060010190565b600060a0602084016020840137601460c0840160cc840137600460d4840160fc840137505060b90190565b60006080602084016020840137505060810190565b60006040517fd0426f7b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405160009063ffffffff600480356111cc810135929092168083016111ec01939290910135037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee38019060ac815360316001820153608c6002820153605d600382015360406004820152846024820152816044820152818360648301376001600160a01b03600254169250823b614309576310a0493960e11b60005260046000fd5b6000806064840183865afa9250505080614327573d6000803e3d6000fd5b5061433183614be5565b9392505050565b60006111e08085019061010085028601015b8082101561366d5760a082015180156143f357825160e084015160c085015160018314156143db5761010086206001600160a01b038216600090815260086020908152604080832084845290915290205460ff166143ce5788880180516060825260006143b684614d98565b90506143c3818487614eb1565b509052606097909701965b6143d9838387614ffd565b505b82600214156143ef576143ef84828461507e565b5050505b610100830192505061434a565b606060008061441185611180015190565b9050601054811461445c576010546040517f88011dd6000000000000000000000000000000000000000000000000000000008152611052918391600401918252602082015260400190565b6000614466615101565b90935090506144758184615acd565b600280547ffffffffffc00ffffffffffffffffffffffffffffffffffffffffffffffffffff1660d083901b1790556020878101519194506000935091506144bc9190615cde565b6040805160808082018352600080835260208301819052828401819052606090920182905282519081019092529192506101808701915b6020811015614870578251806145095750614870565b61040084015180614546576040517fb246041300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061455183613675565b9050600080600080614563858c6138e5565b93509350935093506040517f4bd947a800000000000000000000000000000000000000000000000000000000815260048101905060208601518082525084516020820152602085015160408201526040850151606082015283516080820152602084015160a0820152604084015160c0820152825160e082015260208301516101008201526040830151610120820152815161014082015260208201516101608201526040820151610180820152866101a08201528b6101c082015260c0860151806101e083015250600d6102008201528e610220820152600a54803b614655576310a0493960e11b60005260046000fd5b60008061024460048503846101a08c0151f490503d6000833e80600181146146955760008c52600060208d0152600060408d0152600060608d01526146b5565b82518c52602083015160208d0152604083015160408d0152600160608d01525b5050508461018001516146ca57600060208a01525b60408901516001811461480a576040518781528a51602082015260208b0151604082015260608b0151606082015260a0608082015260608b01511561473857600060a08201528c897f692cf5822a02f5edf084dc7249b3a06293621e069f11975ed70908ed10ed2e2c60c084a35b60608b0151614792573d60a08201523d602081066020038115150281600060c085013e60008260c0018401528e8b7f692cf5822a02f5edf084dc7249b3a06293621e069f11975ed70908ed10ed2e2c83850160c00186a350505b8881528c60208201528760408201528a51606082015260208b0151608082015260608b015160a08201526020600060c08360025afa50507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600051068d6000526006602052806040600020555060018d019c50614851565b6040518781528c897f38ce48f4c2f3454bcf130721f25a4262b2ff2c8e36af937b30edf01ba481eb1d602084a3508b600052600c6020526040600020888155876001820155505b5060018b019a5060208a019950876001019750505050505050506144f3565b506002548060c01c6103ff166103ff86820111801561489a57632c52558760e11b60005260046000fd5b506040516006602052600560605260005b828110156148cf5787810160009081526040828152808020549120556001016148ab565b506040527ffffffffffffffc00ffffffffffffffffffffffffffffffffffffffffffffffff90860160d01b167ffffffffffc00fc00ffffffffffffffffffffffffffffffffffffffffffffffff9091161760025560008061492e615123565b6010559998505050505050505050565b602081028201610980015163ffffffff811115610da657600080fd5b5a81156149645750805b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815284600482015283602482015260008060448360008a87f150505050505050565b6060610da66001600160a01b03831660145b606060006149cb836002615cde565b6149d6906002615d27565b67ffffffffffffffff8111156149ee576149ee615ed1565b6040519080825280601f01601f191660200182016040528015614a18576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110614a4f57614a4f615ae4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110614ab257614ab2615ae4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000614aee846002615cde565b614af9906001615d27565b90505b6001811115614b96577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110614b3a57614b3a615ae4565b1a60f81b828281518110614b5057614b50615ae4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93614b8f81615ee7565b9050614afc565b5083156143315760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401611052565b600080600080600080614bf7876151ff565b945094509450945094506009548414614c46576040517f34fddf400000000000000000000000000000000000000000000000000000000081526004810185905260248101849052604401611052565b60025463ffffffff600160a01b90910481169083168181614c6957614c69615cfd565b0663ffffffff1660001415614cd2578063ffffffff168263ffffffff1614614ccd576040517f7861e6c600000000000000000000000000000000000000000000000000000000815263ffffffff808416600483015282166024820152604401611052565b614d4c565b60008363ffffffff168263ffffffff1681614cef57614cef615cfd565b068483010363ffffffff169050808363ffffffff1614614d4a576040517f7861e6c600000000000000000000000000000000000000000000000000000000815263ffffffff8416600482015260248101829052604401611052565b505b506009929092556002805463ffffffff9390920192909216600160a01b027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9091161790555092915050565b600080614da4836152a8565b90506040517f19457468657265756d205369676e6564204d6573736167653a0a32313000000060208201527f5369676e696e672074686973206d6573736167652077696c6c20616c6c6f7720603d8201527f796f75722070656e64696e672066756e647320746f206265207370656e742069605d8201527f6e20417a746563207472616e73616374696f6e3a0a0a30780000000000000000607d82015260208201516095820152604082015160b58201527f0a0a494d504f5254414e543a204f6e6c79207369676e20746865206d6573736160d58201527f676520696620796f752074727573742074686520636c69656e7400000000000060f582015260ef602082012092505050919050565b6000806001600160a01b038316614ef4576040517fd57e351000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8351858552606085015160408601518060608801526020870151604088015281602088015260208760808960015afa601c8314601b84141760608514167f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a183101616945050508451861460008114614f6b57614f70565b855192505b508452801519919091169081614fb2576040517f8a3e28aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b0316816001600160a01b031614613c7e576040517fa3402a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82631fffffff81111561502357604051630104ef3360e21b815260040160405180910390fd5b60008481526007602090815260408083209091528482529020805483810390915582118015613c7e576040517f8e8af4f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0382166150be576040517f6df19fea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806150d5576000806000808686617530f150505050565b60006150e082611297565b9050613c80818486600e60008781526020019081526020016000205461495a565b6002546103ff60d082901c16908190602082111561511e57602091505b509091565b60606000806000615132615101565b909250905060006151438284615acd565b90506040519450602085016020610400018601604052828652600660205260005b83811015615188578281016000908152604090205460208202830152600101615164565b5b60208110156151c2577f2d25a1e3a51eb293004c4b56abe12ed0da6bca2b4a21936752a85d102593c1b460208202830152600101615189565b50602060006104008360025afa50507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016000510693505050509091565b604081015160608201516000918291829160011b906020860163ffffffff808411908311171561522e57600080fd5b805195506040518681526060820151602082015260a0820151604082015260e08201516060820152610120820151608082015260a0812095506001870181526080820151602082015260c082015160408201526101008201516060820152610140820151608082015260a081209450505091939590929450565b606081615310576040519050604081527f303030303030303030303030303030303030303030303030303030303030303060208201527f3030303030303030303030303030303030303030303030303030303030303030604082015260608101604052919050565b506040517f3030303130323033303430353036303730383039306130623063306430653066607e8201527f3130313131323133313431353136313731383139316131623163316431653166609e8201527f323032313232323332343235323632373238323932613262326332643265326660be8201527f333033313332333333343335333633373338333933613362336333643365336660de8201527f343034313432343334343435343634373438343934613462346334643465346660fe8201527f353035313532353335343535353635373538353935613562356335643565356661011e8201527f363036313632363336343635363636373638363936613662366336643665366661013e8201527f373037313732373337343735373637373738373937613762376337643765376661015e8201527f383038313832383338343835383638373838383938613862386338643865386661017e8201527f393039313932393339343935393639373938393939613962396339643965396661019e8201527f61306131613261336134613561366137613861396161616261636164616561666101be8201527f62306231623262336234623562366237623862396261626262636264626562666101de8201527f63306331633263336334633563366337633863396361636263636364636563666101fe8201527f643064316432643364346435643664376438643964616462646364646465646661021e8201527f653065316532653365346535653665376538653965616562656365646565656661023e8201527f663066316632663366346635663666376638663966616662666366646665666661025e820152606081018260408352600181901b6101fe908116830151601e52600782901c8116830151601c52600f82901c8116830151601a52601782901c8116830151601852601f82901c8116830151601652602782901c8116830151601452602f82901c8116830151601252603782901c8116830151601052603f82901c8116830151600e52604782901c8116830151600c52604f82901c8116830151600a52605782901c8116830151600852605f82901c8116830151600652606782901c8116830151600452606f82901c8116830151600252607782901c16820151600052601e51604084015260801c61573f82826101fe600182901b8116830151601e52600782901c8116830151601c52600f82901c8116830151601a52601782901c8116830151601852601f82901c8116830151601652602782901c8116830151601452602f82901c8116830151601252603782901c8116830151601052603f82901c8116830151600e52604782901c8116830151600c52604f82901c8116830151600a52605782901c8116830151600852605f82901c8116830151600652606782901c8116830151600452606f82901c811683015160025260779190911c160151600052565b5050601e51602082015260608101604052919050565b61575d615efe565b565b60006020828403121561577157600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461433157600080fd5b6000602082840312156157b357600080fd5b5035919050565b801515811461313857600080fd5b6000602082840312156157da57600080fd5b8135614331816157ba565b60008083601f8401126157f757600080fd5b50813567ffffffffffffffff81111561580f57600080fd5b60208301915083602082850101111561582757600080fd5b9250929050565b60008060008060006080868803121561584657600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff81111561587257600080fd5b61587e888289016157e5565b969995985093965092949392505050565b80356001600160a01b038116811461408357600080fd5b600080604083850312156158b957600080fd5b823591506158c96020840161588f565b90509250929050565b6000602082840312156158e457600080fd5b6143318261588f565b803563ffffffff8116811461408357600080fd5b60006020828403121561591357600080fd5b614331826158ed565b6000806040838503121561592f57600080fd5b6159388361588f565b946020939093013593505050565b6000806000806080858703121561595c57600080fd5b84359350602085013592506159736040860161588f565b9396929550929360600135925050565b6000806040838503121561599657600080fd5b61599f8361588f565b915060208301356159af816157ba565b809150509250929050565b600080600080608085870312156159d057600080fd5b843593506159e0602086016158ed565b92506159ee604086016158ed565b9150606085013560ff81168114615a0457600080fd5b939692955090935050565b60008060008060408587031215615a2557600080fd5b843567ffffffffffffffff80821115615a3d57600080fd5b615a49888389016157e5565b90965094506020870135915080821115615a6257600080fd5b50615a6f878288016157e5565b95989497509550505050565b634e487b7160e01b600052601160045260246000fd5b600061ffff808316818516808303821115615aae57615aae615a7b565b01949350505050565b634e487b7160e01b600052602160045260246000fd5b600082821015615adf57615adf615a7b565b500390565b634e487b7160e01b600052603260045260246000fd5b600060208284031215615b0c57600080fd5b5051919050565b805182526001600160a01b036020820151166020830152604081015160048110615b4d57634e487b7160e01b600052602160045260246000fd5b806040840152505050565b6101c08101615b678289615b13565b615b746060830188615b13565b615b8160c0830187615b13565b615b8f610120830186615b13565b8361018083015267ffffffffffffffff83166101a0830152979650505050505050565b600080600060608486031215615bc757600080fd5b83519250602084015191506040840151615be0816157ba565b809150509250925092565b600181815b80851115615c26578160001904821115615c0c57615c0c615a7b565b80851615615c1957918102915b93841c9390800290615bf0565b509250929050565b600082615c3d57506001610da6565b81615c4a57506000610da6565b8160018114615c605760028114615c6a57615c86565b6001915050610da6565b60ff841115615c7b57615c7b615a7b565b50506001821b610da6565b5060208310610133831016604e8410600b8410161715615ca9575081810a610da6565b615cb38383615beb565b8060001904821115615cc757615cc7615a7b565b029392505050565b600061433160ff841683615c2e565b6000816000190483118215151615615cf857615cf8615a7b565b500290565b634e487b7160e01b600052601260045260246000fd5b600082615d2257615d22615cfd565b500690565b60008219821115615d3a57615d3a615a7b565b500190565b600082615d4e57615d4e615cfd565b500490565b60006001600160801b03808316818516808303821115615aae57615aae615a7b565b60006001600160801b0383811690831681811015615d9557615d95615a7b565b039392505050565b604080825283519082018190526000906020906060840190828701845b82811015615dd657815184529284019290840190600101615dba565b5050506001600160a01b039490941692019190915250919050565b60005b83811015615e0c578181015183820152602001615df4565b83811115613c805750506000910152565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351615e55816017850160208801615df1565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351615e92816028840160208801615df1565b01602801949350505050565b6020815260008251806020840152615ebd816040850160208701615df1565b601f01601f19169190910160400192915050565b634e487b7160e01b600052604160045260246000fd5b600081615ef657615ef6615a7b565b506000190190565b634e487b7160e01b600052605160045260246000fdfea26469706673582212204986047a3c1dc740c0f7b2da538464da5d8465856c4b6d0dec03c81aa8d6df1564736f6c634300080a003300000000000000000000000000000000000000000000000000000000000008700000000000000000000000000000000000000000000000000000000000000960

Deployed Bytecode

0x6080604052600436106103975760003560e01c80638666c0a9116101dc578063c37c656d11610102578063dcefed85116100a0578063e58378bb1161006f578063e58378bb14610c72578063f21c69bb14610ca6578063f81cccbe14610cd3578063fb0ce18514610cf357600080fd5b8063dcefed8514610bd1578063deb26b9414610bfe578063e0d16c3214610c32578063e393635514610c5257600080fd5b8063cd12bf62116100dc578063cd12bf6214610b19578063d547741f14610b46578063d8ba363714610b66578063db1533aa14610b9a57600080fd5b8063c37c656d14610a21578063c4a7a35f14610ad4578063caa3455314610af957600080fd5b8063a2b096e41161017a578063b3a07b9811610149578063b3a07b98146109a4578063bc327e40146109c4578063be71f8a4146109e0578063c0fd22b714610a0c57600080fd5b8063a2b096e41461090e578063a33dc5e71461092e578063a8d1eae71461095b578063b045009c1461097057600080fd5b806391dfe78f116101b657806391dfe78f14610899578063999e3614146108b95780639b60ae2b146108da578063a217fddf146108f957600080fd5b80638666c0a9146107ea5780638afceb391461080a57806391d148541461085357600080fd5b806336ce0a92116102c1578063781e04321161025f5780637ff48afb1161022e5780637ff48afb1461078d5780638129fc1c146107a05780638188f468146107b55780638456cb59146107d557600080fd5b8063781e0432146106fa5780637ba3e7ae146107355780637baf71181461074b5780637d036b271461076b57600080fd5b80635ad1def31161029b5780635ad1def31461066b5780635c975abb1461069b57806360a8b18a146106ba5780636a0214a9146106da57600080fd5b806336ce0a92146105fe5780633f4ba83a146106365780635437988d1461064b57600080fd5b806320825443116103395780632b7ac3f3116103085780632b7ac3f31461056c5780632de03aa11461058a5780632f2ff15d146105be57806336568abe146105de57600080fd5b806320825443146104b557806320a23dd3146104d557806320df435914610507578063248a9ca31461053b57600080fd5b80630ceee68c116103755780630ceee68c146104215780630d698f6f1461045957806312a536231461047b5780631ab9c6031461049f57600080fd5b806301ffc9a71461039c57806302f6ccd4146103d157806303561119146103f4575b600080fd5b3480156103a857600080fd5b506103bc6103b736600461575f565b610d13565b60405190151581526020015b60405180910390f35b3480156103dd57600080fd5b506103e6610dac565b6040519081526020016103c8565b34801561040057600080fd5b506103e661040f3660046157a1565b600e6020526000908152604090205481565b34801561042d57600080fd5b50600a54610441906001600160a01b031681565b6040516001600160a01b0390911681526020016103c8565b34801561046557600080fd5b506104796104743660046157c8565b610df0565b005b6104796104893660046157a1565b6000908152600d60205260409020805434019055565b3480156104ab57600080fd5b506103e660095481565b3480156104c157600080fd5b506104796104d036600461582e565b610f39565b3480156104e157600080fd5b506011546104f29063ffffffff1681565b60405163ffffffff90911681526020016103c8565b34801561051357600080fd5b506103e67fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b2681565b34801561054757600080fd5b506103e66105563660046157a1565b6000908152600160208190526040909120015490565b34801561057857600080fd5b506002546001600160a01b0316610441565b34801561059657600080fd5b506103e67f2fc10cc8ae19568712f7a176fb4978616a610650813c9d05326c34abb62749c781565b3480156105ca57600080fd5b506104796105d93660046158a6565b610fad565b3480156105ea57600080fd5b506104796105f93660046158a6565b610fd8565b34801561060a57600080fd5b506103e66106193660046158a6565b600760209081526000928352604080842090915290825290205481565b34801561064257600080fd5b50610479611069565b34801561065757600080fd5b506104796106663660046158d2565b611186565b34801561067757600080fd5b506103bc6106863660046158d2565b600b6020526000908152604090205460ff1681565b3480156106a757600080fd5b50600254600160e81b900460ff166103bc565b3480156106c657600080fd5b506104416106d53660046157a1565b611297565b3480156106e657600080fd5b506104796106f5366004615901565b611343565b34801561070657600080fd5b506103bc61071536600461591c565b600860209081526000928352604080842090915290825290205460ff1681565b34801561074157600080fd5b506103e660105481565b34801561075757600080fd5b50600254600160c01b900461ffff166103e6565b34801561077757600080fd5b50600254600160a01b900463ffffffff166103e6565b61047961079b366004615946565b61142b565b3480156107ac57600080fd5b50610479611693565b3480156107c157600080fd5b506103bc6107d03660046157a1565b611ae9565b3480156107e157600080fd5b5061047961238f565b3480156107f657600080fd5b5061047961080536600461591c565b61249a565b34801561081657600080fd5b5061083e6108253660046157a1565b600c602052600090815260409020805460019091015482565b604080519283526020830191909152016103c8565b34801561085f57600080fd5b506103bc61086e3660046158a6565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156108a557600080fd5b506104796108b4366004615983565b6126c4565b3480156108c557600080fd5b50600a546103bc90600160a01b900460ff1681565b3480156108e657600080fd5b50600254600160f01b900460ff166103bc565b34801561090557600080fd5b506103e6600081565b34801561091a57600080fd5b506104796109293660046157c8565b6127ad565b34801561093a57600080fd5b506103e66109493660046157a1565b60066020526000908152604090205481565b34801561096757600080fd5b506004546103e6565b34801561097c57600080fd5b506103e67f000000000000000000000000000000000000000000000000000000000000087081565b3480156109b057600080fd5b506104796109bf3660046159ba565b612891565b3480156109d057600080fd5b50604051600281526020016103c8565b3480156109ec57600080fd5b506109f5612aa4565b6040805192151583526020830191909152016103c8565b348015610a1857600080fd5b506003546103e6565b348015610a2d57600080fd5b50610a93610a3c3660046157a1565b6012602052600090815260409020546001600160801b0381169063ffffffff7001000000000000000000000000000000008204811691600160a01b8104821691600160c01b8204169060ff600160e01b9091041685565b604080516001600160801b03909616865263ffffffff94851660208701529284169285019290925291909116606083015260ff16608082015260a0016103c8565b348015610ae057600080fd5b506011546104f290640100000000900463ffffffff1681565b348015610b0557600080fd5b50610479610b143660046158d2565b612be5565b348015610b2557600080fd5b506103e6610b343660046157a1565b60056020526000908152604090205481565b348015610b5257600080fd5b50610479610b613660046158a6565b612ce3565b348015610b7257600080fd5b506103e67f000000000000000000000000000000000000000000000000000000000000096081565b348015610ba657600080fd5b506002547a010000000000000000000000000000000000000000000000000000900461ffff166103e6565b348015610bdd57600080fd5b506103e6610bec3660046157a1565b600d6020526000908152604090205481565b348015610c0a57600080fd5b506103e67ff94103142c1baabe9ac2b5d1487bf783de9e69cfeea9a72f5c9c94afd7877b8c81565b348015610c3e57600080fd5b50610441610c4d3660046157a1565b612d09565b348015610c5e57600080fd5b50610479610c6d3660046157a1565b612d43565b348015610c7e57600080fd5b506103e67fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e81565b348015610cb257600080fd5b506103e6610cc13660046157a1565b600f6020526000908152604090205481565b348015610cdf57600080fd5b50610479610cee366004615a0f565b612d8e565b348015610cff57600080fd5b50610479610d0e36600461591c565b612f23565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610da657507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b600254600090610de79061ffff7a0100000000000000000000000000000000000000000000000000008204811691600160c01b900416615a91565b61ffff16905090565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e610e1a8161312e565b600060028054600160e01b900460ff1690811115610e3a57610e3a615ab7565b14610e5857604051631e7b117d60e01b815260040160405180910390fd5b60028054819060ff60e01b1916600160e01b820217905550600254600160f01b900460ff1615158215151415610e8d57610f1a565b8115610ea9576011805463ffffffff19164263ffffffff161790555b60028054831515600160f01b027fff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9091161790556040517f99895cad53cbbff374fbe3c76182ad42a6cb1c0c7306d3b6651786e7154ccbe690610f1190841515815260200190565b60405180910390a15b600280546000919060ff60e01b1916600160e01b835b02179055505050565b600254600160e81b900460ff1615610f6457604051632a6ab56360e21b815260040160405180910390fd5b60408051858152602081018590523381830152905186917fb92710e3fad9222f817fcd828bd1ce3612ad0cd1c8bd5f3a3f4b8d85c4444621919081900360600190a25050505050565b60008281526001602081905260409091200154610fc98161312e565b610fd3838361313b565b505050565b6001600160a01b038116331461105b5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b61106582826131c2565b5050565b600254600160e81b900460ff166110ac576040517f395fbd0500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f2fc10cc8ae19568712f7a176fb4978616a610650813c9d05326c34abb62749c76110d68161312e565b600060028054600160e01b900460ff16908111156110f6576110f6615ab7565b1461111457604051631e7b117d60e01b815260040160405180910390fd5b600280547fffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160e11b1790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1506002805460ff60e01b19169055565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e6111b08161312e565b600060028054600160e01b900460ff16908111156111d0576111d0615ab7565b146111ee57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0382163b611229576040516310a0493960e11b815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0384169081179091556040517fd24015cc99cc1700cafca3042840a1d8ac1e3964fd2e0e37ea29c654056ee32790600090a2600280546000919060ff60e01b1916600160e01b83610f30565b600081631fffffff8111156112bf57604051630104ef3360e21b815260040160405180910390fd5b826112cd576000915061133d565b600060036112dc600186615acd565b815481106112ec576112ec615ae4565b6000918252602090912001546001600160a01b031690508061133a576040517ffc3be2bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b91505b50919050565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e61136d8161312e565b600060028054600160e01b900460ff169081111561138d5761138d615ab7565b146113ab57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b179055601180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff1664010000000063ffffffff8516908102919091179091556040519081527f536948e5a71b8ffbb707a6903b99b812c8c291a711ed188e54d36505127d1c3590602001610f11565b600254600160e81b900460ff161561145657604051632a6ab56360e21b815260040160405180910390fd5b600060028054600160e01b900460ff169081111561147657611476615ab7565b1461149457604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b179055831580156114b55750823414155b156114ec576040517ff2be5ced00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83158015906114fa57503415155b15611531576040517fd08ba85b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61153c848385613245565b801561154b5761154b81612d43565b816001600160a01b0316847feaa18152488ce5959073c9c79c88ca90b3d96c00de1f118cfaad664c3dab06b98560405161158791815260200190565b60405180910390a383156116725760006115a085611297565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815233600482015230602482015290915084906001600160a01b0383169063dd62ed3e90604401602060405180830381865afa158015611608573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162c9190615afa565b1015611664576040517f7bf8af0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611670813330876135f6565b505b600280546000919060ff60e01b1916600160e01b835b021790555050505050565b6002600054610100900460ff161580156116b4575060005460ff8083169116105b6117265760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401611052565b806000806101000a81548160ff021916908360ff1602179055506001600060016101000a81548160ff02191690831515021790555060016002600001601e6101000a81548160ff02191690831515021790555042601160006101000a81548163ffffffff021916908363ffffffff1602179055506040518060a00160405280683635c9adc5dea000006001600160801b031681526020014263ffffffff168152602001600663ffffffff1681526020016103e863ffffffff168152602001601260ff168152506012600080815260200190815260200160002060008201518160000160006101000a8154816001600160801b0302191690836001600160801b0316021790555060208201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001601c6101000a81548160ff021916908360ff1602179055509050506040518060a0016040528069d3c21bcecceda10000006001600160801b031681526020014263ffffffff16815260200161277463ffffffff168152602001620f424063ffffffff168152602001601260ff16815250601260006001815260200190815260200160002060008201518160000160006101000a8154816001600160801b0302191690836001600160801b0316021790555060208201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001601c6101000a81548160ff021916908360ff1602179055509050507f2c87e4aece114a15933668e808bd3756196c2fb05a4902851081ed8584f8690e600060066103e8604051611a3c939291909283526020830191909152604082015260600190565b60405180910390a160408051600181526127746020820152620f42408183015290517f2c87e4aece114a15933668e808bd3756196c2fb05a4902851081ed8584f8690e9181900360600190a1600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b600254600090600160e81b900460ff1615611b1757604051632a6ab56360e21b815260040160405180910390fd5b600254600160e01b900460ff166001816002811115611b3857611b38615ab7565b1415611f3c576000838152600c60205260409020805460019091015481611b8b576040517f973e3ae300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611b9683613675565b9050600080600080611ba8858b6138e5565b60046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19a63ffffffff8c160154939750919550935091506001600160a01b031680611c21576040517fbb65988600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600c60008d815260200190815260200160002060000181905550600060405180606001604052808981526020018d81526020018860c0015167ffffffffffffffff1681525090506000806000846001600160a01b0316639b07d3428a8a8a8a89602001518a604001516040518763ffffffff1660e01b8152600401611cad96959493929190615b58565b6060604051808303816000875af1158015611ccc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf09190615bb2565b92509250925080611d26575050506020908101516000908152600c90915260408120989098555095975061133d95505050505050565b600082118015611d4b5750600086604001516003811115611d4957611d49615ab7565b145b15611d85576040517f26e939c600000000000000000000000000000000000000000000000000000000815260048101839052602401611052565b82158015611d91575081155b15611dc357611daa858a86600001518760200151613bcb565b611dbe858986600001518760200151613bcb565b611de3565b611dd38588858760200151613bcb565b611de38587848760200151613bcb565b6000845160208601516000851460008714161592506040518f81528160208201528260408201528660608201528560808201528360a08201526020600060c08360025afa505050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600051066002548060c01c6103ff168160d01c6103ff166102008183600101011115611e8357632c52558760e11b60005260046000fd5b50600081815260056020908152604080832095909555600190920160c090811b7ffffffffffffffc00ffffffffffffffffffffffffffffffffffffffffffffffff909416939093176002558882015189518551908152928301899052938201879052841515606083015260a0608083018190528201528f917f692cf5822a02f5edf084dc7249b3a06293621e069f11975ed70908ed10ed2e2c910160405180910390a360019e505050505050505050505050505061133d565b6000816002811115611f5057611f50615ab7565b1415612376576002805460ff60e01b1916600160e01b1790556000838152600c6020526040902080546001919091015481611fb7576040517f973e3ae300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611fc283613675565b9050600080600080611fd4858b6138e5565b60046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19a63ffffffff8c160154939750919550935091506001600160a01b03168061204d576040517fbb65988600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600c60008d815260200190815260200160002060000181905550600060405180606001604052808981526020018d81526020018860c0015167ffffffffffffffff1681525090506000806000846001600160a01b0316639b07d3428a8a8a8a89602001518a604001516040518763ffffffff1660e01b81526004016120d996959493929190615b58565b6060604051808303816000875af11580156120f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211c9190615bb2565b92509250925080612152575050506020908101516000908152600c90915260408120989098555095975061236495505050505050565b600082118015612177575060008660400151600381111561217557612175615ab7565b145b156121b1576040517f26e939c600000000000000000000000000000000000000000000000000000000815260048101839052602401611052565b821580156121bd575081155b156121ef576121d6858a86600001518760200151613bcb565b6121ea858986600001518760200151613bcb565b61220f565b6121ff8588858760200151613bcb565b61220f8587848760200151613bcb565b6000845160208601516000851460008714161592506040518f81528160208201528260408201528660608201528560808201528360a08201526020600060c08360025afa505050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600051066002548060c01c6103ff168160d01c6103ff1661020081836001010111156122af57632c52558760e11b60005260046000fd5b50600081815260056020908152604080832095909555600190920160c090811b7ffffffffffffffc00ffffffffffffffffffffffffffffffffffffffffffffffff909416939093176002558882015189518551908152928301899052938201879052841515606083015260a0608083018190528201528f917f692cf5822a02f5edf084dc7249b3a06293621e069f11975ed70908ed10ed2e2c910160405180910390a360019e50505050505050505050505050505b6002805460ff60e01b1916905561133d565b604051631e7b117d60e01b815260040160405180910390fd5b600254600160e81b900460ff16156123ba57604051632a6ab56360e21b815260040160405180910390fd5b7fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b266123e48161312e565b600060028054600160e01b900460ff169081111561240457612404615ab7565b1461242257604051631e7b117d60e01b815260040160405180910390fd5b600280547fffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167d0102000000000000000000000000000000000000000000000000000000001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200161116e565b600254600160e81b900460ff16156124c557604051632a6ab56360e21b815260040160405180910390fd5b3360009081527f65ab7acc1bb8390bd4d3ba8eb4987cf212c814cedeacf3ad4b0583b29d65f538602052604090205460ff1615801561250e5750600a54600160a01b900460ff16155b15612545576040517f11d74fb800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060028054600160e01b900460ff169081111561256557612565615ab7565b1461258357604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0382163b6125be576040516310a0493960e11b815260040160405180910390fd5b6188b88110806125d05750624c4b4081115b15612607576040517f037bbe6d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480546001810182557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03851690811790915590546000818152600f6020908152604091829020859055905184815291929183917f0e62be7fe47a9095143143f8ee61bab3ade27b661223fed33e16122ffe1f284d91015b60405180910390a350600280546000919060ff60e01b1916600160e01b83610f30565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e6126ee8161312e565b600060028054600160e01b900460ff169081111561270e5761270e615ab7565b1461272c57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0383166000818152600b6020908152604091829020805460ff1916861515908117909155825190815291517f46359ce9dbb6c7f9a375b44072210287916d3de725fc8927a8e762047e4a84249281900390910190a250506002805460ff60e01b1916905550565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e6127d78161312e565b600060028054600160e01b900460ff16908111156127f7576127f7615ab7565b1461281557604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b179055600a8054831515600160a01b81027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff909216919091179091556040519081527fad6b1fc8881be24fc1ad35119b136f0026a4496e6251980e325ddcf86dab394390602001610f11565b7ff94103142c1baabe9ac2b5d1487bf783de9e69cfeea9a72f5c9c94afd7877b8c6128bb8161312e565b600060028054600160e01b900460ff16908111156128db576128db615ab7565b146128f957604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556040805160a081019091528061293b61292685600a615ccf565b6129369063ffffffff8816615cde565b613c86565b6001600160801b03908116825263ffffffff4281166020808501919091528882166040808601829052898416606080880182905260ff8b81166080998a015260008f8152601287528490208a5181548c8901518d8801518e8701519e909d0151909416600160e01b0260ff60e01b199d8b16600160c01b027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9d8c16600160a01b029d909d167fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff95909b167001000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff1990921692909b169190911717919091169690961797909717979097169490941790925582518a815290810191909152908101929092527f2c87e4aece114a15933668e808bd3756196c2fb05a4902851081ed8584f8690e910160405180910390a150506002805460ff60e01b19169055505050565b60008043817f0000000000000000000000000000000000000000000000000000000000000870612af47f000000000000000000000000000000000000000000000000000000000000096084615d13565b1015905060008115612b8457601154612b1d9063ffffffff640100000000820481169116615d27565b421015612b2957600091505b612b537f000000000000000000000000000000000000000000000000000000000000096084615d13565b612b7d907f0000000000000000000000000000000000000000000000000000000000000960615acd565b9050612bdb565b612bae7f000000000000000000000000000000000000000000000000000000000000096084615d13565b612bd8907f0000000000000000000000000000000000000000000000000000000000000870615acd565b90505b9094909350915050565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e612c0f8161312e565b600060028054600160e01b900460ff1690811115612c2f57612c2f615ab7565b14612c4d57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0382163b612c88576040516310a0493960e11b815260040160405180910390fd5b600a805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0384169081179091556040519081527fc4fc5cbf094d63a6fb20dc7cb9b0236e7dba8c04667182ec259a00a74f95901890602001610f11565b60008281526001602081905260409091200154612cff8161312e565b610fd383836131c2565b60006004612d18600184615acd565b81548110612d2857612d28615ae4565b6000918252602090912001546001600160a01b031692915050565b600254600160e81b900460ff1615612d6e57604051632a6ab56360e21b815260040160405180910390fd5b336000526008602052604060002060205280600052600160406000205550565b600254600160e81b900460ff1615612db957604051632a6ab56360e21b815260040160405180910390fd5b600060028054600160e01b900460ff1690811115612dd957612dd9615ab7565b14612df757604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e01b179055336000908152600b602052604090205460ff1615612e4f57600254600160f01b900460ff1615612e4a576011805463ffffffff19164263ffffffff161790555b612e95565b6000612e59612aa4565b50905080612e93576040517f83633aab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b6000806000612ea2613ccd565b9250925092506000612eb384614069565b9050612efa8487878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250889250879150869050614088565b612f0484826140f2565b5050600280546000935090915060ff60e01b1916600160e01b83611688565b600254600160e81b900460ff1615612f4e57604051632a6ab56360e21b815260040160405180910390fd5b3360009081527f65ab7acc1bb8390bd4d3ba8eb4987cf212c814cedeacf3ad4b0583b29d65f538602052604090205460ff16158015612f975750600a54600160a01b900460ff16155b15612fce576040517f11d74fb800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060028054600160e01b900460ff1690811115612fee57612fee615ab7565b1461300c57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0382163b613047576040516310a0493960e11b815260040160405180910390fd5b61d6d881108061305957506216e36081115b15613090576040517f11e80d6c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380546001810182557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03851690811790915590546000818152600e6020908152604091829020859055905184815291929183917f85ac039d1da307b778050ca29271ac915424bac011342c9452960f6679b18ff091016126a1565b6131388133614177565b50565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff166110655760008281526001602081815260408084206001600160a01b0386168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff16156110655760008281526001602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b82631fffffff81111561326b57604051630104ef3360e21b815260040160405180910390fd5b60008481526007602090815260408083206001600160a01b0387168452909152902054600254600160f01b900460ff16156135be576000858152601260209081526040808320815160a08101835290546001600160801b038116825263ffffffff7001000000000000000000000000000000008204811694830194909452600160a01b8104841692820192909252600160c01b8204909216606083015260ff600160e01b909104166080820181905290919061332890600a615ccf565b9050816040015163ffffffff1660001480613360575080826040015163ffffffff166133549190615cde565b61335e8685615d27565b115b15613397576040517ffb1837c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015163ffffffff166133d8576040517fd014828600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081836060015163ffffffff166133f09190615cde565b905060006134016201518083615d3f565b9050613426846020015163ffffffff164261341c9190615acd565b6129369083615cde565b84518590613435908390615d53565b6001600160801b0390811690915285511683101590506134645761345882613c86565b6001600160801b031684525b83516001600160801b03168711156134a8576040517fd014828600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6134b187613c86565b845185906134c0908390615d75565b6001600160801b0390811690915263ffffffff428116602080890191825260008e81526012909152604090819020895181549351928b015160608c015160808d015160ff16600160e01b0260ff60e01b19918816600160c01b027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff938916600160a01b02939093167fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff969098167001000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff199097169390981692909217949094179290921693909317919091171691909117905550505050505b6135c88382615d27565b60009586526007602090815260408088206001600160a01b0390971688529590529390942092909255505050565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152836004820152826024820152816044820152843b613645576310a0493960e11b60005260046000fd5b602060006064836000895af190506001600051163d151780821661366d573d6000803e3d6000fd5b505050505050565b604080516101c081018252600060208083018290526101a083019190915263ffffffff8416808352633fffffff9185901c821693830193909352603e84901c81166060830152605c84901c81166080830152607a84901c1660a082015267ffffffffffffffff60b884901c1660c08201526001603d84901c811660e0830152605b84901c8116610100830152607984901c8116610120830152609784901c8116610140830152609884901c81168114610160830152609984901c81168114610180830152909160049161374791615acd565b8154811061375757613757615ae4565b60009182526020808320909101546001600160a01b03168382015282518252600f905260409020546101a082015261016081015115801561379c575060008160600151115b156137d3576040517f3448066300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061018001511580156137ea575060008160a00151115b15613821576040517f3448066300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806101600151801561383a575080606001518160400151145b156138795780604001516040517f760558e800000000000000000000000000000000000000000000000000000000815260040161105291815260200190565b600081610180015180156138905750816101400151155b90508080156138a657508160a001518260800151145b1561133d5781608001516040517ff23e3f9500000000000000000000000000000000000000000000000000000000815260040161105291815260200190565b61390660408051606081018252600080825260208201819052909182015290565b61392760408051606081018252600080825260208201819052909182015290565b61394860408051606081018252600080825260208201819052909182015290565b61396960408051606081018252600080825260208201819052909182015290565b8560e001511561399c57632000000086604001516139879190615acd565b845260006020850152600360408501526139fa565b6040860180518552516139ae90611297565b6001600160a01b031660208501819052156139ca5760026139cd565b60015b846040019060038111156139e3576139e3615ab7565b908160038111156139f6576139f6615ab7565b9052505b85610120015115613a1b578482526000602083015260036040830152613a79565b608086018051835251613a2d90611297565b6001600160a01b03166020830181905215613a49576002613a4c565b60015b82604001906003811115613a6257613a62615ab7565b90816003811115613a7557613a75615ab7565b9052505b85610100015115613ac35763200000008660600151613a989190615acd565b8352600060208401526040830160035b90816003811115613abb57613abb615ab7565b905250613b27565b85610160015115613b1557606086018051845251613ae090611297565b6001600160a01b03166020840181905215613afc576002613aff565b60015b83604001906003811115613aa857613aa8615ab7565b60008084526020840181905260408401525b85610140015115613b5e57848152600060208201526040810160035b90816003811115613b5657613b56615ab7565b905250613bc2565b85610180015115613bb05760a086018051825251613b7b90611297565b6001600160a01b03166020820181905215613b97576002613b9a565b60015b81604001906003811115613b4357613b43615ab7565b60008082526020820181905260408201525b92959194509250565b81613bd557613c80565b600183604001516003811115613bed57613bed615ab7565b1415613c4f576000818152600d6020526040902054821115613c3b576040517fcbbf6eca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600d6020526040812055613c80565b600283604001516003811115613c6757613c67615ab7565b1415613c80576020830151613c7e818630866135f6565b505b50505050565b60006001600160801b03821115613cc9576040517f7a781de100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090565b6040805161010080820183526141ec82526141f360208084018290528385019190915261421e606084018190526080840181905260a0840181905260c084015261423360e084015283516111c46004359081013560448201359081046111c883013563ffffffff908116828104808402821415019092029096028481016111e0019098526111c08881018086529498919760009795968a0195602486019589948594615755949391926111cc013590911690888a376111c098909801976111a9888101988a97509091010193505b86841115613dd15760078735168089528060051b830151935050613dc387898563ffffffff16565b965061010088019750613d9b565b505050506111c088810151604051600092828604808c048082028d1415019384900393909261010084029260043560240182376111c08101905060208202810191505b81811015613e635760206000848960025afa613e2f57600080fd5b6000517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000019006815295820195602001613e14565b8415613fe057600092508360208114613eaf5760108114613ed75760408114613eff5760018114613f275760028114613f4f5760048114613f775760088114613f9f5760019650613fc3565b7f0df0e06ab8a02ce2ff08babd7144ab23ca2e99ddf318080cf88602eeb8913d449350613fc3565b7f1c52c159b4dae66c3dcf33b44d4d61ead6bc4d260f882ac6ba34dccf78892ca49350613fc3565b7f1f83672815ac9b3ca31732d641784035834e96b269eaf6a2e759bf4fcc8e5bfd9350613fc3565b7f22dd983f8337d97d56071f7986209ab2ee6039a422242e89126701c6ee005af09350613fc3565b7f076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f365609350613fc3565b7f2f0c70a5bf5460465e9902f9c96be324e8064e762a5de52589fdb97cbce3c6ee9350613fc3565b7f240ed0de145447ff0ceff2aa477f43e0e2ed7f3543ee3d8832f158ec76b183a993505b5060208502820191505b81811015613fe057828152602001613fcd565b6040519450602060008683038760025afa613ffa57600080fd5b50505050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600051069650801561405e576040517f3259ec1e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050909192565b6111a08101516001600160a01b0381111561408357600080fd5b919050565b60006140948684614267565b90506140a1868587614338565b60006140ad8784614400565b9050817f14054a15b39bfd65ec00fc6d15c7e5f9cbc1dc6f452cbefa359b4da61ad89fb682336040516140e1929190615d9d565b60405180910390a250505050505050565b60005b6010811015610fd3576000614111848360200201610b80015190565b9050801561416e576000614125858461493e565b90508061413e57600080600080858861c350f15061416c565b600061414982611297565b905061416a818685600e60008781526020019081526020016000205461495a565b505b505b506001016140f5565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff16611065576141aa816149aa565b6141b58360206149bc565b6040516020016141c6929190615e1d565b60408051601f198184030181529082905262461bcd60e51b825261105291600401615e9e565b5060010190565b600060a0602084016020840137601460c0840160cc840137600460d4840160fc840137505060b90190565b60006080602084016020840137505060810190565b60006040517fd0426f7b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405160009063ffffffff600480356111cc810135929092168083016111ec01939290910135037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee38019060ac815360316001820153608c6002820153605d600382015360406004820152846024820152816044820152818360648301376001600160a01b03600254169250823b614309576310a0493960e11b60005260046000fd5b6000806064840183865afa9250505080614327573d6000803e3d6000fd5b5061433183614be5565b9392505050565b60006111e08085019061010085028601015b8082101561366d5760a082015180156143f357825160e084015160c085015160018314156143db5761010086206001600160a01b038216600090815260086020908152604080832084845290915290205460ff166143ce5788880180516060825260006143b684614d98565b90506143c3818487614eb1565b509052606097909701965b6143d9838387614ffd565b505b82600214156143ef576143ef84828461507e565b5050505b610100830192505061434a565b606060008061441185611180015190565b9050601054811461445c576010546040517f88011dd6000000000000000000000000000000000000000000000000000000008152611052918391600401918252602082015260400190565b6000614466615101565b90935090506144758184615acd565b600280547ffffffffffc00ffffffffffffffffffffffffffffffffffffffffffffffffffff1660d083901b1790556020878101519194506000935091506144bc9190615cde565b6040805160808082018352600080835260208301819052828401819052606090920182905282519081019092529192506101808701915b6020811015614870578251806145095750614870565b61040084015180614546576040517fb246041300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061455183613675565b9050600080600080614563858c6138e5565b93509350935093506040517f4bd947a800000000000000000000000000000000000000000000000000000000815260048101905060208601518082525084516020820152602085015160408201526040850151606082015283516080820152602084015160a0820152604084015160c0820152825160e082015260208301516101008201526040830151610120820152815161014082015260208201516101608201526040820151610180820152866101a08201528b6101c082015260c0860151806101e083015250600d6102008201528e610220820152600a54803b614655576310a0493960e11b60005260046000fd5b60008061024460048503846101a08c0151f490503d6000833e80600181146146955760008c52600060208d0152600060408d0152600060608d01526146b5565b82518c52602083015160208d0152604083015160408d0152600160608d01525b5050508461018001516146ca57600060208a01525b60408901516001811461480a576040518781528a51602082015260208b0151604082015260608b0151606082015260a0608082015260608b01511561473857600060a08201528c897f692cf5822a02f5edf084dc7249b3a06293621e069f11975ed70908ed10ed2e2c60c084a35b60608b0151614792573d60a08201523d602081066020038115150281600060c085013e60008260c0018401528e8b7f692cf5822a02f5edf084dc7249b3a06293621e069f11975ed70908ed10ed2e2c83850160c00186a350505b8881528c60208201528760408201528a51606082015260208b0151608082015260608b015160a08201526020600060c08360025afa50507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600051068d6000526006602052806040600020555060018d019c50614851565b6040518781528c897f38ce48f4c2f3454bcf130721f25a4262b2ff2c8e36af937b30edf01ba481eb1d602084a3508b600052600c6020526040600020888155876001820155505b5060018b019a5060208a019950876001019750505050505050506144f3565b506002548060c01c6103ff166103ff86820111801561489a57632c52558760e11b60005260046000fd5b506040516006602052600560605260005b828110156148cf5787810160009081526040828152808020549120556001016148ab565b506040527ffffffffffffffc00ffffffffffffffffffffffffffffffffffffffffffffffff90860160d01b167ffffffffffc00fc00ffffffffffffffffffffffffffffffffffffffffffffffff9091161760025560008061492e615123565b6010559998505050505050505050565b602081028201610980015163ffffffff811115610da657600080fd5b5a81156149645750805b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815284600482015283602482015260008060448360008a87f150505050505050565b6060610da66001600160a01b03831660145b606060006149cb836002615cde565b6149d6906002615d27565b67ffffffffffffffff8111156149ee576149ee615ed1565b6040519080825280601f01601f191660200182016040528015614a18576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110614a4f57614a4f615ae4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110614ab257614ab2615ae4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000614aee846002615cde565b614af9906001615d27565b90505b6001811115614b96577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110614b3a57614b3a615ae4565b1a60f81b828281518110614b5057614b50615ae4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93614b8f81615ee7565b9050614afc565b5083156143315760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401611052565b600080600080600080614bf7876151ff565b945094509450945094506009548414614c46576040517f34fddf400000000000000000000000000000000000000000000000000000000081526004810185905260248101849052604401611052565b60025463ffffffff600160a01b90910481169083168181614c6957614c69615cfd565b0663ffffffff1660001415614cd2578063ffffffff168263ffffffff1614614ccd576040517f7861e6c600000000000000000000000000000000000000000000000000000000815263ffffffff808416600483015282166024820152604401611052565b614d4c565b60008363ffffffff168263ffffffff1681614cef57614cef615cfd565b068483010363ffffffff169050808363ffffffff1614614d4a576040517f7861e6c600000000000000000000000000000000000000000000000000000000815263ffffffff8416600482015260248101829052604401611052565b505b506009929092556002805463ffffffff9390920192909216600160a01b027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9091161790555092915050565b600080614da4836152a8565b90506040517f19457468657265756d205369676e6564204d6573736167653a0a32313000000060208201527f5369676e696e672074686973206d6573736167652077696c6c20616c6c6f7720603d8201527f796f75722070656e64696e672066756e647320746f206265207370656e742069605d8201527f6e20417a746563207472616e73616374696f6e3a0a0a30780000000000000000607d82015260208201516095820152604082015160b58201527f0a0a494d504f5254414e543a204f6e6c79207369676e20746865206d6573736160d58201527f676520696620796f752074727573742074686520636c69656e7400000000000060f582015260ef602082012092505050919050565b6000806001600160a01b038316614ef4576040517fd57e351000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8351858552606085015160408601518060608801526020870151604088015281602088015260208760808960015afa601c8314601b84141760608514167f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a183101616945050508451861460008114614f6b57614f70565b855192505b508452801519919091169081614fb2576040517f8a3e28aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b0316816001600160a01b031614613c7e576040517fa3402a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82631fffffff81111561502357604051630104ef3360e21b815260040160405180910390fd5b60008481526007602090815260408083209091528482529020805483810390915582118015613c7e576040517f8e8af4f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0382166150be576040517f6df19fea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806150d5576000806000808686617530f150505050565b60006150e082611297565b9050613c80818486600e60008781526020019081526020016000205461495a565b6002546103ff60d082901c16908190602082111561511e57602091505b509091565b60606000806000615132615101565b909250905060006151438284615acd565b90506040519450602085016020610400018601604052828652600660205260005b83811015615188578281016000908152604090205460208202830152600101615164565b5b60208110156151c2577f2d25a1e3a51eb293004c4b56abe12ed0da6bca2b4a21936752a85d102593c1b460208202830152600101615189565b50602060006104008360025afa50507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016000510693505050509091565b604081015160608201516000918291829160011b906020860163ffffffff808411908311171561522e57600080fd5b805195506040518681526060820151602082015260a0820151604082015260e08201516060820152610120820151608082015260a0812095506001870181526080820151602082015260c082015160408201526101008201516060820152610140820151608082015260a081209450505091939590929450565b606081615310576040519050604081527f303030303030303030303030303030303030303030303030303030303030303060208201527f3030303030303030303030303030303030303030303030303030303030303030604082015260608101604052919050565b506040517f3030303130323033303430353036303730383039306130623063306430653066607e8201527f3130313131323133313431353136313731383139316131623163316431653166609e8201527f323032313232323332343235323632373238323932613262326332643265326660be8201527f333033313332333333343335333633373338333933613362336333643365336660de8201527f343034313432343334343435343634373438343934613462346334643465346660fe8201527f353035313532353335343535353635373538353935613562356335643565356661011e8201527f363036313632363336343635363636373638363936613662366336643665366661013e8201527f373037313732373337343735373637373738373937613762376337643765376661015e8201527f383038313832383338343835383638373838383938613862386338643865386661017e8201527f393039313932393339343935393639373938393939613962396339643965396661019e8201527f61306131613261336134613561366137613861396161616261636164616561666101be8201527f62306231623262336234623562366237623862396261626262636264626562666101de8201527f63306331633263336334633563366337633863396361636263636364636563666101fe8201527f643064316432643364346435643664376438643964616462646364646465646661021e8201527f653065316532653365346535653665376538653965616562656365646565656661023e8201527f663066316632663366346635663666376638663966616662666366646665666661025e820152606081018260408352600181901b6101fe908116830151601e52600782901c8116830151601c52600f82901c8116830151601a52601782901c8116830151601852601f82901c8116830151601652602782901c8116830151601452602f82901c8116830151601252603782901c8116830151601052603f82901c8116830151600e52604782901c8116830151600c52604f82901c8116830151600a52605782901c8116830151600852605f82901c8116830151600652606782901c8116830151600452606f82901c8116830151600252607782901c16820151600052601e51604084015260801c61573f82826101fe600182901b8116830151601e52600782901c8116830151601c52600f82901c8116830151601a52601782901c8116830151601852601f82901c8116830151601652602782901c8116830151601452602f82901c8116830151601252603782901c8116830151601052603f82901c8116830151600e52604782901c8116830151600c52604f82901c8116830151600a52605782901c8116830151600852605f82901c8116830151600652606782901c8116830151600452606f82901c811683015160025260779190911c160151600052565b5050601e51602082015260608101604052919050565b61575d615efe565b565b60006020828403121561577157600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461433157600080fd5b6000602082840312156157b357600080fd5b5035919050565b801515811461313857600080fd5b6000602082840312156157da57600080fd5b8135614331816157ba565b60008083601f8401126157f757600080fd5b50813567ffffffffffffffff81111561580f57600080fd5b60208301915083602082850101111561582757600080fd5b9250929050565b60008060008060006080868803121561584657600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff81111561587257600080fd5b61587e888289016157e5565b969995985093965092949392505050565b80356001600160a01b038116811461408357600080fd5b600080604083850312156158b957600080fd5b823591506158c96020840161588f565b90509250929050565b6000602082840312156158e457600080fd5b6143318261588f565b803563ffffffff8116811461408357600080fd5b60006020828403121561591357600080fd5b614331826158ed565b6000806040838503121561592f57600080fd5b6159388361588f565b946020939093013593505050565b6000806000806080858703121561595c57600080fd5b84359350602085013592506159736040860161588f565b9396929550929360600135925050565b6000806040838503121561599657600080fd5b61599f8361588f565b915060208301356159af816157ba565b809150509250929050565b600080600080608085870312156159d057600080fd5b843593506159e0602086016158ed565b92506159ee604086016158ed565b9150606085013560ff81168114615a0457600080fd5b939692955090935050565b60008060008060408587031215615a2557600080fd5b843567ffffffffffffffff80821115615a3d57600080fd5b615a49888389016157e5565b90965094506020870135915080821115615a6257600080fd5b50615a6f878288016157e5565b95989497509550505050565b634e487b7160e01b600052601160045260246000fd5b600061ffff808316818516808303821115615aae57615aae615a7b565b01949350505050565b634e487b7160e01b600052602160045260246000fd5b600082821015615adf57615adf615a7b565b500390565b634e487b7160e01b600052603260045260246000fd5b600060208284031215615b0c57600080fd5b5051919050565b805182526001600160a01b036020820151166020830152604081015160048110615b4d57634e487b7160e01b600052602160045260246000fd5b806040840152505050565b6101c08101615b678289615b13565b615b746060830188615b13565b615b8160c0830187615b13565b615b8f610120830186615b13565b8361018083015267ffffffffffffffff83166101a0830152979650505050505050565b600080600060608486031215615bc757600080fd5b83519250602084015191506040840151615be0816157ba565b809150509250925092565b600181815b80851115615c26578160001904821115615c0c57615c0c615a7b565b80851615615c1957918102915b93841c9390800290615bf0565b509250929050565b600082615c3d57506001610da6565b81615c4a57506000610da6565b8160018114615c605760028114615c6a57615c86565b6001915050610da6565b60ff841115615c7b57615c7b615a7b565b50506001821b610da6565b5060208310610133831016604e8410600b8410161715615ca9575081810a610da6565b615cb38383615beb565b8060001904821115615cc757615cc7615a7b565b029392505050565b600061433160ff841683615c2e565b6000816000190483118215151615615cf857615cf8615a7b565b500290565b634e487b7160e01b600052601260045260246000fd5b600082615d2257615d22615cfd565b500690565b60008219821115615d3a57615d3a615a7b565b500190565b600082615d4e57615d4e615cfd565b500490565b60006001600160801b03808316818516808303821115615aae57615aae615a7b565b60006001600160801b0383811690831681811015615d9557615d95615a7b565b039392505050565b604080825283519082018190526000906020906060840190828701845b82811015615dd657815184529284019290840190600101615dba565b5050506001600160a01b039490941692019190915250919050565b60005b83811015615e0c578181015183820152602001615df4565b83811115613c805750506000910152565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351615e55816017850160208801615df1565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351615e92816028840160208801615df1565b01602801949350505050565b6020815260008251806020840152615ebd816040850160208701615df1565b601f01601f19169190910160400192915050565b634e487b7160e01b600052604160045260246000fd5b600081615ef657615ef6615a7b565b506000190190565b634e487b7160e01b600052605160045260246000fdfea26469706673582212204986047a3c1dc740c0f7b2da538464da5d8465856c4b6d0dec03c81aa8d6df1564736f6c634300080a0033

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

00000000000000000000000000000000000000000000000000000000000008700000000000000000000000000000000000000000000000000000000000000960

-----Decoded View---------------
Arg [0] : _escapeBlockLowerBound (uint256): 2160
Arg [1] : _escapeBlockUpperBound (uint256): 2400

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000870
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000960


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

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.