ETH Price: $1,671.73 (+2.51%)
Gas: 7 Gwei
 
Transaction Hash
Method
Block
From
To
Value
Process Rollup182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023IN
Aztec: Private Rollup Bridge
0 ETH0.021938412.73212624
Process Rollup182193402023-09-26 10:25:112 days 23 hrs ago1695723911IN
Aztec: Private Rollup Bridge
0 ETH0.0234042618.07581906
Process Rollup182050212023-09-24 10:20:114 days 23 hrs ago1695550811IN
Aztec: Private Rollup Bridge
0 ETH0.009921269.1955241
Process Rollup181907232023-09-22 10:15:236 days 23 hrs ago1695377723IN
Aztec: Private Rollup Bridge
0 ETH0.0117248411.3007065
Process Rollup181764152023-09-20 10:10:239 days 1 min ago1695204623IN
Aztec: Private Rollup Bridge
0 ETH0.0158230413.28361993
Deposit Pending ...181627162023-09-18 12:06:1110 days 22 hrs ago1695038771IN
Aztec: Private Rollup Bridge
0.014689 ETH0.0005503710.14377549
Process Rollup181621262023-09-18 10:05:2311 days 6 mins ago1695031523IN
Aztec: Private Rollup Bridge
0 ETH0.0152370911.48967675
Process Rollup181479802023-09-16 10:00:2313 days 11 mins ago1694858423IN
Aztec: Private Rollup Bridge
0 ETH0.0119735811.54058003
Process Rollup181236852023-09-13 0:01:3516 days 10 hrs ago1694563295IN
Aztec: Private Rollup Bridge
0 ETH0.0109686610.57188352
Process Rollup181093852023-09-10 23:56:3518 days 10 hrs ago1694390195IN
Aztec: Private Rollup Bridge
0 ETH0.011177210.51869266
Process Rollup180848492023-09-07 13:29:1121 days 20 hrs ago1694093351IN
Aztec: Private Rollup Bridge
0 ETH0.0189040117.25723986
Process Rollup180705552023-09-05 13:24:1123 days 20 hrs ago1693920251IN
Aztec: Private Rollup Bridge
0 ETH0.0169995116.38589139
Process Rollup180537412023-09-03 4:59:4726 days 5 hrs ago1693717187IN
Aztec: Private Rollup Bridge
0 ETH0.013197212.71966166
Process Rollup180388492023-09-01 2:53:4728 days 7 hrs ago1693536827IN
Aztec: Private Rollup Bridge
0 ETH0.0167177814.14809589
Process Rollup180245442023-08-30 2:48:4730 days 7 hrs ago1693363727IN
Aztec: Private Rollup Bridge
0 ETH0.0229593321.27891539
Process Rollup180102362023-08-28 2:43:4732 days 7 hrs ago1693190627IN
Aztec: Private Rollup Bridge
0 ETH0.014293813.77658038
Process Rollup179917722023-08-25 12:41:2334 days 21 hrs ago1692967283IN
Aztec: Private Rollup Bridge
0 ETH0.0222684521.17887042
Process Rollup179774482023-08-23 12:36:2336 days 21 hrs ago1692794183IN
Aztec: Private Rollup Bridge
0 ETH0.0198658219.14763353
Process Rollup179631242023-08-21 12:31:2338 days 21 hrs ago1692621083IN
Aztec: Private Rollup Bridge
0 ETH0.0256089322.91282775
Deposit Pending ...179607722023-08-21 4:39:1139 days 5 hrs ago1692592751IN
Aztec: Private Rollup Bridge
0.01683 ETH0.0009692917.86488262
Process Rollup179488102023-08-19 12:26:2340 days 21 hrs ago1692447983IN
Aztec: Private Rollup Bridge
0 ETH0.0184184717.75220094
Process Rollup179215182023-08-15 16:46:2344 days 17 hrs ago1692117983IN
Aztec: Private Rollup Bridge
0 ETH0.0355507332.94873984
Process Rollup179071952023-08-13 16:41:2346 days 17 hrs ago1691944883IN
Aztec: Private Rollup Bridge
0 ETH0.0228681621.03589189
Process Rollup178928782023-08-11 16:36:2348 days 17 hrs ago1691771783IN
Aztec: Private Rollup Bridge
0 ETH0.0310523229.92937454
Process Rollup178667252023-08-08 0:47:3552 days 9 hrs ago1691455655IN
Aztec: Private Rollup Bridge
0 ETH0.016985816.37192178
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Advanced Filter
Parent Txn Hash Block From To Value
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.125811 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.00459 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.014515 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.018265 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.016715 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.013215 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.005515 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.010736 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.008976 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.008413 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.017413 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.009973 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.007413 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.006413 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.039813 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.051913 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.056413 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.045313 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.046513 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.034313 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.04588 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.02718 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.03988 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.00388 ETH
182336472023-09-28 10:30:2323 hrs 41 mins ago1695897023
Aztec: Private Rollup Bridge
0.03674 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
RollupProcessor

Compiler Version
v0.6.10+commit.00c0fcaf

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 14 : RollupProcessor.sol
// SPDX-License-Identifier: GPL-2.0-only
// Copyright 2020 Spilsbury Holdings Ltd.
pragma solidity >=0.6.10 <0.8.0;

import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
import {Pausable} from '@openzeppelin/contracts/utils/Pausable.sol';
import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol';

import {IVerifier} from './interfaces/IVerifier.sol';
import {IRollupProcessor} from './interfaces/IRollupProcessor.sol';
import {IFeeDistributor} from './interfaces/IFeeDistributor.sol';
import {IERC20Permit} from './interfaces/IERC20Permit.sol';
import {Decoder} from './Decoder.sol';
import './libraries/RollupProcessorLibrary.sol';

/**
 * @title Rollup Processor
 * @dev Smart contract responsible for processing Aztec zkRollups, including relaying them to a verifier
 * contract for validation and performing all relevant ERC20 token transfers
 */
contract RollupProcessor is IRollupProcessor, Decoder, Ownable, Pausable {
    using SafeMath for uint256;

    bytes32 public dataRoot = 0x2708a627d38d74d478f645ec3b4e91afa325331acf1acebe9077891146b75e39;
    bytes32 public nullRoot = 0x2694dbe3c71a25d92213422d392479e7b8ef437add81e1e17244462e6edca9b1;
    bytes32 public rootRoot = 0x2d264e93dc455751a721aead9dba9ee2a9fef5460921aeede73f63f6210e6851;

    uint256 public dataSize;
    uint256 public nextRollupId;

    IVerifier public verifier;

    uint256 public constant numberOfAssets = 4;
    uint256 public constant txNumPubInputs = 12;
    uint256 public constant rollupNumPubInputs = 10 + numberOfAssets;
    uint256 public constant txPubInputLength = txNumPubInputs * 32; // public inputs length for of each inner proof tx
    uint256 public constant rollupPubInputLength = rollupNumPubInputs * 32;
    uint256 public constant ethAssetId = 0;
    uint256 public immutable escapeBlockLowerBound;
    uint256 public immutable escapeBlockUpperBound;

    event RollupProcessed(
        uint256 indexed rollupId,
        bytes32 dataRoot,
        bytes32 nullRoot,
        bytes32 rootRoot,
        uint256 dataSize
    );
    event Deposit(uint256 assetId, address depositorAddress, uint256 depositValue);
    event Withdraw(uint256 assetId, address withdrawAddress, uint256 withdrawValue);
    event WithdrawError(bytes errorReason);
    event AssetAdded(uint256 indexed assetId, address indexed assetAddress);
    event RollupProviderUpdated(address indexed providerAddress, bool valid);
    event VerifierUpdated(address indexed verifierAddress);

    // Array of supported ERC20 token address.
    address[] public supportedAssets;

    // Mapping which maps an asset address to a bool, determining whether it supports
    // permit as according to ERC-2612
    mapping(address => bool) assetPermitSupport;

    // Mapping from assetId to mapping of userAddress to public userBalance stored on this contract
    mapping(uint256 => mapping(address => uint256)) public userPendingDeposits;

    mapping(address => mapping(bytes32 => bool)) public depositProofApprovals;

    mapping(address => bool) public rollupProviders;

    address public override feeDistributor;

    // Metrics
    uint256[] public totalPendingDeposit;
    uint256[] public totalDeposited;
    uint256[] public totalWithdrawn;
    uint256[] public totalFees;

    constructor(
        address _verifierAddress,
        uint256 _escapeBlockLowerBound,
        uint256 _escapeBlockUpperBound,
        address _contractOwner
    ) public {
        verifier = IVerifier(_verifierAddress);
        escapeBlockLowerBound = _escapeBlockLowerBound;
        escapeBlockUpperBound = _escapeBlockUpperBound;
        rollupProviders[msg.sender] = true;
        totalPendingDeposit.push(0);
        totalDeposited.push(0);
        totalWithdrawn.push(0);
        totalFees.push(0);
        transferOwnership(_contractOwner);
    }

    function setRollupProvider(address providerAddress, bool valid) public override onlyOwner {
        rollupProviders[providerAddress] = valid;
        emit RollupProviderUpdated(providerAddress, valid);
    }

    function setVerifier(address _verifierAddress) public override onlyOwner {
        verifier = IVerifier(_verifierAddress);
        emit VerifierUpdated(_verifierAddress);
    }

    function setFeeDistributor(address feeDistributorAddress) public override onlyOwner {
        feeDistributor = feeDistributorAddress;
    }

    /**
     * @dev Approve a proofHash for spending a users deposited funds, this is one way and must be called by the owner of the funds
     * @param _proofHash - keccack256 hash of the inner proof public inputs
     */

    function approveProof(bytes32 _proofHash) public override whenNotPaused {
        depositProofApprovals[msg.sender][_proofHash] = true;
    }

    /**
     * @dev Get the ERC20 token address of a supported asset, for a given assetId
     * @param assetId - identifier used to denote a particular asset
     */
    function getSupportedAsset(uint256 assetId) public view override returns (address) {
        if (assetId == ethAssetId) {
            return address(0x0);
        }

        return supportedAssets[assetId - 1];
    }

    /**
     * @dev Get the addresses of all supported ERC20 tokens
     */
    function getSupportedAssets() external view override returns (address[] memory) {
        return supportedAssets;
    }

    function getTotalDeposited() external view override returns (uint256[] memory) {
        return totalDeposited;
    }

    function getTotalWithdrawn() external view override returns (uint256[] memory) {
        return totalWithdrawn;
    }

    function getTotalPendingDeposit() external view override returns (uint256[] memory) {
        return totalPendingDeposit;
    }

    function getTotalFees() external view override returns (uint256[] memory) {
        return totalFees;
    }

    /**
     * @dev Get the status of whether an asset supports the permit ERC-2612 approval flow
     * @param assetId - unique identifier of the supported asset
     */
    function getAssetPermitSupport(uint256 assetId) external view override returns (bool) {
        address assetAddress = getSupportedAsset(assetId);
        return assetPermitSupport[assetAddress];
    }

    /**
     * @dev Get the status of the escape hatch, specifically retrieve whether the
     * hatch is open and also the number of blocks until the hatch will switch from
     * open to closed or vice versa
     */
    function getEscapeHatchStatus() public view override returns (bool, uint256) {
        uint256 blockNum = block.number;

        bool isOpen = blockNum % escapeBlockUpperBound >= escapeBlockLowerBound;
        uint256 blocksRemaining = 0;
        if (isOpen) {
            // 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);
    }

    /**
     * @dev Get the balance of a user, for a particular asset, held on the user's behalf
     * by this contract
     * @param assetId - unique identifier of the asset
     * @param userAddress - Ethereum address of the user who's balance is being queried
     */
    function getUserPendingDeposit(uint256 assetId, address userAddress) external view override returns (uint256) {
        return userPendingDeposits[assetId][userAddress];
    }

    /**
     * @dev Increase the userPendingDeposits mapping
     */
    function increasePendingDepositBalance(
        uint256 assetId,
        address depositorAddress,
        uint256 amount
    ) internal {
        userPendingDeposits[assetId][depositorAddress] = userPendingDeposits[assetId][depositorAddress].add(amount);
        totalPendingDeposit[assetId] = totalPendingDeposit[assetId].add(amount);
    }

    /**
     * @dev Decrease the userPendingDeposits mapping
     */
    function decreasePendingDepositBalance(
        uint256 assetId,
        address transferFromAddress,
        uint256 amount
    ) internal {
        uint256 userBalance = userPendingDeposits[assetId][transferFromAddress];
        require(userBalance >= amount, 'Rollup Processor: INSUFFICIENT_DEPOSIT');

        userPendingDeposits[assetId][transferFromAddress] = userBalance.sub(amount);
        totalPendingDeposit[assetId] = totalPendingDeposit[assetId].sub(amount);
        totalDeposited[assetId] = totalDeposited[assetId].add(amount);
    }

    /**
     * @dev Set the mapping between an assetId and the address of the linked asset.
     * Protected by onlyOwner
     * @param linkedToken - address of the asset
     * @param supportsPermit - bool determining whether this supports permit
     */
    function setSupportedAsset(address linkedToken, bool supportsPermit) external override onlyOwner {
        require(linkedToken != address(0x0), 'Rollup Processor: ZERO_ADDRESS');

        supportedAssets.push(linkedToken);
        assetPermitSupport[linkedToken] = supportsPermit;

        uint256 assetId = supportedAssets.length;
        require(assetId < numberOfAssets, 'Rollup Processor: MAX_ASSET_REACHED');

        totalPendingDeposit.push(0);
        totalDeposited.push(0);
        totalWithdrawn.push(0);
        totalFees.push(0);

        emit AssetAdded(assetId, linkedToken);
    }

    /**
     * @dev Update the value indicating whether a linked asset supports permit.
     * Protected by onlyOwner
     * @param assetId - unique ID of the asset
     * @param supportsPermit - bool determining whether this supports permit
     */
    function setAssetPermitSupport(uint256 assetId, bool supportsPermit) external override onlyOwner {
        address assetAddress = getSupportedAsset(assetId);
        require(assetAddress != address(0x0), 'Rollup Processor: TOKEN_ASSET_NOT_LINKED');

        assetPermitSupport[assetAddress] = supportsPermit;
    }

    /**
     * @dev Deposit funds as part of the first stage of the two stage deposit. Non-permit flow
     * @param assetId - unique ID of the asset
     * @param amount - number of tokens being deposited
     * @param depositorAddress - address from which funds are being transferred to the contract
     */
    function depositPendingFunds(
        uint256 assetId,
        uint256 amount,
        address depositorAddress
    ) external payable override whenNotPaused {
        if (assetId == ethAssetId) {
            require(msg.value == amount, 'Rollup Processor: WRONG_AMOUNT');

            increasePendingDepositBalance(assetId, depositorAddress, amount);
        } else {
            require(msg.value == 0, 'Rollup Processor: WRONG_PAYMENT_TYPE');

            address assetAddress = getSupportedAsset(assetId);
            internalDeposit(assetId, assetAddress, depositorAddress, amount);
        }
    }

    /**
     * @dev Deposit funds as part of the first stage of the two stage deposit. Permit flow
     * @param assetId - unique ID of the asset
     * @param amount - number of tokens being deposited
     * @param depositorAddress - address from which funds are being transferred to the contract
     * @param spender - address being granted approval to spend the funds
     * @param permitApprovalAmount - amount permit signature is approving
     * @param deadline - when the permit signature expires
     * @param v - ECDSA sig param
     * @param r - ECDSA sig param
     * @param s - ECDSA sig param
     */
    function depositPendingFundsPermit(
        uint256 assetId,
        uint256 amount,
        address depositorAddress,
        address spender,
        uint256 permitApprovalAmount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external override whenNotPaused {
        address assetAddress = getSupportedAsset(assetId);
        IERC20Permit(assetAddress).permit(depositorAddress, spender, permitApprovalAmount, deadline, v, r, s);
        internalDeposit(assetId, assetAddress, depositorAddress, amount);
    }

    /**
     * @dev Deposit funds as part of the first stage of the two stage deposit. Non-permit flow
     * @param assetId - unique ID of the asset
     * @param assetAddress - address of the ERC20 asset
     * @param depositorAddress - address from which funds are being transferred to the contract
     * @param amount - amount being deposited
     */
    function internalDeposit(
        uint256 assetId,
        address assetAddress,
        address depositorAddress,
        uint256 amount
    ) internal {
        // check user approved contract to transfer funds, so can throw helpful error to user
        uint256 rollupAllowance = IERC20(assetAddress).allowance(depositorAddress, address(this));
        require(rollupAllowance >= amount, 'Rollup Processor: INSUFFICIENT_TOKEN_APPROVAL');

        IERC20(assetAddress).transferFrom(depositorAddress, address(this), amount);
        increasePendingDepositBalance(assetId, depositorAddress, amount);

        emit Deposit(assetId, depositorAddress, amount);
    }

    /**
     * @dev Process a rollup - decode the rollup, update relevant state variables and
     * verify the proof
     * @param proofData - cryptographic proof data associated with a rollup
     * @param signatures - bytes array of secp256k1 ECDSA signatures, authorising a transfer of tokens
     * from the publicOwner for the particular inner proof in question. There is a signature for each
     * inner proof.
     *
     * Structure of each signature in the bytes array is:
     * 0x00 - 0x20 : r
     * 0x20 - 0x40 : s
     * 0x40 - 0x60 : v (in form: 0x0000....0001b for example)
     *
     * @param viewingKeys - viewingKeys for the notes submitted in the rollup. Note: not used in the logic
     * of the rollupProcessor contract, but called here as a convenient to place data on chain
     */
    function escapeHatch(
        bytes calldata proofData,
        bytes calldata signatures,
        bytes calldata viewingKeys
    ) external override whenNotPaused {
        (bool isOpen, ) = getEscapeHatchStatus();
        require(isOpen, 'Rollup Processor: ESCAPE_BLOCK_RANGE_INCORRECT');

        processRollupProof(proofData, signatures, viewingKeys);
    }

    function processRollup(
        bytes calldata proofData,
        bytes calldata signatures,
        bytes calldata viewingKeys,
        bytes calldata providerSignature,
        address provider,
        address payable feeReceiver,
        uint256 feeLimit
    ) external override whenNotPaused {
        uint256 initialGas = gasleft();

        require(rollupProviders[provider], 'Rollup Processor: UNKNOWN_PROVIDER');
        bytes memory sigData =
            abi.encodePacked(proofData[0:rollupPubInputLength], feeReceiver, feeLimit, feeDistributor);
        RollupProcessorLibrary.validateSignature(keccak256(sigData), providerSignature, provider);

        processRollupProof(proofData, signatures, viewingKeys);

        transferFee(proofData);

        (bool success, ) =
            feeDistributor.call(
                abi.encodeWithSignature(
                    'reimburseGas(uint256,uint256,address)',
                    initialGas - gasleft(),
                    feeLimit,
                    feeReceiver
                )
            );
        require(success, 'Rollup Processor: REIMBURSE_GAS_FAILED');
    }

    function processRollupProof(
        bytes memory proofData,
        bytes memory signatures,
        bytes calldata /*viewingKeys*/
    ) internal {
        uint256 numTxs = verifyProofAndUpdateState(proofData);
        processDepositsAndWithdrawals(proofData, numTxs, signatures);
    }

    /**
     * @dev Verify the zk proof and update the contract state variables with those provided by the rollup.
     * @param proofData - cryptographic zk proof data. Passed to the verifier for verification.
     */
    function verifyProofAndUpdateState(bytes memory proofData) internal returns (uint256) {
        (
            bytes32 newDataRoot,
            bytes32 newNullRoot,
            uint256 rollupId,
            uint256 rollupSize,
            bytes32 newRootRoot,
            uint256 numTxs,
            uint256 newDataSize
        ) = validateMerkleRoots(proofData);

        // Verify the rollup proof.
        //
        // We manually call the verifier contract via assembly. This is to prevent a
        // redundant copy of `proofData` into memory, which costs between 100,000 to 1,000,000 gas
        // depending on the rollup size!
        bool proof_verified = false;
        address verifierAddress;
        uint256 temp1;
        uint256 temp2;
        uint256 temp3;
        assembly {
            // Step 1: we need to insert 68 bytes of verifier 'calldata' just prior to proofData
            // Start by defining the start of our 'calldata'. Also grab the verifier contract address from storage
            let inputPtr := sub(proofData, 0x44)
            verifierAddress := sload(verifier_slot)

            // Step 2: we need to overwrite the memory between `inputPtr` and `inputPtr + 68`
            // we load the existing 68 bytes of memory into stack variables temp1, temp2, temp3
            // Once we have called the verifier contract, we will write this data back into memory
            temp1 := mload(inputPtr)
            temp2 := mload(add(inputPtr, 0x20))
            temp3 := mload(add(inputPtr, 0x40))

            // Step 3: insert our calldata into memory
            // 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 : rollupSize
            // 0x44 - .... : proofData (already present in memory)
            mstore8(inputPtr, 0xac)
            mstore8(add(inputPtr, 0x01), 0x31)
            mstore8(add(inputPtr, 0x02), 0x8c)
            mstore8(add(inputPtr, 0x03), 0x5d)
            mstore(add(inputPtr, 0x04), 0x40)
            mstore(add(inputPtr, 0x24), rollupSize)

            // Total calldata size is proofData.length + 96 bytes (the 66 bytes we just wrote, plus the 32 byte 'length' field of proofData)
            let callSize := add(mload(proofData), 0x64)

            // Step 4: Call our verifier contract. If 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
            proof_verified := staticcall(gas(), verifierAddress, inputPtr, callSize, 0x00, 0x00)

            // Step 5: Restore the memory we overwrote with our 'calldata'
            mstore(inputPtr, temp1)
            mstore(add(inputPtr, 0x20), temp2)
            mstore(add(inputPtr, 0x40), temp3)
        }

        // Check the proof is valid!
        require(proof_verified, 'proof verification failed');

        // Update state variables.
        dataRoot = newDataRoot;
        nullRoot = newNullRoot;
        nextRollupId = rollupId.add(1);
        rootRoot = newRootRoot;
        dataSize = newDataSize;

        emit RollupProcessed(rollupId, dataRoot, nullRoot, rootRoot, dataSize);
        return numTxs;
    }

    /**
     * @dev Extract public inputs and validate they are inline with current contract state.
     * @param proofData - Rollup proof data.
     */
    function validateMerkleRoots(bytes memory proofData)
        internal
        view
        returns (
            bytes32,
            bytes32,
            uint256,
            uint256,
            bytes32,
            uint256,
            uint256
        )
    {
        (
            // Stack to deep workaround:
            // 0: rollupId
            // 1: rollupSize
            // 2: dataStartIndex
            // 3: numTxs
            uint256[4] memory nums,
            bytes32 oldDataRoot,
            bytes32 newDataRoot,
            bytes32 oldNullRoot,
            bytes32 newNullRoot,
            bytes32 oldRootRoot,
            bytes32 newRootRoot
        ) = decodeProof(proofData, numberOfAssets);

        // Escape hatch denominated by a rollup size of 0, which means inserting 2 new entries.
        nums[3] = nums[1] == 0 ? 1 : nums[1];

        // Ensure we are inserting at the next subtree boundary.
        uint256 toInsert = nums[3].mul(2);
        if (dataSize % toInsert == 0) {
            require(nums[2] == dataSize, 'Rollup Processor: INCORRECT_DATA_START_INDEX');
        } else {
            uint256 expected = dataSize + toInsert - (dataSize % toInsert);
            require(nums[2] == expected, 'Rollup Processor: INCORRECT_DATA_START_INDEX');
        }

        // Data validation checks.
        require(oldDataRoot == dataRoot, 'Rollup Processor: INCORRECT_DATA_ROOT');
        require(oldNullRoot == nullRoot, 'Rollup Processor: INCORRECT_NULL_ROOT');
        require(oldRootRoot == rootRoot, 'Rollup Processor: INCORRECT_ROOT_ROOT');
        require(nums[0] == nextRollupId, 'Rollup Processor: ID_NOT_SEQUENTIAL');

        return (newDataRoot, newNullRoot, nums[0], nums[1], newRootRoot, nums[3], nums[2] + toInsert);
    }

    /**
     * @dev Process deposits and withdrawls.
     * @param proofData - the proof data
     * @param numTxs - number of transactions rolled up in the proof
     * @param signatures - bytes 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;
        assembly {
            proofDataPtr := add(proofData, 0x20) // add 0x20 to skip over 1st field in bytes array (the length field)
        }
        proofDataPtr += rollupPubInputLength; // update pointer to skip over rollup public inputs and point to inner tx public inputs
        uint256 end = proofDataPtr + (numTxs * txPubInputLength);
        uint256 stepSize = txPubInputLength;

        // 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 proofId;
            uint256 publicInput;
            uint256 publicOutput;
            bool txNeedsProcessing;
            assembly {
                proofId := mload(proofDataPtr)
                publicInput := mload(add(proofDataPtr, 0x20))
                publicOutput := mload(add(proofDataPtr, 0x40))
                // only process deposits and withdrawals iff
                // the proofId == 0 (not an account proof) and publicInput > 0 OR publicOutput > 0
                txNeedsProcessing := and(iszero(proofId), or(not(iszero(publicInput)), not(iszero(publicOutput))))
            }

            if (txNeedsProcessing) {
                // extract asset Id
                uint256 assetId;
                assembly {
                    assetId := mload(add(proofDataPtr, 0x60))
                }

                if (publicInput > 0) {
                    // validate user has approved deposit
                    address inputOwner;
                    bytes32 digest;
                    assembly {
                        inputOwner := mload(add(proofDataPtr, 0x140))

                        // compute the message digest to check if user has approved tx
                        digest := keccak256(proofDataPtr, stepSize)
                    }
                    if (!depositProofApprovals[inputOwner][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 (92)
                        // 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 92-byte 'length' parameter into the `signature` bytes array
                            mstore(signature, 0x60)
                        }
                        // validate the signature
                        RollupProcessorLibrary.validateUnpackedSignature(digest, signature, inputOwner);
                        // restore the memory we overwrote
                        assembly {
                            mstore(signature, temp)
                            sigIndex := add(sigIndex, 0x60)
                        }
                    }
                    decreasePendingDepositBalance(assetId, inputOwner, publicInput);
                }

                if (publicOutput > 0) {
                    address outputOwner;
                    assembly {
                        outputOwner := mload(add(proofDataPtr, 0x160))
                    }
                    withdraw(publicOutput, outputOwner, assetId);
                }
            }
            proofDataPtr += txPubInputLength;
        }
    }

    function transferFee(bytes memory proofData) internal {
        for (uint256 i = 0; i < numberOfAssets; ++i) {
            uint256 txFee = extractTotalTxFee(proofData, i);
            if (txFee > 0) {
                bool success;
                if (i == ethAssetId) {
                    (success, ) = payable(feeDistributor).call{value: txFee}('');
                } else {
                    address assetAddress = getSupportedAsset(i);
                    IERC20(assetAddress).approve(feeDistributor, txFee);
                    (success, ) = feeDistributor.call(abi.encodeWithSignature('deposit(uint256,uint256)', i, txFee));
                }
                require(success, 'Rollup Processor: DEPOSIT_TX_FEE_FAILED');
                totalFees[i] = totalFees[i].add(txFee);
            }
        }
    }

    /**
     * @dev Internal utility function to withdraw funds from the contract to a receiver address
     * @param withdrawValue - value being withdrawn from the contract
     * @param receiverAddress - address receiving public ERC20 tokens
     * @param assetId - ID of the asset for which a withdrawl is being performed
     */
    function withdraw(
        uint256 withdrawValue,
        address receiverAddress,
        uint256 assetId
    ) internal {
        require(receiverAddress != address(0), 'Rollup Processor: ZERO_ADDRESS');
        if (assetId == 0) {
            // We explicitly do not throw if this call fails, as this opens up the possiblity of
            // griefing attacks, as engineering a failed withdrawal will invalidate an entire rollup block
            payable(receiverAddress).call{gas: 30000, value: withdrawValue}('');
        } else {
            address assetAddress = getSupportedAsset(assetId);
            IERC20(assetAddress).transfer(receiverAddress, withdrawValue);
        }
        totalWithdrawn[assetId] = totalWithdrawn[assetId].add(withdrawValue);
    }
}

File 2 of 14 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @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);
}

File 3 of 14 : Ownable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "../utils/Context.sol";
/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

File 4 of 14 : Pausable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor () internal {
        _paused = false;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        require(!paused(), "Pausable: paused");
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        require(paused(), "Pausable: not paused");
        _;
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

File 5 of 14 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) return (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

File 6 of 14 : IVerifier.sol
// SPDX-License-Identifier: GPL-2.0-only
// Copyright 2020 Spilsbury Holdings Ltd
pragma solidity >=0.6.10 <0.8.0;

interface IVerifier {
    function verify(bytes memory serialized_proof, uint256 _keyId) external;
}

File 7 of 14 : IRollupProcessor.sol
// SPDX-License-Identifier: GPL-2.0-only
// Copyright 2020 Spilsbury Holdings Ltd
pragma solidity >=0.6.10 <0.8.0;

interface IRollupProcessor {
    function feeDistributor() external view returns (address);

    function escapeHatch(
        bytes calldata proofData,
        bytes calldata signatures,
        bytes calldata viewingKeys
    ) external;

    function processRollup(
        bytes calldata proofData,
        bytes calldata signatures,
        bytes calldata viewingKeys,
        bytes calldata providerSignature,
        address provider,
        address payable feeReceiver,
        uint256 feeLimit
    ) external;

    function depositPendingFunds(
        uint256 assetId,
        uint256 amount,
        address owner
    ) external payable;

    function depositPendingFundsPermit(
        uint256 assetId,
        uint256 amount,
        address owner,
        address spender,
        uint256 permitApprovalAmount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    function setRollupProvider(address provderAddress, bool valid) external;

    function approveProof(bytes32 _proofHash) external;

    function setFeeDistributor(address feeDistributorAddress) external;

    function setVerifier(address verifierAddress) external;

    function setSupportedAsset(address linkedToken, bool supportsPermit) external;

    function setAssetPermitSupport(uint256 assetId, bool supportsPermit) external;

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

    function getSupportedAssets() external view returns (address[] memory);

    function getTotalDeposited() external view returns (uint256[] memory);

    function getTotalWithdrawn() external view returns (uint256[] memory);

    function getTotalPendingDeposit() external view returns (uint256[] memory);

    function getTotalFees() external view returns (uint256[] memory);

    function getAssetPermitSupport(uint256 assetId) external view returns (bool);

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

    function getUserPendingDeposit(uint256 assetId, address userAddress) external view returns (uint256);
}

File 8 of 14 : IFeeDistributor.sol
// SPDX-License-Identifier: GPL-2.0-only
// Copyright 2020 Spilsbury Holdings Ltd
pragma solidity >=0.6.10 <0.8.0;

interface IFeeDistributor {
    event FeeReimbursed(address receiver, uint256 amount);

    function txFeeBalance(uint256 assetId) external view returns (uint256);

    function deposit(uint256 assetId, uint256 amount) external payable returns (uint256 depositedAmount);

    function reimburseGas(
        uint256 gasUsed,
        uint256 feeLimit,
        address payable feeReceiver
    ) external returns (uint256 reimbursement);
}

File 9 of 14 : IERC20Permit.sol
// SPDX-License-Identifier: GPL-2.0-only
// Copyright 2020 Spilsbury Holdings Ltd
pragma solidity >=0.6.10 <0.8.0;

import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';

interface IERC20Permit is IERC20 {
    function nonces(address user) external view returns (uint256);

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}

File 10 of 14 : Decoder.sol
// SPDX-License-Identifier: GPL-2.0-only
// Copyright 2020 Spilsbury Holdings Ltd
pragma solidity >=0.6.10 <0.8.0;

import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol';
import {Types} from './verifier/cryptography/Types.sol';
import {Bn254Crypto} from './verifier/cryptography/Bn254Crypto.sol';

contract Decoder {
    using SafeMath for uint256;

    /**
     * @dev Decode the public inputs component of proofData. Required to update state variables
     * @param proofData - cryptographic proofData associated with a rollup
     */
    function decodeProof(bytes memory proofData, uint256 numberOfAssets)
        internal
        pure
        returns (
            uint256[4] memory nums,
            bytes32 oldDataRoot,
            bytes32 newDataRoot,
            bytes32 oldNullRoot,
            bytes32 newNullRoot,
            bytes32 oldRootRoot,
            bytes32 newRootRoot
        )
    {
        uint256 rollupId;
        uint256 rollupSize;
        uint256 dataStartIndex;
        uint256 numTxs;
        assembly {
            let dataStart := add(proofData, 0x20) // jump over first word, it's length of data
            rollupId := mload(dataStart)
            rollupSize := mload(add(dataStart, 0x20))
            dataStartIndex := mload(add(dataStart, 0x40))
            oldDataRoot := mload(add(dataStart, 0x60))
            newDataRoot := mload(add(dataStart, 0x80))
            oldNullRoot := mload(add(dataStart, 0xa0))
            newNullRoot := mload(add(dataStart, 0xc0))
            oldRootRoot := mload(add(dataStart, 0xe0))
            newRootRoot := mload(add(dataStart, 0x100))
            numTxs := mload(add(add(dataStart, 0x120), mul(0x20, numberOfAssets)))
        }
        return (
            [rollupId, rollupSize, dataStartIndex, numTxs],
            oldDataRoot,
            newDataRoot,
            oldNullRoot,
            newNullRoot,
            oldRootRoot,
            newRootRoot
        );
    }

    function extractTotalTxFee(bytes memory proofData, uint256 assetId) internal pure returns (uint256) {
        uint256 totalTxFee;
        assembly {
            totalTxFee := mload(add(add(proofData, 0x140), mul(0x20, assetId)))
        }
        return totalTxFee;
    }
}

File 11 of 14 : RollupProcessorLibrary.sol
// SPDX-License-Identifier: GPL-2.0-only
// Copyright 2020 Spilsbury Holdings Ltd
pragma solidity >=0.6.10 <0.8.0;

library RollupProcessorLibrary {

    /**
    * 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);
        require(signer != address(0x0), 'validateSignature: ZERO_ADDRESS');


        // 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)))
        }

        require(result, 'validateSignature: signature recovery failed');
        require(recoveredSigner == signer, 'validateSignature: 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 92-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);
        require(signer != address(0x0), 'validateSignature: ZERO_ADDRESS');


        // 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)))
        }

        require(result, 'validateSignature: signature recovery failed');
        require(recoveredSigner == signer, 'validateSignature: INVALID_SIGNATURE');
    }
}

File 12 of 14 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <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 GSN 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 payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 13 of 14 : Types.sol
// SPDX-License-Identifier: GPL-2.0-only
// Copyright 2020 Spilsbury Holdings Ltd

pragma solidity >=0.6.0 <0.8.0;
pragma experimental ABIEncoderV2;

/**
 * @title Bn254Crypto library used for the fr, g1 and g2 point types
 * @dev Used to manipulate fr, g1, g2 types, perform modular arithmetic on them and call
 * the precompiles add, scalar mul and pairing
 *
 * Notes on optimisations
 * 1) Perform addmod, mulmod etc. in assembly - removes the check that Solidity performs to confirm that
 * the supplied modulus is not 0. This is safe as the modulus's used (r_mod, q_mod) are hard coded
 * inside the contract and not supplied by the user
 */
library Types {
    uint256 constant PROGRAM_WIDTH = 4;
    uint256 constant NUM_NU_CHALLENGES = 11;

    uint256 constant coset_generator0 = 0x0000000000000000000000000000000000000000000000000000000000000005;
    uint256 constant coset_generator1 = 0x0000000000000000000000000000000000000000000000000000000000000006;
    uint256 constant coset_generator2 = 0x0000000000000000000000000000000000000000000000000000000000000007;

    // TODO: add external_coset_generator() method to compute this
    uint256 constant coset_generator7 = 0x000000000000000000000000000000000000000000000000000000000000000c;

    struct G1Point {
        uint256 x;
        uint256 y;
    }

    // G2 group element where x \in Fq2 = x0 * z + x1
    struct G2Point {
        uint256 x0;
        uint256 x1;
        uint256 y0;
        uint256 y1;
    }

    // N>B. Do not re-order these fields! They must appear in the same order as they
    // appear in the proof data
    struct Proof {
        G1Point W1;
        G1Point W2;
        G1Point W3;
        G1Point W4;
        G1Point Z;
        G1Point T1;
        G1Point T2;
        G1Point T3;
        G1Point T4;
        uint256 w1;
        uint256 w2;
        uint256 w3;
        uint256 w4;
        uint256 sigma1;
        uint256 sigma2;
        uint256 sigma3;
        uint256 q_arith;
        uint256 q_ecc;
        uint256 q_c;
        uint256 linearization_polynomial;
        uint256 grand_product_at_z_omega;
        uint256 w1_omega;
        uint256 w2_omega;
        uint256 w3_omega;
        uint256 w4_omega;
        G1Point PI_Z;
        G1Point PI_Z_OMEGA;
        G1Point recursive_P1;
        G1Point recursive_P2;
        uint256 quotient_polynomial_eval;
    }

    struct ChallengeTranscript {
        uint256 alpha_base;
        uint256 alpha;
        uint256 zeta;
        uint256 beta;
        uint256 gamma;
        uint256 u;
        uint256 v0;
        uint256 v1;
        uint256 v2;
        uint256 v3;
        uint256 v4;
        uint256 v5;
        uint256 v6;
        uint256 v7;
        uint256 v8;
        uint256 v9;
        uint256 v10;
    }

    struct VerificationKey {
        uint256 circuit_size;
        uint256 num_inputs;
        uint256 work_root;
        uint256 domain_inverse;
        uint256 work_root_inverse;
        G1Point Q1;
        G1Point Q2;
        G1Point Q3;
        G1Point Q4;
        G1Point Q5;
        G1Point QM;
        G1Point QC;
        G1Point QARITH;
        G1Point QECC;
        G1Point QRANGE;
        G1Point QLOGIC;
        G1Point SIGMA1;
        G1Point SIGMA2;
        G1Point SIGMA3;
        G1Point SIGMA4;
        bool contains_recursive_proof;
        uint256 recursive_proof_indices;
        G2Point g2_x;

        // zeta challenge raised to the power of the circuit size.
        // Not actually part of the verification key, but we put it here to prevent stack depth errors
        uint256 zeta_pow_n;
    }
}

File 14 of 14 : Bn254Crypto.sol
// SPDX-License-Identifier: GPL-2.0-only
// Copyright 2020 Spilsbury Holdings Ltd
pragma solidity >=0.6.0 <0.8.0;
pragma experimental ABIEncoderV2;

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

/**
 * @title Bn254 elliptic curve crypto
 * @dev Provides some basic methods to compute bilinear pairings, construct group elements and misc numerical methods
 */
library Bn254Crypto {
    uint256 constant p_mod = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
    uint256 constant r_mod = 21888242871839275222246405745257275088548364400416034343698204186575808495617;

    // Perform a modular exponentiation. This method is ideal for small exponents (~64 bits or less), as
    // it is cheaper than using the pow precompile
    function pow_small(
        uint256 base,
        uint256 exponent,
        uint256 modulus
    ) internal pure returns (uint256) {
        uint256 result = 1;
        uint256 input = base;
        uint256 count = 1;

        assembly {
            let endpoint := add(exponent, 0x01)
            for {} lt(count, endpoint) { count := add(count, count) }
            {
                if and(exponent, count) {
                    result := mulmod(result, input, modulus)
                }
                input := mulmod(input, input, modulus)
            }
        }

        return result;
    }

    function invert(uint256 fr) internal view returns (uint256)
    {
        uint256 output;
        bool success;
        uint256 p = r_mod;
        assembly {
            let mPtr := mload(0x40)
            mstore(mPtr, 0x20)
            mstore(add(mPtr, 0x20), 0x20)
            mstore(add(mPtr, 0x40), 0x20)
            mstore(add(mPtr, 0x60), fr)
            mstore(add(mPtr, 0x80), sub(p, 2))
            mstore(add(mPtr, 0xa0), p)
            success := staticcall(gas(), 0x05, mPtr, 0xc0, 0x00, 0x20)
            output := mload(0x00)
        }
        require(success, "pow precompile call failed!");
        return output;
    }

    function new_g1(uint256 x, uint256 y)
        internal
        pure
        returns (Types.G1Point memory)
    {
        uint256 xValue;
        uint256 yValue;
        assembly {
            xValue := mod(x, r_mod)
            yValue := mod(y, r_mod)
        }
        return Types.G1Point(xValue, yValue);
    }

    function new_g2(uint256 x0, uint256 x1, uint256 y0, uint256 y1)
        internal
        pure
        returns (Types.G2Point memory)
    {
        return Types.G2Point(x0, x1, y0, y1);
    }

    function P1() internal pure returns (Types.G1Point memory) {
        return Types.G1Point(1, 2);
    }

    function P2() internal pure returns (Types.G2Point memory) {
        return Types.G2Point({
            x0: 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2,
            x1: 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed,
            y0: 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b,
            y1: 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa
        });
    }


    /// Evaluate the following pairing product:
    /// e(a1, a2).e(-b1, b2) == 1
    function pairingProd2(
        Types.G1Point memory a1,
        Types.G2Point memory a2,
        Types.G1Point memory b1,
        Types.G2Point memory b2
    ) internal view returns (bool) {
        validateG1Point(a1);
        validateG1Point(b1);
        bool success;
        uint256 out;
        assembly {
            let mPtr := mload(0x40)
            mstore(mPtr, mload(a1))
            mstore(add(mPtr, 0x20), mload(add(a1, 0x20)))
            mstore(add(mPtr, 0x40), mload(a2))
            mstore(add(mPtr, 0x60), mload(add(a2, 0x20)))
            mstore(add(mPtr, 0x80), mload(add(a2, 0x40)))
            mstore(add(mPtr, 0xa0), mload(add(a2, 0x60)))

            mstore(add(mPtr, 0xc0), mload(b1))
            mstore(add(mPtr, 0xe0), mload(add(b1, 0x20)))
            mstore(add(mPtr, 0x100), mload(b2))
            mstore(add(mPtr, 0x120), mload(add(b2, 0x20)))
            mstore(add(mPtr, 0x140), mload(add(b2, 0x40)))
            mstore(add(mPtr, 0x160), mload(add(b2, 0x60)))
            success := staticcall(
                gas(),
                8,
                mPtr,
                0x180,
                0x00,
                0x20
            )
            out := mload(0x00)
        }
        require(success, "Pairing check failed!");
        return (out != 0);
    }

    /**
    * validate the following:
    *   x != 0
    *   y != 0
    *   x < p
    *   y < p
    *   y^2 = x^3 + 3 mod p
    */
    function validateG1Point(Types.G1Point memory point) internal pure {
        bool is_well_formed;
        uint256 p = p_mod;
        assembly {
            let x := mload(point)
            let y := mload(add(point, 0x20))

            is_well_formed := and(
                and(
                    and(lt(x, p), lt(y, p)),
                    not(or(iszero(x), iszero(y)))
                ),
                eq(mulmod(y, y, p), addmod(mulmod(x, mulmod(x, x, p), p), 3, p))
            )
        }
        require(is_well_formed, "Bn254: G1 point not on curve, or is malformed");
    }
}

Settings
{
  "evmVersion": "istanbul",
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_verifierAddress","type":"address"},{"internalType":"uint256","name":"_escapeBlockLowerBound","type":"uint256"},{"internalType":"uint256","name":"_escapeBlockUpperBound","type":"uint256"},{"internalType":"address","name":"_contractOwner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":true,"internalType":"address","name":"assetAddress","type":"address"}],"name":"AssetAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":false,"internalType":"address","name":"depositorAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"depositValue","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rollupId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"dataRoot","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"nullRoot","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"rootRoot","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"dataSize","type":"uint256"}],"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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":false,"internalType":"address","name":"withdrawAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"withdrawValue","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"errorReason","type":"bytes"}],"name":"WithdrawError","type":"event"},{"inputs":[{"internalType":"bytes32","name":"_proofHash","type":"bytes32"}],"name":"approveProof","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"dataRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dataSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"depositorAddress","type":"address"}],"name":"depositPendingFunds","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"depositorAddress","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"permitApprovalAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"depositPendingFundsPermit","outputs":[],"stateMutability":"nonpayable","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":"bytes","name":"proofData","type":"bytes"},{"internalType":"bytes","name":"signatures","type":"bytes"},{"internalType":"bytes","name":"viewingKeys","type":"bytes"}],"name":"escapeHatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ethAssetId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeDistributor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"}],"name":"getAssetPermitSupport","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEscapeHatchStatus","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"}],"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":"getSupportedAssets","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalDeposited","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalFees","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalPendingDeposit","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalWithdrawn","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"},{"internalType":"address","name":"userAddress","type":"address"}],"name":"getUserPendingDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextRollupId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nullRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numberOfAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"proofData","type":"bytes"},{"internalType":"bytes","name":"signatures","type":"bytes"},{"internalType":"bytes","name":"viewingKeys","type":"bytes"},{"internalType":"bytes","name":"providerSignature","type":"bytes"},{"internalType":"address","name":"provider","type":"address"},{"internalType":"address payable","name":"feeReceiver","type":"address"},{"internalType":"uint256","name":"feeLimit","type":"uint256"}],"name":"processRollup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rollupNumPubInputs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rollupProviders","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rollupPubInputLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rootRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"},{"internalType":"bool","name":"supportsPermit","type":"bool"}],"name":"setAssetPermitSupport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"feeDistributorAddress","type":"address"}],"name":"setFeeDistributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"providerAddress","type":"address"},{"internalType":"bool","name":"valid","type":"bool"}],"name":"setRollupProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"linkedToken","type":"address"},{"internalType":"bool","name":"supportsPermit","type":"bool"}],"name":"setSupportedAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_verifierAddress","type":"address"}],"name":"setVerifier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"supportedAssets","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalDeposited","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalPendingDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalWithdrawn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"txNumPubInputs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"txPubInputLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"contract IVerifier","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60c06040527f2708a627d38d74d478f645ec3b4e91afa325331acf1acebe9077891146b75e396001557f2694dbe3c71a25d92213422d392479e7b8ef437add81e1e17244462e6edca9b16002557f2d264e93dc455751a721aead9dba9ee2a9fef5460921aeede73f63f6210e68516003553480156200007d57600080fd5b50604051620036763803806200367683398181016040526080811015620000a357600080fd5b50805160208201516040830151606090930151919290916000620000cf6001600160e01b036200022416565b600080546001600160a01b0319166001600160a01b03831690811782556040519293509160008051602062003656833981519152908290a3506000805460ff60a01b19168155600680546001600160a01b0319166001600160a01b038716179055608084905260a0839052338152600b60205260408120805460ff19166001908117909155600d80548083019091557fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb501829055600e80548083019091557fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd01829055600f80548083019091557f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac8020182905560108054918201815582527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae67201556200021a8162000228565b5050505062000353565b3390565b6200023b6001600160e01b036200022416565b6001600160a01b0316620002576001600160e01b036200034416565b6001600160a01b031614620002b3576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b038116620002fa5760405162461bcd60e51b8152600401808060200182810382526026815260200180620036306026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216916000805160206200365683398151915291a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031690565b60805160a05161329b6200039560003980611651528061168752806116b152806116da5280611a4f5250806115b152806116305280611704525061329b6000f3fe60806040526004361061027d5760003560e01c806394401d751161014f578063d1d2d95e116100c1578063e5406dbf1161007a578063e5406dbf14610b13578063e70626e614610b28578063edf49c0914610b3d578063ef76e2ee14610b52578063f0e7e29b14610b8d578063f2fde38b14610ba25761027d565b8063d1d2d95e14610a39578063d28bbda514610a6b578063d6ae328414610a95578063d8ba363714610abf578063e059d80714610ad4578063e393635514610ae95761027d565b8063b68ef55911610113578063b68ef55914610852578063be71f8a414610867578063c68dbb3714610897578063c6c62390146108c1578063ccfc2e8d146108eb578063d1c652641461091e5761027d565b806394401d75146107b0578063a009f7e4146107c5578063a3d205f4146107ef578063ae35bfc214610828578063b045009c1461083d5761027d565b80635437988d116101f35780636dff3584116101ac5780636dff3584146106e8578063715018a6146106fd578063781e04321461071257806389404a791461074b5780638da5cb5b1461076057806391dfe78f146107755761027d565b80635437988d146106055780635ad1def3146106385780635c975abb1461067f57806360a8b18a14610694578063626e1ae7146106be57806366535f30146106d35761027d565b806336ce0a921161024557806336ce0a92146104e1578063408ccbdf1461051a57806344c5125214610544578063479b3d951461055957806347a695a71461058b57806349ce468d146105f05761027d565b8063018892ac1461028257806306011a46146102f05780630d43e8ad146104745780632b7ac3f3146104a55780633248295f146104ba575b600080fd5b34801561028e57600080fd5b506102ee60048036036101208110156102a657600080fd5b508035906020810135906001600160a01b03604082013581169160608101359091169060808101359060a08101359060ff60c0820135169060e0810135906101000135610bd5565b005b3480156102fc57600080fd5b506102ee600480360360e081101561031357600080fd5b810190602081018135600160201b81111561032d57600080fd5b82018360208201111561033f57600080fd5b803590602001918460018302840111600160201b8311171561036057600080fd5b919390929091602081019035600160201b81111561037d57600080fd5b82018360208201111561038f57600080fd5b803590602001918460018302840111600160201b831117156103b057600080fd5b919390929091602081019035600160201b8111156103cd57600080fd5b8201836020820111156103df57600080fd5b803590602001918460018302840111600160201b8311171561040057600080fd5b919390929091602081019035600160201b81111561041d57600080fd5b82018360208201111561042f57600080fd5b803590602001918460018302840111600160201b8311171561045057600080fd5b91935091506001600160a01b03813581169160208101359091169060400135610cd8565b34801561048057600080fd5b5061048961106c565b604080516001600160a01b039092168252519081900360200190f35b3480156104b157600080fd5b5061048961107b565b3480156104c657600080fd5b506104cf61108a565b60408051918252519081900360200190f35b3480156104ed57600080fd5b506104cf6004803603604081101561050457600080fd5b50803590602001356001600160a01b0316611090565b34801561052657600080fd5b506104cf6004803603602081101561053d57600080fd5b50356110ad565b34801561055057600080fd5b506104cf6110cb565b34801561056557600080fd5b506102ee6004803603604081101561057c57600080fd5b508035906020013515156110d0565b34801561059757600080fd5b506105a06111ad565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156105dc5781810151838201526020016105c4565b505050509050019250505060405180910390f35b3480156105fc57600080fd5b506104cf611205565b34801561061157600080fd5b506102ee6004803603602081101561062857600080fd5b50356001600160a01b031661120b565b34801561064457600080fd5b5061066b6004803603602081101561065b57600080fd5b50356001600160a01b03166112b7565b604080519115158252519081900360200190f35b34801561068b57600080fd5b5061066b6112cc565b3480156106a057600080fd5b50610489600480360360208110156106b757600080fd5b50356112dc565b3480156106ca57600080fd5b506105a0611318565b3480156106df57600080fd5b506104cf61136e565b3480156106f457600080fd5b506104cf611374565b34801561070957600080fd5b506102ee61137a565b34801561071e57600080fd5b5061066b6004803603604081101561073557600080fd5b506001600160a01b038135169060200135611426565b34801561075757600080fd5b506105a0611446565b34801561076c57600080fd5b5061048961149c565b34801561078157600080fd5b506102ee6004803603604081101561079857600080fd5b506001600160a01b03813516906020013515156114ab565b3480156107bc57600080fd5b506104cf61156d565b3480156107d157600080fd5b506104cf600480360360208110156107e857600080fd5b5035611573565b3480156107fb57600080fd5b506104cf6004803603604081101561081257600080fd5b50803590602001356001600160a01b0316611580565b34801561083457600080fd5b506104cf6115aa565b34801561084957600080fd5b506104cf6115af565b34801561085e57600080fd5b506105a06115d3565b34801561087357600080fd5b5061087c611629565b60408051921515835260208301919091528051918290030190f35b3480156108a357600080fd5b50610489600480360360208110156108ba57600080fd5b5035611731565b3480156108cd57600080fd5b506104cf600480360360208110156108e457600080fd5b5035611758565b3480156108f757600080fd5b506102ee6004803603602081101561090e57600080fd5b50356001600160a01b0316611765565b34801561092a57600080fd5b506102ee6004803603606081101561094157600080fd5b810190602081018135600160201b81111561095b57600080fd5b82018360208201111561096d57600080fd5b803590602001918460018302840111600160201b8311171561098e57600080fd5b919390929091602081019035600160201b8111156109ab57600080fd5b8201836020820111156109bd57600080fd5b803590602001918460018302840111600160201b831117156109de57600080fd5b919390929091602081019035600160201b8111156109fb57600080fd5b820183602082011115610a0d57600080fd5b803590602001918460018302840111600160201b83111715610a2e57600080fd5b5090925090506117e9565b6102ee60048036036060811015610a4f57600080fd5b50803590602081013590604001356001600160a01b03166118ff565b348015610a7757600080fd5b5061066b60048036036020811015610a8e57600080fd5b5035611a12565b348015610aa157600080fd5b506104cf60048036036020811015610ab857600080fd5b5035611a40565b348015610acb57600080fd5b506104cf611a4d565b348015610ae057600080fd5b506104cf611a71565b348015610af557600080fd5b506102ee60048036036020811015610b0c57600080fd5b5035611a77565b348015610b1f57600080fd5b506105a0611aea565b348015610b3457600080fd5b506104cf611b4b565b348015610b4957600080fd5b506104cf611b50565b348015610b5e57600080fd5b506102ee60048036036040811015610b7557600080fd5b506001600160a01b0381351690602001351515611b55565b348015610b9957600080fd5b506104cf611db2565b348015610bae57600080fd5b506102ee60048036036020811015610bc557600080fd5b50356001600160a01b0316611db8565b610bdd6112cc565b15610c22576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6000610c2d8a6112dc565b6040805163d505accf60e01b81526001600160a01b038b811660048301528a81166024830152604482018a90526064820189905260ff8816608483015260a4820187905260c4820186905291519293509083169163d505accf9160e48082019260009290919082900301818387803b158015610ca857600080fd5b505af1158015610cbc573d6000803e3d6000fd5b50505050610ccc8a828a8c611eba565b50505050505050505050565b610ce06112cc565b15610d25576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b60005a6001600160a01b0385166000908152600b602052604090205490915060ff16610d825760405162461bcd60e51b815260040180806020018281038252602281526020018061302f6022913960400191505060405180910390fd5b60608c8c6000906004600a0160200292610d9e93929190612f69565b600c54604051879187916001600160a01b03909116906020018086868082843780830192505050846001600160a01b03166001600160a01b031660601b8152601401838152602001826001600160a01b03166001600160a01b031660601b8152601401955050505050506040516020818303038152906040529050610e62818051906020012088888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a9250612058915050565b610eea8d8d8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508e92508d91506122019050565b610f298d8d8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061222092505050565b600c546000906001600160a01b03165a604080519186036024830152604482018790526001600160a01b03881660648084019190915281518084039091018152608490920181526020820180516001600160e01b03166356aa719960e01b17815290518251909182918083835b60208310610fb55780518252601f199092019160209182019101610f96565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611017576040519150601f19603f3d011682016040523d82523d6000602084013e61101c565b606091505b505090508061105c5760405162461bcd60e51b8152600401808060200182810382526026815260200180612fe66026913960400191505060405180910390fd5b5050505050505050505050505050565b600c546001600160a01b031681565b6006546001600160a01b031681565b60035481565b600960209081526000928352604080842090915290825290205481565b601081815481106110ba57fe5b600091825260209091200154905081565b600e81565b6110d86124ab565b6001600160a01b03166110e961149c565b6001600160a01b031614611132576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b600061113d836112dc565b90506001600160a01b0381166111845760405162461bcd60e51b81526004018080602001828103825260288152602001806130a96028913960400191505060405180910390fd5b6001600160a01b03166000908152600860205260409020805460ff191691151591909117905550565b6060600d8054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020905b8154815260200190600101908083116111e7575b5050505050905090565b60045481565b6112136124ab565b6001600160a01b031661122461149c565b6001600160a01b03161461126d576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b600680546001600160a01b0319166001600160a01b0383169081179091556040517fd24015cc99cc1700cafca3042840a1d8ac1e3964fd2e0e37ea29c654056ee32790600090a250565b600b6020526000908152604090205460ff1681565b600054600160a01b900460ff1690565b6000816112eb57506000611313565b600760018303815481106112fb57fe5b6000918252602090912001546001600160a01b031690505b919050565b606060108054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020908154815260200190600101908083116111e7575050505050905090565b61018081565b60015481565b6113826124ab565b6001600160a01b031661139361149c565b6001600160a01b0316146113dc576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b600a60209081526000928352604080842090915290825290205460ff1681565b6060600f8054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020908154815260200190600101908083116111e7575050505050905090565b6000546001600160a01b031690565b6114b36124ab565b6001600160a01b03166114c461149c565b6001600160a01b03161461150d576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b6001600160a01b0382166000818152600b6020908152604091829020805460ff1916851515908117909155825190815291517f46359ce9dbb6c7f9a375b44072210287916d3de725fc8927a8e762047e4a84249281900390910190a25050565b60025481565b600f81815481106110ba57fe5b60008281526009602090815260408083206001600160a01b03851684529091529020545b92915050565b600c81565b7f000000000000000000000000000000000000000000000000000000000000000081565b6060600e8054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020908154815260200190600101908083116111e7575050505050905090565b60008043817f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000838161167857fe5b0610801591506000906116d8577f000000000000000000000000000000000000000000000000000000000000000083816116ae57fe5b067f0000000000000000000000000000000000000000000000000000000000000000039050611727565b7f0000000000000000000000000000000000000000000000000000000000000000838161170157fe5b067f00000000000000000000000000000000000000000000000000000000000000000390505b9093509150509091565b6007818154811061173e57fe5b6000918252602090912001546001600160a01b0316905081565b600e81815481106110ba57fe5b61176d6124ab565b6001600160a01b031661177e61149c565b6001600160a01b0316146117c7576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b6117f16112cc565b15611836576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6000611840611629565b5090508061187f5760405162461bcd60e51b815260040180806020018281038252602e815260200180612fb8602e913960400191505060405180910390fd5b6118f687878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8b0181900481028201810190925289815292508991508890819084018382808284376000920191909152508892508791506122019050565b50505050505050565b6119076112cc565b1561194c576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b826119b5578134146119a5576040805162461bcd60e51b815260206004820152601e60248201527f526f6c6c75702050726f636573736f723a2057524f4e475f414d4f554e540000604482015290519081900360640190fd5b6119b08382846124af565b611a0d565b34156119f25760405162461bcd60e51b81526004018080602001828103825260248152602001806132426024913960400191505060405180910390fd5b60006119fd846112dc565b9050611a0b84828486611eba565b505b505050565b600080611a1e836112dc565b6001600160a01b031660009081526008602052604090205460ff169392505050565b600d81815481106110ba57fe5b7f000000000000000000000000000000000000000000000000000000000000000081565b60055481565b611a7f6112cc565b15611ac4576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b336000908152600a6020908152604080832093835292905220805460ff19166001179055565b606060078054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611b24575050505050905090565b600081565b600481565b611b5d6124ab565b6001600160a01b0316611b6e61149c565b6001600160a01b031614611bb7576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b6001600160a01b038216611c12576040805162461bcd60e51b815260206004820152601e60248201527f526f6c6c75702050726f636573736f723a205a45524f5f414444524553530000604482015290519081900360640190fd5b600780546001810182557fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6880180546001600160a01b0319166001600160a01b0385169081179091556000908152600860205260409020805460ff19168315151790555460048110611cb45760405162461bcd60e51b81526004018080602001828103825260238152602001806131a76023913960400191505060405180910390fd5b600d8054600181810190925560007fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5909101819055600e80548084019091557fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd01819055600f80548084019091557f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac8020181905560108054928301815581527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6729091018190556040516001600160a01b0385169183917fc53536963369dbfa4c398238ebb9b09fce3943a140928bd25d3052a8a9cacdaf9190a3505050565b6101c081565b611dc06124ab565b6001600160a01b0316611dd161149c565b6001600160a01b031614611e1a576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b6001600160a01b038116611e5f5760405162461bcd60e51b8152600401808060200182810382526026815260200180612f926026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60408051636eb1769f60e11b81526001600160a01b038481166004830152306024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b158015611f0b57600080fd5b505afa158015611f1f573d6000803e3d6000fd5b505050506040513d6020811015611f3557600080fd5b5051905081811015611f785760405162461bcd60e51b815260040180806020018281038252602d8152602001806131ef602d913960400191505060405180910390fd5b604080516323b872dd60e01b81526001600160a01b038581166004830152306024830152604482018590529151918616916323b872dd916064808201926020929091908290030181600087803b158015611fd157600080fd5b505af1158015611fe5573d6000803e3d6000fd5b505050506040513d6020811015611ffb57600080fd5b5061200990508584846124af565b604080518681526001600160a01b038516602082015280820184905290517feaa18152488ce5959073c9c79c88ca90b3d96c00de1f118cfaad664c3dab06b99181900360600190a15050505050565b6000806001600160a01b0383166120b6576040805162461bcd60e51b815260206004820152601f60248201527f76616c69646174655369676e61747572653a205a45524f5f4144445245535300604482015290519081900360640190fd5b60007f19457468657265756d205369676e6564204d6573736167653a0a33320000000060005285601c60000152603c60002090506040518551828252606087015160f81c60408801518060608501526020890151604085015281602085015260208460808660015afa601c8314601b84141760418514166fa2a8918ca85bafe22016d0b997e4df5f600160ff1b038310161696505050815183146000811461215d57612162565b825194505b5090528115199290921691826121a95760405162461bcd60e51b815260040180806020018281038252602c815260200180613051602c913960400191505060405180910390fd5b836001600160a01b0316826001600160a01b0316146121f95760405162461bcd60e51b815260040180806020018281038252602481526020018061315e6024913960400191505060405180910390fd5b505050505050565b600061220c85612537565b90506122198582866126a2565b5050505050565b60005b60048110156124a75760006122388383612773565b9050801561249e576000826122a457600c546040516001600160a01b03909116908390600081818185875af1925050503d8060008114612294576040519150601f19603f3d011682016040523d82523d6000602084013e612299565b606091505b50508091505061241d565b60006122af846112dc565b600c546040805163095ea7b360e01b81526001600160a01b0392831660048201526024810187905290519293509083169163095ea7b3916044808201926020929091908290030181600087803b15801561230857600080fd5b505af115801561231c573d6000803e3d6000fd5b505050506040513d602081101561233257600080fd5b5050600c546040805160248101879052604480820187905282518083039091018152606490910182526020810180516001600160e01b0316631c57762b60e31b178152915181516001600160a01b0390941693919290918291908083835b602083106123af5780518252601f199092019160209182019101612390565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612411576040519150601f19603f3d011682016040523d82523d6000602084013e612416565b606091505b5090925050505b806124595760405162461bcd60e51b81526004018080602001828103825260278152602001806131376027913960400191505060405180910390fd5b612483826010858154811061246a57fe5b906000526020600020015461278490919063ffffffff16565b6010848154811061249057fe5b600091825260209091200155505b50600101612223565b5050565b3390565b60008381526009602090815260408083206001600160a01b03861684529091529020546124e2908263ffffffff61278416565b60008481526009602090815260408083206001600160a01b0387168452909152902055600d80546125199183918690811061246a57fe5b600d848154811061252657fe5b600091825260209091200155505050565b60008060008060008060008061254c896127e5565b9650965096509650965096509650600080905060008060008060448e03600654945080519350602081015192506040810151915060ac815360316001820153608c6002820153605d60038201536040600482015289602482015260648f51016000808284895afa9650508381528260208201528160408201525084612618576040805162461bcd60e51b815260206004820152601960248201527f70726f6f6620766572696669636174696f6e206661696c656400000000000000604482015290519081900360640190fd5b60018c815560028c9055612633908b9063ffffffff61278416565b600555600388905560048690556001546002546040805192835260208301919091528181018a905260608201889052518b917ff1034928243e3365c0bf101598066f51439bb2a8763ec84cf7902d8917fb974f919081900360800190a250949c9b505050505050505050505050565b60006101e0808501906101808581028701909101905b818310156118f6578251602084015160408501518215821519821519171680156127625760608701518315612747576101408801518689206001600160a01b0382166000908152600a6020908152604080832084845290915290205460ff16612739578b8b0180516060825261272f838386612a5c565b905260609a909a01995b612744838388612ba4565b50505b82156127605761016088015161275e848284612cb1565b505b505b5050506101809390930192506126b8565b602081028201610140015192915050565b6000828201838110156127de576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b60008060008060008060006127f8612f4b565b60008060008060008061280c8f6004612e25565b96509650965096509650965096508660016004811061282757fe5b60200201511561283b57602087015161283e565b60015b60608801819052600090612853906002612e95565b9050806004548161286057fe5b066128ae576004546040890151146128a95760405162461bcd60e51b815260040180806020018281038252602c81526020018061307d602c913960400191505060405180910390fd5b612915565b600081600454816128bb57fe5b06826004540103905080896002600481106128d257fe5b6020020151146129135760405162461bcd60e51b815260040180806020018281038252602c81526020018061307d602c913960400191505060405180910390fd5b505b60015487146129555760405162461bcd60e51b81526004018080602001828103825260258152602001806131ca6025913960400191505060405180910390fd5b60025485146129955760405162461bcd60e51b81526004018080602001828103825260258152602001806131826025913960400191505060405180910390fd5b60035483146129d55760405162461bcd60e51b81526004018080602001828103825260258152602001806130d16025913960400191505060405180910390fd5b600554885114612a165760405162461bcd60e51b815260040180806020018281038252602381526020018061300c6023913960400191505060405180910390fd5b858489600060200201518a60016020020151858c60036020020151868e60026020020151019e509e509e509e509e509e509e505050505050505050919395979092949650565b6000806001600160a01b038316612aba576040805162461bcd60e51b815260206004820152601f60248201527f76616c69646174655369676e61747572653a205a45524f5f4144445245535300604482015290519081900360640190fd5b60007f19457468657265756d205369676e6564204d6573736167653a0a33320000000060005285601c52603c60002090508451818652606086015160408701518060608901526020880151604089015281602089015260208860808a60015afa601c8314601b84141760608514166fa2a8918ca85bafe22016d0b997e4df5f600160ff1b0383101616955050508551821460008114612b5857612b5d565b865193505b5085528115199290921691826121a95760405162461bcd60e51b815260040180806020018281038252602c815260200180613051602c913960400191505060405180910390fd5b60008381526009602090815260408083206001600160a01b038616845290915290205481811015612c065760405162461bcd60e51b815260040180806020018281038252602681526020018061321c6026913960400191505060405180910390fd5b612c16818363ffffffff612eee16565b60008581526009602090815260408083206001600160a01b0388168452909152902055600d8054612c6691849187908110612c4d57fe5b9060005260206000200154612eee90919063ffffffff16565b600d8581548110612c7357fe5b9060005260206000200181905550612c9282600e868154811061246a57fe5b600e8581548110612c9f57fe5b60009182526020909120015550505050565b6001600160a01b038216612d0c576040805162461bcd60e51b815260206004820152601e60248201527f526f6c6c75702050726f636573736f723a205a45524f5f414444524553530000604482015290519081900360640190fd5b80612d6c576040516001600160a01b038316906175309085906000818181858888f193505050503d8060008114612d5f576040519150601f19603f3d011682016040523d82523d6000602084013e612d64565b606091505b505050612e07565b6000612d77826112dc565b9050806001600160a01b031663a9059cbb84866040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015612dd957600080fd5b505af1158015612ded573d6000803e3d6000fd5b505050506040513d6020811015612e0357600080fd5b5050505b612e1883600f838154811061246a57fe5b600f828154811061252657fe5b612e2d612f4b565b5060208281015160408085015160608087015160808089015160a08a015160c08b015160e08c01516101008d01516101208e01519c8c02909d01610140015189519586018a529985529984019690965295820192909252918201949094529692959194909392565b600082612ea4575060006115a4565b82820282848281612eb157fe5b04146127de5760405162461bcd60e51b81526004018080602001828103825260218152602001806130f66021913960400191505060405180910390fd5b600082821115612f45576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60405180608001604052806004906020820280368337509192915050565b60008085851115612f78578182fd5b83861115612f84578182fd5b505082019391909203915056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373526f6c6c75702050726f636573736f723a204553434150455f424c4f434b5f52414e47455f494e434f5252454354526f6c6c75702050726f636573736f723a205245494d42555253455f4741535f4641494c4544526f6c6c75702050726f636573736f723a2049445f4e4f545f53455155454e5449414c526f6c6c75702050726f636573736f723a20554e4b4e4f574e5f50524f564944455276616c69646174655369676e61747572653a207369676e6174757265207265636f76657279206661696c6564526f6c6c75702050726f636573736f723a20494e434f52524543545f444154415f53544152545f494e444558526f6c6c75702050726f636573736f723a20544f4b454e5f41535345545f4e4f545f4c494e4b4544526f6c6c75702050726f636573736f723a20494e434f52524543545f524f4f545f524f4f54536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572526f6c6c75702050726f636573736f723a204445504f5349545f54585f4645455f4641494c454476616c69646174655369676e61747572653a20494e56414c49445f5349474e4154555245526f6c6c75702050726f636573736f723a20494e434f52524543545f4e554c4c5f524f4f54526f6c6c75702050726f636573736f723a204d41585f41535345545f52454143484544526f6c6c75702050726f636573736f723a20494e434f52524543545f444154415f524f4f54526f6c6c75702050726f636573736f723a20494e53554646494349454e545f544f4b454e5f415050524f56414c526f6c6c75702050726f636573736f723a20494e53554646494349454e545f4445504f534954526f6c6c75702050726f636573736f723a2057524f4e475f5041594d454e545f54595045a26469706673582212202fd47ddc29f53f6efddfd5689a51af7ae006998ca8597c21d3ffbbc3cd7da41f64736f6c634300060a00334f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573738be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0000000000000000000000000dcc80db987bf63f01b7bafced6230de5002ef87400000000000000000000000000000000000000000000000000000000000011d000000000000000000000000000000000000000000000000000000000000012c0000000000000000000000000fcf75295f242c4e87203abb5d7c9bbeda90a8895

Deployed Bytecode

0x60806040526004361061027d5760003560e01c806394401d751161014f578063d1d2d95e116100c1578063e5406dbf1161007a578063e5406dbf14610b13578063e70626e614610b28578063edf49c0914610b3d578063ef76e2ee14610b52578063f0e7e29b14610b8d578063f2fde38b14610ba25761027d565b8063d1d2d95e14610a39578063d28bbda514610a6b578063d6ae328414610a95578063d8ba363714610abf578063e059d80714610ad4578063e393635514610ae95761027d565b8063b68ef55911610113578063b68ef55914610852578063be71f8a414610867578063c68dbb3714610897578063c6c62390146108c1578063ccfc2e8d146108eb578063d1c652641461091e5761027d565b806394401d75146107b0578063a009f7e4146107c5578063a3d205f4146107ef578063ae35bfc214610828578063b045009c1461083d5761027d565b80635437988d116101f35780636dff3584116101ac5780636dff3584146106e8578063715018a6146106fd578063781e04321461071257806389404a791461074b5780638da5cb5b1461076057806391dfe78f146107755761027d565b80635437988d146106055780635ad1def3146106385780635c975abb1461067f57806360a8b18a14610694578063626e1ae7146106be57806366535f30146106d35761027d565b806336ce0a921161024557806336ce0a92146104e1578063408ccbdf1461051a57806344c5125214610544578063479b3d951461055957806347a695a71461058b57806349ce468d146105f05761027d565b8063018892ac1461028257806306011a46146102f05780630d43e8ad146104745780632b7ac3f3146104a55780633248295f146104ba575b600080fd5b34801561028e57600080fd5b506102ee60048036036101208110156102a657600080fd5b508035906020810135906001600160a01b03604082013581169160608101359091169060808101359060a08101359060ff60c0820135169060e0810135906101000135610bd5565b005b3480156102fc57600080fd5b506102ee600480360360e081101561031357600080fd5b810190602081018135600160201b81111561032d57600080fd5b82018360208201111561033f57600080fd5b803590602001918460018302840111600160201b8311171561036057600080fd5b919390929091602081019035600160201b81111561037d57600080fd5b82018360208201111561038f57600080fd5b803590602001918460018302840111600160201b831117156103b057600080fd5b919390929091602081019035600160201b8111156103cd57600080fd5b8201836020820111156103df57600080fd5b803590602001918460018302840111600160201b8311171561040057600080fd5b919390929091602081019035600160201b81111561041d57600080fd5b82018360208201111561042f57600080fd5b803590602001918460018302840111600160201b8311171561045057600080fd5b91935091506001600160a01b03813581169160208101359091169060400135610cd8565b34801561048057600080fd5b5061048961106c565b604080516001600160a01b039092168252519081900360200190f35b3480156104b157600080fd5b5061048961107b565b3480156104c657600080fd5b506104cf61108a565b60408051918252519081900360200190f35b3480156104ed57600080fd5b506104cf6004803603604081101561050457600080fd5b50803590602001356001600160a01b0316611090565b34801561052657600080fd5b506104cf6004803603602081101561053d57600080fd5b50356110ad565b34801561055057600080fd5b506104cf6110cb565b34801561056557600080fd5b506102ee6004803603604081101561057c57600080fd5b508035906020013515156110d0565b34801561059757600080fd5b506105a06111ad565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156105dc5781810151838201526020016105c4565b505050509050019250505060405180910390f35b3480156105fc57600080fd5b506104cf611205565b34801561061157600080fd5b506102ee6004803603602081101561062857600080fd5b50356001600160a01b031661120b565b34801561064457600080fd5b5061066b6004803603602081101561065b57600080fd5b50356001600160a01b03166112b7565b604080519115158252519081900360200190f35b34801561068b57600080fd5b5061066b6112cc565b3480156106a057600080fd5b50610489600480360360208110156106b757600080fd5b50356112dc565b3480156106ca57600080fd5b506105a0611318565b3480156106df57600080fd5b506104cf61136e565b3480156106f457600080fd5b506104cf611374565b34801561070957600080fd5b506102ee61137a565b34801561071e57600080fd5b5061066b6004803603604081101561073557600080fd5b506001600160a01b038135169060200135611426565b34801561075757600080fd5b506105a0611446565b34801561076c57600080fd5b5061048961149c565b34801561078157600080fd5b506102ee6004803603604081101561079857600080fd5b506001600160a01b03813516906020013515156114ab565b3480156107bc57600080fd5b506104cf61156d565b3480156107d157600080fd5b506104cf600480360360208110156107e857600080fd5b5035611573565b3480156107fb57600080fd5b506104cf6004803603604081101561081257600080fd5b50803590602001356001600160a01b0316611580565b34801561083457600080fd5b506104cf6115aa565b34801561084957600080fd5b506104cf6115af565b34801561085e57600080fd5b506105a06115d3565b34801561087357600080fd5b5061087c611629565b60408051921515835260208301919091528051918290030190f35b3480156108a357600080fd5b50610489600480360360208110156108ba57600080fd5b5035611731565b3480156108cd57600080fd5b506104cf600480360360208110156108e457600080fd5b5035611758565b3480156108f757600080fd5b506102ee6004803603602081101561090e57600080fd5b50356001600160a01b0316611765565b34801561092a57600080fd5b506102ee6004803603606081101561094157600080fd5b810190602081018135600160201b81111561095b57600080fd5b82018360208201111561096d57600080fd5b803590602001918460018302840111600160201b8311171561098e57600080fd5b919390929091602081019035600160201b8111156109ab57600080fd5b8201836020820111156109bd57600080fd5b803590602001918460018302840111600160201b831117156109de57600080fd5b919390929091602081019035600160201b8111156109fb57600080fd5b820183602082011115610a0d57600080fd5b803590602001918460018302840111600160201b83111715610a2e57600080fd5b5090925090506117e9565b6102ee60048036036060811015610a4f57600080fd5b50803590602081013590604001356001600160a01b03166118ff565b348015610a7757600080fd5b5061066b60048036036020811015610a8e57600080fd5b5035611a12565b348015610aa157600080fd5b506104cf60048036036020811015610ab857600080fd5b5035611a40565b348015610acb57600080fd5b506104cf611a4d565b348015610ae057600080fd5b506104cf611a71565b348015610af557600080fd5b506102ee60048036036020811015610b0c57600080fd5b5035611a77565b348015610b1f57600080fd5b506105a0611aea565b348015610b3457600080fd5b506104cf611b4b565b348015610b4957600080fd5b506104cf611b50565b348015610b5e57600080fd5b506102ee60048036036040811015610b7557600080fd5b506001600160a01b0381351690602001351515611b55565b348015610b9957600080fd5b506104cf611db2565b348015610bae57600080fd5b506102ee60048036036020811015610bc557600080fd5b50356001600160a01b0316611db8565b610bdd6112cc565b15610c22576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6000610c2d8a6112dc565b6040805163d505accf60e01b81526001600160a01b038b811660048301528a81166024830152604482018a90526064820189905260ff8816608483015260a4820187905260c4820186905291519293509083169163d505accf9160e48082019260009290919082900301818387803b158015610ca857600080fd5b505af1158015610cbc573d6000803e3d6000fd5b50505050610ccc8a828a8c611eba565b50505050505050505050565b610ce06112cc565b15610d25576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b60005a6001600160a01b0385166000908152600b602052604090205490915060ff16610d825760405162461bcd60e51b815260040180806020018281038252602281526020018061302f6022913960400191505060405180910390fd5b60608c8c6000906004600a0160200292610d9e93929190612f69565b600c54604051879187916001600160a01b03909116906020018086868082843780830192505050846001600160a01b03166001600160a01b031660601b8152601401838152602001826001600160a01b03166001600160a01b031660601b8152601401955050505050506040516020818303038152906040529050610e62818051906020012088888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a9250612058915050565b610eea8d8d8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508e92508d91506122019050565b610f298d8d8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061222092505050565b600c546000906001600160a01b03165a604080519186036024830152604482018790526001600160a01b03881660648084019190915281518084039091018152608490920181526020820180516001600160e01b03166356aa719960e01b17815290518251909182918083835b60208310610fb55780518252601f199092019160209182019101610f96565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611017576040519150601f19603f3d011682016040523d82523d6000602084013e61101c565b606091505b505090508061105c5760405162461bcd60e51b8152600401808060200182810382526026815260200180612fe66026913960400191505060405180910390fd5b5050505050505050505050505050565b600c546001600160a01b031681565b6006546001600160a01b031681565b60035481565b600960209081526000928352604080842090915290825290205481565b601081815481106110ba57fe5b600091825260209091200154905081565b600e81565b6110d86124ab565b6001600160a01b03166110e961149c565b6001600160a01b031614611132576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b600061113d836112dc565b90506001600160a01b0381166111845760405162461bcd60e51b81526004018080602001828103825260288152602001806130a96028913960400191505060405180910390fd5b6001600160a01b03166000908152600860205260409020805460ff191691151591909117905550565b6060600d8054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020905b8154815260200190600101908083116111e7575b5050505050905090565b60045481565b6112136124ab565b6001600160a01b031661122461149c565b6001600160a01b03161461126d576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b600680546001600160a01b0319166001600160a01b0383169081179091556040517fd24015cc99cc1700cafca3042840a1d8ac1e3964fd2e0e37ea29c654056ee32790600090a250565b600b6020526000908152604090205460ff1681565b600054600160a01b900460ff1690565b6000816112eb57506000611313565b600760018303815481106112fb57fe5b6000918252602090912001546001600160a01b031690505b919050565b606060108054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020908154815260200190600101908083116111e7575050505050905090565b61018081565b60015481565b6113826124ab565b6001600160a01b031661139361149c565b6001600160a01b0316146113dc576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b600a60209081526000928352604080842090915290825290205460ff1681565b6060600f8054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020908154815260200190600101908083116111e7575050505050905090565b6000546001600160a01b031690565b6114b36124ab565b6001600160a01b03166114c461149c565b6001600160a01b03161461150d576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b6001600160a01b0382166000818152600b6020908152604091829020805460ff1916851515908117909155825190815291517f46359ce9dbb6c7f9a375b44072210287916d3de725fc8927a8e762047e4a84249281900390910190a25050565b60025481565b600f81815481106110ba57fe5b60008281526009602090815260408083206001600160a01b03851684529091529020545b92915050565b600c81565b7f00000000000000000000000000000000000000000000000000000000000011d081565b6060600e8054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020908154815260200190600101908083116111e7575050505050905090565b60008043817f00000000000000000000000000000000000000000000000000000000000011d07f00000000000000000000000000000000000000000000000000000000000012c0838161167857fe5b0610801591506000906116d8577f00000000000000000000000000000000000000000000000000000000000012c083816116ae57fe5b067f00000000000000000000000000000000000000000000000000000000000012c0039050611727565b7f00000000000000000000000000000000000000000000000000000000000012c0838161170157fe5b067f00000000000000000000000000000000000000000000000000000000000011d00390505b9093509150509091565b6007818154811061173e57fe5b6000918252602090912001546001600160a01b0316905081565b600e81815481106110ba57fe5b61176d6124ab565b6001600160a01b031661177e61149c565b6001600160a01b0316146117c7576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b6117f16112cc565b15611836576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6000611840611629565b5090508061187f5760405162461bcd60e51b815260040180806020018281038252602e815260200180612fb8602e913960400191505060405180910390fd5b6118f687878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8b0181900481028201810190925289815292508991508890819084018382808284376000920191909152508892508791506122019050565b50505050505050565b6119076112cc565b1561194c576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b826119b5578134146119a5576040805162461bcd60e51b815260206004820152601e60248201527f526f6c6c75702050726f636573736f723a2057524f4e475f414d4f554e540000604482015290519081900360640190fd5b6119b08382846124af565b611a0d565b34156119f25760405162461bcd60e51b81526004018080602001828103825260248152602001806132426024913960400191505060405180910390fd5b60006119fd846112dc565b9050611a0b84828486611eba565b505b505050565b600080611a1e836112dc565b6001600160a01b031660009081526008602052604090205460ff169392505050565b600d81815481106110ba57fe5b7f00000000000000000000000000000000000000000000000000000000000012c081565b60055481565b611a7f6112cc565b15611ac4576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b336000908152600a6020908152604080832093835292905220805460ff19166001179055565b606060078054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611b24575050505050905090565b600081565b600481565b611b5d6124ab565b6001600160a01b0316611b6e61149c565b6001600160a01b031614611bb7576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b6001600160a01b038216611c12576040805162461bcd60e51b815260206004820152601e60248201527f526f6c6c75702050726f636573736f723a205a45524f5f414444524553530000604482015290519081900360640190fd5b600780546001810182557fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6880180546001600160a01b0319166001600160a01b0385169081179091556000908152600860205260409020805460ff19168315151790555460048110611cb45760405162461bcd60e51b81526004018080602001828103825260238152602001806131a76023913960400191505060405180910390fd5b600d8054600181810190925560007fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5909101819055600e80548084019091557fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd01819055600f80548084019091557f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac8020181905560108054928301815581527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6729091018190556040516001600160a01b0385169183917fc53536963369dbfa4c398238ebb9b09fce3943a140928bd25d3052a8a9cacdaf9190a3505050565b6101c081565b611dc06124ab565b6001600160a01b0316611dd161149c565b6001600160a01b031614611e1a576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b6001600160a01b038116611e5f5760405162461bcd60e51b8152600401808060200182810382526026815260200180612f926026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60408051636eb1769f60e11b81526001600160a01b038481166004830152306024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b158015611f0b57600080fd5b505afa158015611f1f573d6000803e3d6000fd5b505050506040513d6020811015611f3557600080fd5b5051905081811015611f785760405162461bcd60e51b815260040180806020018281038252602d8152602001806131ef602d913960400191505060405180910390fd5b604080516323b872dd60e01b81526001600160a01b038581166004830152306024830152604482018590529151918616916323b872dd916064808201926020929091908290030181600087803b158015611fd157600080fd5b505af1158015611fe5573d6000803e3d6000fd5b505050506040513d6020811015611ffb57600080fd5b5061200990508584846124af565b604080518681526001600160a01b038516602082015280820184905290517feaa18152488ce5959073c9c79c88ca90b3d96c00de1f118cfaad664c3dab06b99181900360600190a15050505050565b6000806001600160a01b0383166120b6576040805162461bcd60e51b815260206004820152601f60248201527f76616c69646174655369676e61747572653a205a45524f5f4144445245535300604482015290519081900360640190fd5b60007f19457468657265756d205369676e6564204d6573736167653a0a33320000000060005285601c60000152603c60002090506040518551828252606087015160f81c60408801518060608501526020890151604085015281602085015260208460808660015afa601c8314601b84141760418514166fa2a8918ca85bafe22016d0b997e4df5f600160ff1b038310161696505050815183146000811461215d57612162565b825194505b5090528115199290921691826121a95760405162461bcd60e51b815260040180806020018281038252602c815260200180613051602c913960400191505060405180910390fd5b836001600160a01b0316826001600160a01b0316146121f95760405162461bcd60e51b815260040180806020018281038252602481526020018061315e6024913960400191505060405180910390fd5b505050505050565b600061220c85612537565b90506122198582866126a2565b5050505050565b60005b60048110156124a75760006122388383612773565b9050801561249e576000826122a457600c546040516001600160a01b03909116908390600081818185875af1925050503d8060008114612294576040519150601f19603f3d011682016040523d82523d6000602084013e612299565b606091505b50508091505061241d565b60006122af846112dc565b600c546040805163095ea7b360e01b81526001600160a01b0392831660048201526024810187905290519293509083169163095ea7b3916044808201926020929091908290030181600087803b15801561230857600080fd5b505af115801561231c573d6000803e3d6000fd5b505050506040513d602081101561233257600080fd5b5050600c546040805160248101879052604480820187905282518083039091018152606490910182526020810180516001600160e01b0316631c57762b60e31b178152915181516001600160a01b0390941693919290918291908083835b602083106123af5780518252601f199092019160209182019101612390565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612411576040519150601f19603f3d011682016040523d82523d6000602084013e612416565b606091505b5090925050505b806124595760405162461bcd60e51b81526004018080602001828103825260278152602001806131376027913960400191505060405180910390fd5b612483826010858154811061246a57fe5b906000526020600020015461278490919063ffffffff16565b6010848154811061249057fe5b600091825260209091200155505b50600101612223565b5050565b3390565b60008381526009602090815260408083206001600160a01b03861684529091529020546124e2908263ffffffff61278416565b60008481526009602090815260408083206001600160a01b0387168452909152902055600d80546125199183918690811061246a57fe5b600d848154811061252657fe5b600091825260209091200155505050565b60008060008060008060008061254c896127e5565b9650965096509650965096509650600080905060008060008060448e03600654945080519350602081015192506040810151915060ac815360316001820153608c6002820153605d60038201536040600482015289602482015260648f51016000808284895afa9650508381528260208201528160408201525084612618576040805162461bcd60e51b815260206004820152601960248201527f70726f6f6620766572696669636174696f6e206661696c656400000000000000604482015290519081900360640190fd5b60018c815560028c9055612633908b9063ffffffff61278416565b600555600388905560048690556001546002546040805192835260208301919091528181018a905260608201889052518b917ff1034928243e3365c0bf101598066f51439bb2a8763ec84cf7902d8917fb974f919081900360800190a250949c9b505050505050505050505050565b60006101e0808501906101808581028701909101905b818310156118f6578251602084015160408501518215821519821519171680156127625760608701518315612747576101408801518689206001600160a01b0382166000908152600a6020908152604080832084845290915290205460ff16612739578b8b0180516060825261272f838386612a5c565b905260609a909a01995b612744838388612ba4565b50505b82156127605761016088015161275e848284612cb1565b505b505b5050506101809390930192506126b8565b602081028201610140015192915050565b6000828201838110156127de576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b60008060008060008060006127f8612f4b565b60008060008060008061280c8f6004612e25565b96509650965096509650965096508660016004811061282757fe5b60200201511561283b57602087015161283e565b60015b60608801819052600090612853906002612e95565b9050806004548161286057fe5b066128ae576004546040890151146128a95760405162461bcd60e51b815260040180806020018281038252602c81526020018061307d602c913960400191505060405180910390fd5b612915565b600081600454816128bb57fe5b06826004540103905080896002600481106128d257fe5b6020020151146129135760405162461bcd60e51b815260040180806020018281038252602c81526020018061307d602c913960400191505060405180910390fd5b505b60015487146129555760405162461bcd60e51b81526004018080602001828103825260258152602001806131ca6025913960400191505060405180910390fd5b60025485146129955760405162461bcd60e51b81526004018080602001828103825260258152602001806131826025913960400191505060405180910390fd5b60035483146129d55760405162461bcd60e51b81526004018080602001828103825260258152602001806130d16025913960400191505060405180910390fd5b600554885114612a165760405162461bcd60e51b815260040180806020018281038252602381526020018061300c6023913960400191505060405180910390fd5b858489600060200201518a60016020020151858c60036020020151868e60026020020151019e509e509e509e509e509e509e505050505050505050919395979092949650565b6000806001600160a01b038316612aba576040805162461bcd60e51b815260206004820152601f60248201527f76616c69646174655369676e61747572653a205a45524f5f4144445245535300604482015290519081900360640190fd5b60007f19457468657265756d205369676e6564204d6573736167653a0a33320000000060005285601c52603c60002090508451818652606086015160408701518060608901526020880151604089015281602089015260208860808a60015afa601c8314601b84141760608514166fa2a8918ca85bafe22016d0b997e4df5f600160ff1b0383101616955050508551821460008114612b5857612b5d565b865193505b5085528115199290921691826121a95760405162461bcd60e51b815260040180806020018281038252602c815260200180613051602c913960400191505060405180910390fd5b60008381526009602090815260408083206001600160a01b038616845290915290205481811015612c065760405162461bcd60e51b815260040180806020018281038252602681526020018061321c6026913960400191505060405180910390fd5b612c16818363ffffffff612eee16565b60008581526009602090815260408083206001600160a01b0388168452909152902055600d8054612c6691849187908110612c4d57fe5b9060005260206000200154612eee90919063ffffffff16565b600d8581548110612c7357fe5b9060005260206000200181905550612c9282600e868154811061246a57fe5b600e8581548110612c9f57fe5b60009182526020909120015550505050565b6001600160a01b038216612d0c576040805162461bcd60e51b815260206004820152601e60248201527f526f6c6c75702050726f636573736f723a205a45524f5f414444524553530000604482015290519081900360640190fd5b80612d6c576040516001600160a01b038316906175309085906000818181858888f193505050503d8060008114612d5f576040519150601f19603f3d011682016040523d82523d6000602084013e612d64565b606091505b505050612e07565b6000612d77826112dc565b9050806001600160a01b031663a9059cbb84866040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015612dd957600080fd5b505af1158015612ded573d6000803e3d6000fd5b505050506040513d6020811015612e0357600080fd5b5050505b612e1883600f838154811061246a57fe5b600f828154811061252657fe5b612e2d612f4b565b5060208281015160408085015160608087015160808089015160a08a015160c08b015160e08c01516101008d01516101208e01519c8c02909d01610140015189519586018a529985529984019690965295820192909252918201949094529692959194909392565b600082612ea4575060006115a4565b82820282848281612eb157fe5b04146127de5760405162461bcd60e51b81526004018080602001828103825260218152602001806130f66021913960400191505060405180910390fd5b600082821115612f45576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60405180608001604052806004906020820280368337509192915050565b60008085851115612f78578182fd5b83861115612f84578182fd5b505082019391909203915056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373526f6c6c75702050726f636573736f723a204553434150455f424c4f434b5f52414e47455f494e434f5252454354526f6c6c75702050726f636573736f723a205245494d42555253455f4741535f4641494c4544526f6c6c75702050726f636573736f723a2049445f4e4f545f53455155454e5449414c526f6c6c75702050726f636573736f723a20554e4b4e4f574e5f50524f564944455276616c69646174655369676e61747572653a207369676e6174757265207265636f76657279206661696c6564526f6c6c75702050726f636573736f723a20494e434f52524543545f444154415f53544152545f494e444558526f6c6c75702050726f636573736f723a20544f4b454e5f41535345545f4e4f545f4c494e4b4544526f6c6c75702050726f636573736f723a20494e434f52524543545f524f4f545f524f4f54536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572526f6c6c75702050726f636573736f723a204445504f5349545f54585f4645455f4641494c454476616c69646174655369676e61747572653a20494e56414c49445f5349474e4154555245526f6c6c75702050726f636573736f723a20494e434f52524543545f4e554c4c5f524f4f54526f6c6c75702050726f636573736f723a204d41585f41535345545f52454143484544526f6c6c75702050726f636573736f723a20494e434f52524543545f444154415f524f4f54526f6c6c75702050726f636573736f723a20494e53554646494349454e545f544f4b454e5f415050524f56414c526f6c6c75702050726f636573736f723a20494e53554646494349454e545f4445504f534954526f6c6c75702050726f636573736f723a2057524f4e475f5041594d454e545f54595045a26469706673582212202fd47ddc29f53f6efddfd5689a51af7ae006998ca8597c21d3ffbbc3cd7da41f64736f6c634300060a0033

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

000000000000000000000000dcc80db987bf63f01b7bafced6230de5002ef87400000000000000000000000000000000000000000000000000000000000011d000000000000000000000000000000000000000000000000000000000000012c0000000000000000000000000fcf75295f242c4e87203abb5d7c9bbeda90a8895

-----Decoded View---------------
Arg [0] : _verifierAddress (address): 0xDCC80dB987bf63f01b7bafCED6230DE5002eF874
Arg [1] : _escapeBlockLowerBound (uint256): 4560
Arg [2] : _escapeBlockUpperBound (uint256): 4800
Arg [3] : _contractOwner (address): 0xFcF75295f242C4E87203Abb5d7C9BbEda90a8895

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000dcc80db987bf63f01b7bafced6230de5002ef874
Arg [1] : 00000000000000000000000000000000000000000000000000000000000011d0
Arg [2] : 00000000000000000000000000000000000000000000000000000000000012c0
Arg [3] : 000000000000000000000000fcf75295f242c4e87203abb5d7c9bbeda90a8895


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.

Validator Index Block Amount
View All Withdrawals

Txn Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.