ETH Price: $2,059.35 (-0.48%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ZkSync

Compiler Version
v0.5.16+commit.9c3226ce

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 18 : ZkSync.sol
pragma solidity ^0.5.0;

import "./ReentrancyGuard.sol";
import "./SafeMath.sol";
import "./SafeMathUInt128.sol";
import "./SafeCast.sol";
import "./Utils.sol";

import "./Storage.sol";
import "./Config.sol";
import "./Events.sol";

import "./Bytes.sol";
import "./Operations.sol";

import "./UpgradeableMaster.sol";

/// @title zkSync main contract
/// @author Matter Labs
contract ZkSync is UpgradeableMaster, Storage, Config, Events, ReentrancyGuard {
    using SafeMath for uint256;
    using SafeMathUInt128 for uint128;

    bytes32 public constant EMPTY_STRING_KECCAK = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;

    // Upgrade functional

    /// @notice Notice period before activation preparation status of upgrade mode
    function getNoticePeriod() external returns (uint) {
        return UPGRADE_NOTICE_PERIOD;
    }

    /// @notice Notification that upgrade notice period started
    function upgradeNoticePeriodStarted() external {

    }

    /// @notice Notification that upgrade preparation status is activated
    function upgradePreparationStarted() external {
        upgradePreparationActive = true;
        upgradePreparationActivationTime = now;
    }

    /// @notice Notification that upgrade canceled
    function upgradeCanceled() external {
        upgradePreparationActive = false;
        upgradePreparationActivationTime = 0;
    }

    /// @notice Notification that upgrade finishes
    function upgradeFinishes() external {
        upgradePreparationActive = false;
        upgradePreparationActivationTime = 0;
    }

    /// @notice Checks that contract is ready for upgrade
    /// @return bool flag indicating that contract is ready for upgrade
    function isReadyForUpgrade() external returns (bool) {
        return !exodusMode;
    }

    /// @notice Franklin contract initialization. Can be external because Proxy contract intercepts illegal calls of this function.
    /// @param initializationParameters Encoded representation of initialization parameters:
    /// _governanceAddress The address of Governance contract
    /// _verifierAddress The address of Verifier contract
    /// _ // FIXME: remove _genesisAccAddress
    /// _genesisRoot Genesis blocks (first block) root
    function initialize(bytes calldata initializationParameters) external {
        initializeReentrancyGuard();

        (
        address _governanceAddress,
        address _verifierAddress,
        bytes32 _genesisRoot
        ) = abi.decode(initializationParameters, (address, address, bytes32));

        verifier = Verifier(_verifierAddress);
        governance = Governance(_governanceAddress);

        blocks[0].stateRoot = _genesisRoot;
    }

    /// @notice zkSync contract upgrade. Can be external because Proxy contract intercepts illegal calls of this function.
    /// @param upgradeParameters Encoded representation of upgrade parameters
    function upgrade(bytes calldata upgradeParameters) external {}

    /// @notice Sends tokens
    /// @dev NOTE: will revert if transfer call fails or rollup balance difference (before and after transfer) is bigger than _maxAmount
    /// @param _token Token address
    /// @param _to Address of recipient
    /// @param _amount Amount of tokens to transfer
    /// @param _maxAmount Maximum possible amount of tokens to transfer to this account
    function withdrawERC20Guarded(IERC20 _token, address _to, uint128 _amount, uint128 _maxAmount) external returns (uint128 withdrawnAmount) {
        require(msg.sender == address(this), "wtg10"); // wtg10 - can be called only from this contract as one "external" call (to revert all this function state changes if it is needed)

        uint256 balance_before = _token.balanceOf(address(this));
        require(Utils.sendERC20(_token, _to, _amount), "wtg11"); // wtg11 - ERC20 transfer fails
        uint256 balance_after = _token.balanceOf(address(this));
        uint256 balance_diff = balance_before.sub(balance_after);
        require(balance_diff <= _maxAmount, "wtg12"); // wtg12 - rollup balance difference (before and after transfer) is bigger than _maxAmount

        return SafeCast.toUint128(balance_diff);
    }

    /// @notice executes pending withdrawals
    /// @param _n The number of withdrawals to complete starting from oldest
    function completeWithdrawals(uint32 _n) external nonReentrant {
        // TODO: when switched to multi validators model we need to add incentive mechanism to call complete.
        uint32 toProcess = Utils.minU32(_n, numberOfPendingWithdrawals);
        uint32 startIndex = firstPendingWithdrawalIndex;
        numberOfPendingWithdrawals -= toProcess;
        firstPendingWithdrawalIndex += toProcess;

        for (uint32 i = startIndex; i < startIndex + toProcess; ++i) {
            uint16 tokenId = pendingWithdrawals[i].tokenId;
            address to = pendingWithdrawals[i].to;
            // send fails are ignored hence there is always a direct way to withdraw.
            delete pendingWithdrawals[i];

            bytes22 packedBalanceKey = packAddressAndTokenId(to, tokenId);
            uint128 amount = balancesToWithdraw[packedBalanceKey].balanceToWithdraw;
            // amount is zero means funds has been withdrawn with withdrawETH or withdrawERC20
            if (amount != 0) {
                balancesToWithdraw[packedBalanceKey].balanceToWithdraw -= amount;
                bool sent = false;
                if (tokenId == 0) {
                    address payable toPayable = address(uint160(to));
                    sent = Utils.sendETHNoRevert(toPayable, amount);
                } else {
                    address tokenAddr = governance.tokenAddresses(tokenId);
                    // we can just check that call not reverts because it wants to withdraw all amount
                    (sent, ) = address(this).call.gas(ERC20_WITHDRAWAL_GAS_LIMIT)(
                        abi.encodeWithSignature("withdrawERC20Guarded(address,address,uint128,uint128)", tokenAddr, to, amount, amount)
                    );
                }
                if (!sent) {
                    balancesToWithdraw[packedBalanceKey].balanceToWithdraw += amount;
                }
            }
        }
        if (toProcess > 0) {
            emit PendingWithdrawalsComplete(startIndex, startIndex + toProcess);
        }
    }

    /// @notice Accrues users balances from deposit priority requests in Exodus mode
    /// @dev WARNING: Only for Exodus mode
    /// @dev Canceling may take several separate transactions to be completed
    /// @param _n number of requests to process
    function cancelOutstandingDepositsForExodusMode(uint64 _n) external nonReentrant {
        require(exodusMode, "coe01"); // exodus mode not active
        uint64 toProcess = Utils.minU64(totalOpenPriorityRequests, _n);
        require(toProcess > 0, "coe02"); // no deposits to process
        for (uint64 id = firstPriorityRequestId; id < firstPriorityRequestId + toProcess; id++) {
            if (priorityRequests[id].opType == Operations.OpType.Deposit) {
                Operations.Deposit memory op = Operations.readDepositPubdata(priorityRequests[id].pubData);
                bytes22 packedBalanceKey = packAddressAndTokenId(op.owner, op.tokenId);
                balancesToWithdraw[packedBalanceKey].balanceToWithdraw += op.amount;
            }
            delete priorityRequests[id];
        }
        firstPriorityRequestId += toProcess;
        totalOpenPriorityRequests -= toProcess;
    }

    /// @notice Deposit ETH to Layer 2 - transfer ether from user into contract, validate it, register deposit
    /// @param _franklinAddr The receiver Layer 2 address
    function depositETH(address _franklinAddr) external payable nonReentrant {
        requireActive();
        registerDeposit(0, SafeCast.toUint128(msg.value), _franklinAddr);
    }

    /// @notice Withdraw ETH to Layer 1 - register withdrawal and transfer ether to sender
    /// @param _amount Ether amount to withdraw
    function withdrawETH(uint128 _amount) external nonReentrant {
        registerWithdrawal(0, _amount, msg.sender);
        (bool success, ) = msg.sender.call.value(_amount)("");
        require(success, "fwe11"); // ETH withdraw failed
    }

    /// @notice Deposit ERC20 token to Layer 2 - transfer ERC20 tokens from user into contract, validate it, register deposit
    /// @param _token Token address
    /// @param _amount Token amount
    /// @param _franklinAddr Receiver Layer 2 address
    function depositERC20(IERC20 _token, uint104 _amount, address _franklinAddr) external nonReentrant {
        requireActive();

        // Get token id by its address
        uint16 tokenId = governance.validateTokenAddress(address(_token));

        uint256 balance_before = _token.balanceOf(address(this));
        require(Utils.transferFromERC20(_token, msg.sender, address(this), SafeCast.toUint128(_amount)), "fd012"); // token transfer failed deposit
        uint256 balance_after = _token.balanceOf(address(this));
        uint128 deposit_amount = SafeCast.toUint128(balance_after.sub(balance_before));

        registerDeposit(tokenId, deposit_amount, _franklinAddr);
    }

    /// @notice Withdraw ERC20 token to Layer 1 - register withdrawal and transfer ERC20 to sender
    /// @param _token Token address
    /// @param _amount amount to withdraw
    function withdrawERC20(IERC20 _token, uint128 _amount) external nonReentrant {
        uint16 tokenId = governance.validateTokenAddress(address(_token));
        bytes22 packedBalanceKey = packAddressAndTokenId(msg.sender, tokenId);
        uint128 balance = balancesToWithdraw[packedBalanceKey].balanceToWithdraw;
        uint128 withdrawnAmount = this.withdrawERC20Guarded(_token, msg.sender, _amount, balance);
        registerWithdrawal(tokenId, withdrawnAmount, msg.sender);
    }

    /// @notice Register full exit request - pack pubdata, add priority request
    /// @param _accountId Numerical id of the account
    /// @param _token Token address, 0 address for ether
    function fullExit (uint32 _accountId, address _token) external nonReentrant {
        requireActive();
        require(_accountId <= MAX_ACCOUNT_ID, "fee11");

        uint16 tokenId;
        if (_token == address(0)) {
            tokenId = 0;
        } else {
            tokenId = governance.validateTokenAddress(_token);
        }

        // Priority Queue request
        Operations.FullExit memory op = Operations.FullExit({
            accountId:  _accountId,
            owner:      msg.sender,
            tokenId:    tokenId,
            amount:     0 // unknown at this point
        });
        bytes memory pubData = Operations.writeFullExitPubdata(op);
        addPriorityRequest(Operations.OpType.FullExit, pubData);

        // User must fill storage slot of balancesToWithdraw(msg.sender, tokenId) with nonzero value
        // In this case operator should just overwrite this slot during confirming withdrawal
        bytes22 packedBalanceKey = packAddressAndTokenId(msg.sender, tokenId);
        balancesToWithdraw[packedBalanceKey].gasReserveValue = 0xff;
    }

    /// @notice Commit block - collect onchain operations, create its commitment, emit BlockCommit event
    /// @param _blockNumber Block number
    /// @param _feeAccount Account to collect fees
    /// @param _newBlockInfo New state of the block. (first element is the account tree root hash, rest of the array is reserved for the future)
    /// @param _publicData Operations pubdata
    /// @param _ethWitness Data passed to ethereum outside pubdata of the circuit.
    /// @param _ethWitnessSizes Amount of eth witness bytes for the corresponding operation.
    function commitBlock(
        uint32 _blockNumber,
        uint32 _feeAccount,
        bytes32[] calldata _newBlockInfo,
        bytes calldata _publicData,
        bytes calldata _ethWitness,
        uint32[] calldata _ethWitnessSizes
    ) external nonReentrant {
        requireActive();
        require(_blockNumber == totalBlocksCommitted + 1, "fck11"); // only commit next block
        governance.requireActiveValidator(msg.sender);
        require(_newBlockInfo.length == 1, "fck13"); // This version of the contract expects only account tree root hash

        bytes memory publicData = _publicData;

        // Unpack onchain operations and store them.
        // Get priority operations number for this block.
        uint64 prevTotalCommittedPriorityRequests = totalCommittedPriorityRequests;

        bytes32 withdrawalsDataHash = collectOnchainOps(_blockNumber, publicData, _ethWitness, _ethWitnessSizes);

        uint64 nPriorityRequestProcessed = totalCommittedPriorityRequests - prevTotalCommittedPriorityRequests;

        createCommittedBlock(_blockNumber, _feeAccount, _newBlockInfo[0], publicData, withdrawalsDataHash, nPriorityRequestProcessed);
        totalBlocksCommitted++;

        emit BlockCommit(_blockNumber);
    }

    /// @notice Block verification.
    /// @notice Verify proof -> process onchain withdrawals (accrue balances from withdrawals) -> remove priority requests
    /// @param _blockNumber Block number
    /// @param _proof Block proof
    /// @param _withdrawalsData Block withdrawals data
    function verifyBlock(uint32 _blockNumber, uint256[] calldata _proof, bytes calldata _withdrawalsData)
        external nonReentrant
    {
        requireActive();
        require(_blockNumber == totalBlocksVerified + 1, "fvk11"); // only verify next block
        governance.requireActiveValidator(msg.sender);

        require(verifier.verifyBlockProof(_proof, blocks[_blockNumber].commitment, blocks[_blockNumber].chunks), "fvk13"); // proof verification failed

        processOnchainWithdrawals(_withdrawalsData, blocks[_blockNumber].withdrawalsDataHash);

        deleteRequests(
            blocks[_blockNumber].priorityOperations
        );

        totalBlocksVerified += 1;

        emit BlockVerification(_blockNumber);
    }


    /// @notice Reverts unverified blocks
    /// @param _maxBlocksToRevert the maximum number blocks that will be reverted (use if can't revert all blocks because of gas limit).
    function revertBlocks(uint32 _maxBlocksToRevert) external nonReentrant {
        require(isBlockCommitmentExpired(), "rbs11"); // trying to revert non-expired blocks.
        governance.requireActiveValidator(msg.sender);

        uint32 blocksCommited = totalBlocksCommitted;
        uint32 blocksToRevert = Utils.minU32(_maxBlocksToRevert, blocksCommited - totalBlocksVerified);
        uint64 revertedPriorityRequests = 0;

        for (uint32 i = totalBlocksCommitted - blocksToRevert + 1; i <= blocksCommited; i++) {
            Block memory revertedBlock = blocks[i];
            require(revertedBlock.committedAtBlock > 0, "frk11"); // block not found

            revertedPriorityRequests += revertedBlock.priorityOperations;

            delete blocks[i];
        }

        blocksCommited -= blocksToRevert;
        totalBlocksCommitted -= blocksToRevert;
        totalCommittedPriorityRequests -= revertedPriorityRequests;

        emit BlocksRevert(totalBlocksVerified, blocksCommited);
    }

    /// @notice Checks if Exodus mode must be entered. If true - enters exodus mode and emits ExodusMode event.
    /// @dev Exodus mode must be entered in case of current ethereum block number is higher than the oldest
    /// @dev of existed priority requests expiration block number.
    /// @return bool flag that is true if the Exodus mode must be entered.
    function triggerExodusIfNeeded() external returns (bool) {
        bool trigger = block.number >= priorityRequests[firstPriorityRequestId].expirationBlock &&
        priorityRequests[firstPriorityRequestId].expirationBlock != 0;
        if (trigger) {
            if (!exodusMode) {
                exodusMode = true;
                emit ExodusMode();
            }
            return true;
        } else {
            return false;
        }
    }

    /// @notice Withdraws token from Franklin to root chain in case of exodus mode. User must provide proof that he owns funds
    /// @param _accountId Id of the account in the tree
    /// @param _proof Proof
    /// @param _tokenId Verified token id
    /// @param _amount Amount for owner (must be total amount, not part of it)
    function exit(uint32 _accountId, uint16 _tokenId, uint128 _amount, uint256[] calldata _proof) external nonReentrant {
        bytes22 packedBalanceKey = packAddressAndTokenId(msg.sender, _tokenId);
        require(exodusMode, "fet11"); // must be in exodus mode
        require(!exited[_accountId][_tokenId], "fet12"); // already exited
        require(verifier.verifyExitProof(blocks[totalBlocksVerified].stateRoot, _accountId, msg.sender, _tokenId, _amount, _proof), "fet13"); // verification failed

        uint128 balance = balancesToWithdraw[packedBalanceKey].balanceToWithdraw;
        balancesToWithdraw[packedBalanceKey].balanceToWithdraw = balance.add(_amount);
        exited[_accountId][_tokenId] = true;
    }

    function setAuthPubkeyHash(bytes calldata _pubkey_hash, uint32 _nonce) external nonReentrant {
        require(_pubkey_hash.length == PUBKEY_HASH_BYTES, "ahf10"); // PubKeyHash should be 20 bytes.
        require(authFacts[msg.sender][_nonce] == bytes32(0), "ahf11"); // auth fact for nonce should be empty

        authFacts[msg.sender][_nonce] = keccak256(_pubkey_hash);

        emit FactAuth(msg.sender, _nonce, _pubkey_hash);
    }

    /// @notice Register deposit request - pack pubdata, add priority request and emit OnchainDeposit event
    /// @param _tokenId Token by id
    /// @param _amount Token amount
    /// @param _owner Receiver
    function registerDeposit(
        uint16 _tokenId,
        uint128 _amount,
        address _owner
    ) internal {
        // Priority Queue request
        Operations.Deposit memory op = Operations.Deposit({
            accountId:  0, // unknown at this point
            owner:      _owner,
            tokenId:    _tokenId,
            amount:     _amount
            });
        bytes memory pubData = Operations.writeDepositPubdata(op);
        addPriorityRequest(Operations.OpType.Deposit, pubData);

        emit OnchainDeposit(
            msg.sender,
            _tokenId,
            _amount,
            _owner
        );
    }

    /// @notice Register withdrawal - update user balance and emit OnchainWithdrawal event
    /// @param _token - token by id
    /// @param _amount - token amount
    /// @param _to - address to withdraw to
    function registerWithdrawal(uint16 _token, uint128 _amount, address payable _to) internal {
        bytes22 packedBalanceKey = packAddressAndTokenId(_to, _token);
        uint128 balance = balancesToWithdraw[packedBalanceKey].balanceToWithdraw;
        balancesToWithdraw[packedBalanceKey].balanceToWithdraw = balance.sub(_amount);
        emit OnchainWithdrawal(
            _to,
            _token,
            _amount
        );
    }

    /// @notice Store committed block structure to the storage.
    /// @param _nCommittedPriorityRequests - number of priority requests in block
    function createCommittedBlock(
        uint32 _blockNumber,
        uint32 _feeAccount,
        bytes32 _newRoot,
        bytes memory _publicData,
        bytes32 _withdrawalDataHash,
        uint64 _nCommittedPriorityRequests
    ) internal {
        require(_publicData.length % CHUNK_BYTES == 0, "cbb10"); // Public data size is not multiple of CHUNK_BYTES

        uint32 blockChunks = uint32(_publicData.length / CHUNK_BYTES);
        require(verifier.isBlockSizeSupported(blockChunks), "ccb11");

        // Create block commitment for verification proof
        bytes32 commitment = createBlockCommitment(
            _blockNumber,
            _feeAccount,
            blocks[_blockNumber - 1].stateRoot,
            _newRoot,
            _publicData
        );

        blocks[_blockNumber] = Block(
            uint32(block.number), // committed at
            _nCommittedPriorityRequests, // number of priority onchain ops in block
            blockChunks,
            _withdrawalDataHash, // hash of onchain withdrawals data (will be used during checking block withdrawal data in verifyBlock function)
            commitment, // blocks' commitment
            _newRoot // new root
        );
    }

    function emitDepositCommitEvent(uint32 _blockNumber, Operations.Deposit memory depositData) internal {
        emit DepositCommit(_blockNumber, depositData.accountId, depositData.owner, depositData.tokenId, depositData.amount);
    }

    function emitFullExitCommitEvent(uint32 _blockNumber, Operations.FullExit memory fullExitData) internal {
        emit FullExitCommit(_blockNumber, fullExitData.accountId, fullExitData.owner, fullExitData.tokenId, fullExitData.amount);
    }

    /// @notice Gets operations packed in bytes array. Unpacks it and stores onchain operations.
    /// @param _blockNumber Franklin block number
    /// @param _publicData Operations packed in bytes array
    /// @param _ethWitness Eth witness that was posted with commit
    /// @param _ethWitnessSizes Amount of eth witness bytes for the corresponding operation.
    /// Priority operations must be committed in the same order as they are in the priority queue.
    function collectOnchainOps(uint32 _blockNumber, bytes memory _publicData, bytes memory _ethWitness, uint32[] memory _ethWitnessSizes)
        internal returns (bytes32 withdrawalsDataHash) {
        require(_publicData.length % CHUNK_BYTES == 0, "fcs11"); // pubdata length must be a multiple of CHUNK_BYTES

        uint64 currentPriorityRequestId = firstPriorityRequestId + totalCommittedPriorityRequests;

        uint256 pubDataPtr = 0;
        uint256 pubDataStartPtr = 0;
        uint256 pubDataEndPtr = 0;

        assembly { pubDataStartPtr := add(_publicData, 0x20) }
        pubDataPtr = pubDataStartPtr;
        pubDataEndPtr = pubDataStartPtr + _publicData.length;

        uint64 ethWitnessOffset = 0;
        uint16 processedOperationsRequiringEthWitness = 0;

        withdrawalsDataHash = EMPTY_STRING_KECCAK;

        while (pubDataPtr < pubDataEndPtr) {
            Operations.OpType opType;
            // read operation type from public data (the first byte per each operation)
            assembly {
                opType := shr(0xf8, mload(pubDataPtr))
            }

            // cheap operations processing
            if (opType == Operations.OpType.Transfer) {
                pubDataPtr += TRANSFER_BYTES;
            } else if (opType == Operations.OpType.Noop) {
                pubDataPtr += NOOP_BYTES;
            } else if (opType == Operations.OpType.TransferToNew) {
                pubDataPtr += TRANSFER_TO_NEW_BYTES;
            } else {
                // other operations processing

                // calculation of public data offset
                uint256 pubdataOffset = pubDataPtr - pubDataStartPtr;

                if (opType == Operations.OpType.Deposit) {
                    bytes memory pubData = Bytes.slice(_publicData, pubdataOffset + 1, DEPOSIT_BYTES - 1);

                    Operations.Deposit memory depositData = Operations.readDepositPubdata(pubData);
                    emitDepositCommitEvent(_blockNumber, depositData);

                    OnchainOperation memory onchainOp = OnchainOperation(
                        Operations.OpType.Deposit,
                        pubData
                    );
                    commitNextPriorityOperation(onchainOp, currentPriorityRequestId);
                    currentPriorityRequestId++;

                    pubDataPtr += DEPOSIT_BYTES;
                } else if (opType == Operations.OpType.PartialExit) {
                    Operations.PartialExit memory data = Operations.readPartialExitPubdata(_publicData, pubdataOffset + 1);

                    bool addToPendingWithdrawalsQueue = true;
                    withdrawalsDataHash = keccak256(abi.encode(withdrawalsDataHash, addToPendingWithdrawalsQueue, data.owner, data.tokenId, data.amount));

                    pubDataPtr += PARTIAL_EXIT_BYTES;
                } else if (opType == Operations.OpType.FullExit) {
                    bytes memory pubData = Bytes.slice(_publicData, pubdataOffset + 1, FULL_EXIT_BYTES - 1);

                    Operations.FullExit memory fullExitData = Operations.readFullExitPubdata(pubData);
                    emitFullExitCommitEvent(_blockNumber, fullExitData);

                    bool addToPendingWithdrawalsQueue = false;
                    withdrawalsDataHash = keccak256(abi.encode(withdrawalsDataHash, addToPendingWithdrawalsQueue, fullExitData.owner, fullExitData.tokenId, fullExitData.amount));

                    OnchainOperation memory onchainOp = OnchainOperation(
                        Operations.OpType.FullExit,
                        pubData
                    );
                    commitNextPriorityOperation(onchainOp, currentPriorityRequestId);
                    currentPriorityRequestId++;

                    pubDataPtr += FULL_EXIT_BYTES;
                } else if (opType == Operations.OpType.ChangePubKey) {
                    require(processedOperationsRequiringEthWitness < _ethWitnessSizes.length, "fcs13"); // eth witness data malformed
                    Operations.ChangePubKey memory op = Operations.readChangePubKeyPubdata(_publicData, pubdataOffset + 1);

                    if (_ethWitnessSizes[processedOperationsRequiringEthWitness] != 0) {
                        bytes memory currentEthWitness = Bytes.slice(_ethWitness, ethWitnessOffset, _ethWitnessSizes[processedOperationsRequiringEthWitness]);

                        bool valid = verifyChangePubkeySignature(currentEthWitness, op.pubKeyHash, op.nonce, op.owner, op.accountId);
                        require(valid, "fpp15"); // failed to verify change pubkey hash signature
                    } else {
                        bool valid = authFacts[op.owner][op.nonce] == keccak256(abi.encodePacked(op.pubKeyHash));
                        require(valid, "fpp16"); // new pub key hash is not authenticated properly
                    }

                    ethWitnessOffset += _ethWitnessSizes[processedOperationsRequiringEthWitness];
                    processedOperationsRequiringEthWitness++;

                    pubDataPtr += CHANGE_PUBKEY_BYTES;
                } else {
                    revert("fpp14"); // unsupported op
                }
            }
        }
        require(pubDataPtr == pubDataEndPtr, "fcs12"); // last chunk exceeds pubdata
        require(ethWitnessOffset == _ethWitness.length, "fcs14"); // _ethWitness was not used completely
        require(processedOperationsRequiringEthWitness == _ethWitnessSizes.length, "fcs15"); // _ethWitnessSizes was not used completely

        require(currentPriorityRequestId <= firstPriorityRequestId + totalOpenPriorityRequests, "fcs16"); // fcs16 - excess priority requests in pubdata
        totalCommittedPriorityRequests = currentPriorityRequestId - firstPriorityRequestId;
    }

    /// @notice Checks that signature is valid for pubkey change message
    /// @param _signature Signature
    /// @param _newPkHash New pubkey hash
    /// @param _nonce Nonce used for message
    /// @param _ethAddress Account's ethereum address
    /// @param _accountId Id of zkSync account
    function verifyChangePubkeySignature(bytes memory _signature, bytes20 _newPkHash, uint32 _nonce, address _ethAddress, uint32 _accountId) internal pure returns (bool) {
        bytes memory signedMessage = abi.encodePacked(
            "\x19Ethereum Signed Message:\n152",
            "Register zkSync pubkey:\n\n",
            Bytes.bytesToHexASCIIBytes(abi.encodePacked(_newPkHash)), "\n",
            "nonce: 0x", Bytes.bytesToHexASCIIBytes(Bytes.toBytesFromUInt32(_nonce)), "\n",
            "account id: 0x", Bytes.bytesToHexASCIIBytes(Bytes.toBytesFromUInt32(_accountId)),
            "\n\n",
            "Only sign this message for a trusted client!"
        );
        address recoveredAddress = Utils.recoverAddressFromEthSignature(_signature, signedMessage);
        return recoveredAddress == _ethAddress;
    }

    /// @notice Creates block commitment from its data
    /// @param _blockNumber Block number
    /// @param _feeAccount Account to collect fees
    /// @param _oldRoot Old tree root
    /// @param _newRoot New tree root
    /// @param _publicData Operations pubdata
    /// @return block commitment
    function createBlockCommitment(
        uint32 _blockNumber,
        uint32 _feeAccount,
        bytes32 _oldRoot,
        bytes32 _newRoot,
        bytes memory _publicData
    ) internal view returns (bytes32 commitment) {
        bytes32 hash = sha256(
            abi.encodePacked(uint256(_blockNumber), uint256(_feeAccount))
        );
        hash = sha256(abi.encodePacked(hash, uint256(_oldRoot)));
        hash = sha256(abi.encodePacked(hash, uint256(_newRoot)));

        /// The code below is equivalent to `commitment = sha256(abi.encodePacked(hash, _publicData))`

        /// We use inline assembly instead of this concise and readable code in order to avoid copying of `_publicData` (which saves ~90 gas per transfer operation).

        /// Specifically, we perform the following trick:
        /// First, replace the first 32 bytes of `_publicData` (where normally its length is stored) with the value of `hash`.
        /// Then, we call `sha256` precompile passing the `_publicData` pointer and the length of the concatenated byte buffer.
        /// Finally, we put the `_publicData.length` back to its original location (to the first word of `_publicData`).
        assembly {
            let hashResult := mload(0x40)
            let pubDataLen := mload(_publicData)
            mstore(_publicData, hash)
            // staticcall to the sha256 precompile at address 0x2
            let success := staticcall(
                gas,
                0x2,
                _publicData,
                add(pubDataLen, 0x20),
                hashResult,
                0x20
            )
            mstore(_publicData, pubDataLen)

            // Use "invalid" to make gas estimation work
            switch success case 0 { invalid() }

            commitment := mload(hashResult)
        }
    }

    /// @notice Checks that operation is same as operation in priority queue
    /// @param _onchainOp The operation
    /// @param _priorityRequestId Operation's id in priority queue
    function commitNextPriorityOperation(OnchainOperation memory _onchainOp, uint64 _priorityRequestId) internal view {
        Operations.OpType priorReqType = priorityRequests[_priorityRequestId].opType;
        bytes memory priorReqPubdata = priorityRequests[_priorityRequestId].pubData;

        require(priorReqType == _onchainOp.opType, "nvp12"); // incorrect priority op type

        if (_onchainOp.opType == Operations.OpType.Deposit) {
            require(Operations.depositPubdataMatch(priorReqPubdata, _onchainOp.pubData), "vnp13");
        } else if (_onchainOp.opType == Operations.OpType.FullExit) {
            require(Operations.fullExitPubdataMatch(priorReqPubdata, _onchainOp.pubData), "vnp14");
        } else {
            revert("vnp15"); // invalid or non-priority operation
        }
    }

    /// @notice Processes onchain withdrawals. Full exit withdrawals will not be added to pending withdrawals queue
    /// @dev NOTICE: must process only withdrawals which hash matches with expectedWithdrawalsDataHash.
    /// @param withdrawalsData Withdrawals data
    /// @param expectedWithdrawalsDataHash Expected withdrawals data hash
    function processOnchainWithdrawals(bytes memory withdrawalsData, bytes32 expectedWithdrawalsDataHash) internal {
        require(withdrawalsData.length % ONCHAIN_WITHDRAWAL_BYTES == 0, "pow11"); // pow11 - withdrawalData length is not multiple of ONCHAIN_WITHDRAWAL_BYTES

        bytes32 withdrawalsDataHash = EMPTY_STRING_KECCAK;

        uint offset = 0;
        uint32 localNumberOfPendingWithdrawals = numberOfPendingWithdrawals;
        while (offset < withdrawalsData.length) {
            (bool addToPendingWithdrawalsQueue, address _to, uint16 _tokenId, uint128 _amount) = Operations.readWithdrawalData(withdrawalsData, offset);
            bytes22 packedBalanceKey = packAddressAndTokenId(_to, _tokenId);

            uint128 balance = balancesToWithdraw[packedBalanceKey].balanceToWithdraw;
            // after this all writes to this slot will cost 5k gas
            balancesToWithdraw[packedBalanceKey] = BalanceToWithdraw({
                balanceToWithdraw: balance.add(_amount),
                gasReserveValue: 0xff
            });

            if (addToPendingWithdrawalsQueue) {
                pendingWithdrawals[firstPendingWithdrawalIndex + localNumberOfPendingWithdrawals] = PendingWithdrawal(_to, _tokenId);
                localNumberOfPendingWithdrawals++;
            }

            withdrawalsDataHash = keccak256(abi.encode(withdrawalsDataHash, addToPendingWithdrawalsQueue, _to, _tokenId, _amount));
            offset += ONCHAIN_WITHDRAWAL_BYTES;
        }
        require(withdrawalsDataHash == expectedWithdrawalsDataHash, "pow12"); // pow12 - withdrawals data hash not matches with expected value
        if (numberOfPendingWithdrawals != localNumberOfPendingWithdrawals) {
            emit PendingWithdrawalsAdd(firstPendingWithdrawalIndex + numberOfPendingWithdrawals, firstPendingWithdrawalIndex + localNumberOfPendingWithdrawals);
        }
        numberOfPendingWithdrawals = localNumberOfPendingWithdrawals;
    }

    /// @notice Checks whether oldest unverified block has expired
    /// @return bool flag that indicates whether oldest unverified block has expired
    function isBlockCommitmentExpired() internal view returns (bool) {
        return (
            totalBlocksCommitted > totalBlocksVerified &&
            blocks[totalBlocksVerified + 1].committedAtBlock > 0 &&
            block.number > blocks[totalBlocksVerified + 1].committedAtBlock + EXPECT_VERIFICATION_IN
        );
    }

    /// @notice Checks that current state not is exodus mode
    function requireActive() internal view {
        require(!exodusMode, "fre11"); // exodus mode activated
    }

    // Priority queue

    /// @notice Saves priority request in storage
    /// @dev Calculates expiration block for request, store this request and emit NewPriorityRequest event
    /// @param _opType Rollup operation type
    /// @param _pubData Operation pubdata
    function addPriorityRequest(
        Operations.OpType _opType,
        bytes memory _pubData
    ) internal {
        // Expiration block is: current block number + priority expiration delta
        uint256 expirationBlock = block.number + PRIORITY_EXPIRATION;

        uint64 nextPriorityRequestId = firstPriorityRequestId + totalOpenPriorityRequests;

        priorityRequests[nextPriorityRequestId] = PriorityOperation({
            opType: _opType,
            pubData: _pubData,
            expirationBlock: expirationBlock
        });

        emit NewPriorityRequest(
            msg.sender,
            nextPriorityRequestId,
            _opType,
            _pubData,
            expirationBlock
        );

        totalOpenPriorityRequests++;
    }

    /// @notice Deletes processed priority requests
    /// @param _number The number of requests
    function deleteRequests(uint64 _number) internal {
        require(_number <= totalOpenPriorityRequests, "pcs21"); // number is higher than total priority requests number

        uint64 numberOfRequestsToClear = Utils.minU64(_number, MAX_PRIORITY_REQUESTS_TO_DELETE_IN_VERIFY);
        uint64 startIndex = firstPriorityRequestId;
        for (uint64 i = startIndex; i < startIndex + numberOfRequestsToClear; i++) {
            delete priorityRequests[i];
        }

        totalOpenPriorityRequests -= _number;
        firstPriorityRequestId += _number;
        totalCommittedPriorityRequests -= _number;
    }

}

File 2 of 18 : ReentrancyGuard.sol
pragma solidity ^0.5.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 *
 * _Since v2.5.0:_ this module is now much more gas efficient, given net gas
 * metering changes introduced in the Istanbul hardfork.
 */
contract ReentrancyGuard {
    /// Address of lock flag variable.
    /// Flag is placed at random memory location to not interfere with Storage contract.
    uint constant private LOCK_FLAG_ADDRESS = 0x8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4; // keccak256("ReentrancyGuard") - 1;

    function initializeReentrancyGuard () internal {
        // Storing an initial non-zero value makes deployment a bit more
        // expensive, but in exchange the refund on every call to nonReentrant
        // will be lower in amount. Since refunds are capped to a percetange of
        // the total transaction's gas, it is best to keep them low in cases
        // like this one, to increase the likelihood of the full refund coming
        // into effect.
        assembly { sstore(LOCK_FLAG_ADDRESS, 1) }
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        bool notEntered;
        assembly { notEntered := sload(LOCK_FLAG_ADDRESS) }

        // On the first call to nonReentrant, _notEntered will be true
        require(notEntered, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        assembly { sstore(LOCK_FLAG_ADDRESS, 0) }

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        assembly { sstore(LOCK_FLAG_ADDRESS, 1) }
    }
}

File 3 of 18 : SafeMath.sol
pragma solidity ^0.5.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, 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) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     *
     * _Available since v2.4.0._
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

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

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts 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) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message 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.
     *
     * _Available since v2.4.0._
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts 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) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message 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.
     *
     * _Available since v2.4.0._
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

File 4 of 18 : SafeMathUInt128.sol
pragma solidity ^0.5.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 SafeMathUInt128 {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint128 a, uint128 b) internal pure returns (uint128) {
        uint128 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(uint128 a, uint128 b) internal pure returns (uint128) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     *
     * _Available since v2.4.0._
     */
    function sub(uint128 a, uint128 b, string memory errorMessage) internal pure returns (uint128) {
        require(b <= a, errorMessage);
        uint128 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint128 a, uint128 b) internal pure returns (uint128) {
        // 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 0;
        }

        uint128 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts 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(uint128 a, uint128 b) internal pure returns (uint128) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message 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.
     *
     * _Available since v2.4.0._
     */
    function div(uint128 a, uint128 b, string memory errorMessage) internal pure returns (uint128) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint128 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts 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(uint128 a, uint128 b) internal pure returns (uint128) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message 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.
     *
     * _Available since v2.4.0._
     */
    function mod(uint128 a, uint128 b, string memory errorMessage) internal pure returns (uint128) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

File 5 of 18 : SafeCast.sol
pragma solidity ^0.5.0;


/**
 * @dev Wrappers over Solidity's uintXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such 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.
 *
 * Can be combined with {SafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and then downcasting.
 *
 * _Available since v2.5.0._
 */
library SafeCast {

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits");
        return uint8(value);
    }
}

File 6 of 18 : Utils.sol
pragma solidity ^0.5.0;

import "./IERC20.sol";
import "./Bytes.sol";

library Utils {
    /// @notice Returns lesser of two values
    function minU32(uint32 a, uint32 b) internal pure returns (uint32) {
        return a < b ? a : b;
    }

    /// @notice Returns lesser of two values
    function minU64(uint64 a, uint64 b) internal pure returns (uint64) {
        return a < b ? a : b;
    }

    /// @notice Sends tokens
    /// @dev NOTE: this function handles tokens that have transfer function not strictly compatible with ERC20 standard
    /// @dev NOTE: call `transfer` to this token may return (bool) or nothing
    /// @param _token Token address
    /// @param _to Address of recipient
    /// @param _amount Amount of tokens to transfer
    /// @return bool flag indicating that transfer is successful
    function sendERC20(IERC20 _token, address _to, uint256 _amount) internal returns (bool) {
        (bool callSuccess, bytes memory callReturnValueEncoded) = address(_token).call(
            abi.encodeWithSignature("transfer(address,uint256)", _to, _amount)
        );
        // `transfer` method may return (bool) or nothing.
        bool returnedSuccess = callReturnValueEncoded.length == 0 || abi.decode(callReturnValueEncoded, (bool));
        return callSuccess && returnedSuccess;
    }

    /// @notice Transfers token from one address to another
    /// @dev NOTE: this function handles tokens that have transfer function not strictly compatible with ERC20 standard
    /// @dev NOTE: call `transferFrom` to this token may return (bool) or nothing
    /// @param _token Token address
    /// @param _from Address of sender
    /// @param _to Address of recipient
    /// @param _amount Amount of tokens to transfer
    /// @return bool flag indicating that transfer is successful
    function transferFromERC20(IERC20 _token, address _from, address _to, uint256 _amount) internal returns (bool) {
        (bool callSuccess, bytes memory callReturnValueEncoded) = address(_token).call(
            abi.encodeWithSignature("transferFrom(address,address,uint256)", _from, _to, _amount)
        );
        // `transferFrom` method may return (bool) or nothing.
        bool returnedSuccess = callReturnValueEncoded.length == 0 || abi.decode(callReturnValueEncoded, (bool));
        return callSuccess && returnedSuccess;
    }

    /// @notice Sends ETH
    /// @param _to Address of recipient
    /// @param _amount Amount of tokens to transfer
    /// @return bool flag indicating that transfer is successful
    function sendETHNoRevert(address payable _to, uint256 _amount) internal returns (bool) {
        // TODO: Use constant from Config
        uint256 ETH_WITHDRAWAL_GAS_LIMIT = 10000;

        (bool callSuccess, ) = _to.call.gas(ETH_WITHDRAWAL_GAS_LIMIT).value(_amount)("");
        return callSuccess;
    }

    /// @notice Recovers signer's address from ethereum signature for given message
    /// @param _signature 65 bytes concatenated. R (32) + S (32) + V (1)
    /// @param _message signed message.
    /// @return address of the signer
    function recoverAddressFromEthSignature(bytes memory _signature, bytes memory _message) internal pure returns (address) {
        require(_signature.length == 65, "ves10"); // incorrect signature length

        bytes32 signR;
        bytes32 signS;
        uint offset = 0;

        (offset, signR) = Bytes.readBytes32(_signature, offset);
        (offset, signS) = Bytes.readBytes32(_signature, offset);
        uint8 signV = uint8(_signature[offset]);

        return ecrecover(keccak256(_message), signV, signR, signS);
    }
}

File 7 of 18 : Storage.sol
pragma solidity ^0.5.0;

import "./IERC20.sol";

import "./Governance.sol";
import "./Verifier.sol";
import "./Operations.sol";


/// @title zkSync storage contract
/// @author Matter Labs
contract Storage {

    /// @notice Flag indicates that upgrade preparation status is active
    /// @dev Will store false in case of not active upgrade mode
    bool public upgradePreparationActive;

    /// @notice Upgrade preparation activation timestamp (as seconds since unix epoch)
    /// @dev Will be equal to zero in case of not active upgrade mode
    uint public upgradePreparationActivationTime;

    /// @notice Verifier contract. Used to verify block proof and exit proof
    Verifier internal verifier;

    /// @notice Governance contract. Contains the governor (the owner) of whole system, validators list, possible tokens list
    Governance internal governance;

    struct BalanceToWithdraw {
        uint128 balanceToWithdraw;
        uint8 gasReserveValue; // gives user opportunity to fill storage slot with nonzero value
    }

    /// @notice Root-chain balances (per owner and token id, see packAddressAndTokenId) to withdraw
    mapping(bytes22 => BalanceToWithdraw) public balancesToWithdraw;

    /// @notice verified withdrawal pending to be executed.
    struct PendingWithdrawal {
        address to;
        uint16 tokenId;
    }
    
    /// @notice Verified but not executed withdrawals for addresses stored in here (key is pendingWithdrawal's index in pending withdrawals queue)
    mapping(uint32 => PendingWithdrawal) public pendingWithdrawals;
    uint32 public firstPendingWithdrawalIndex;
    uint32 public numberOfPendingWithdrawals;

    /// @notice Total number of verified blocks i.e. blocks[totalBlocksVerified] points at the latest verified block (block 0 is genesis)
    uint32 public totalBlocksVerified;

    /// @notice Total number of committed blocks i.e. blocks[totalBlocksCommitted] points at the latest committed block
    uint32 public totalBlocksCommitted;

    /// @notice Rollup block data (once per block)
    /// @member validator Block producer
    /// @member committedAtBlock ETH block number at which this block was committed
    /// @member cumulativeOnchainOperations Total number of operations in this and all previous blocks
    /// @member priorityOperations Total number of priority operations for this block
    /// @member commitment Hash of the block circuit commitment
    /// @member stateRoot New tree root hash
    ///
    /// Consider memory alignment when changing field order: https://solidity.readthedocs.io/en/v0.4.21/miscellaneous.html
    struct Block {
        uint32 committedAtBlock;
        uint64 priorityOperations;
        uint32 chunks;
        bytes32 withdrawalsDataHash; /// can be restricted to 16 bytes to reduce number of required storage slots
        bytes32 commitment;
        bytes32 stateRoot;
    }

    /// @notice Blocks by Franklin block id
    mapping(uint32 => Block) public blocks;

    /// @notice Onchain operations - operations processed inside rollup blocks
    /// @member opType Onchain operation type
    /// @member amount Amount used in the operation
    /// @member pubData Operation pubdata
    struct OnchainOperation {
        Operations.OpType opType;
        bytes pubData;
    }

    /// @notice Flag indicates that a user has exited certain token balance (per account id and tokenId)
    mapping(uint32 => mapping(uint16 => bool)) public exited;

    /// @notice Flag indicates that exodus (mass exit) mode is triggered
    /// @notice Once it was raised, it can not be cleared again, and all users must exit
    bool public exodusMode;

    /// @notice User authenticated fact hashes for some nonce.
    mapping(address => mapping(uint32 => bytes32)) public authFacts;

    /// @notice Priority Operation container
    /// @member opType Priority operation type
    /// @member pubData Priority operation public data
    /// @member expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)
    struct PriorityOperation {
        Operations.OpType opType;
        bytes pubData;
        uint256 expirationBlock;
    }

    /// @notice Priority Requests mapping (request id - operation)
    /// @dev Contains op type, pubdata and expiration block of unsatisfied requests.
    /// @dev Numbers are in order of requests receiving
    mapping(uint64 => PriorityOperation) public priorityRequests;

    /// @notice First open priority request id
    uint64 public firstPriorityRequestId;

    /// @notice Total number of requests
    uint64 public totalOpenPriorityRequests;

    /// @notice Total number of committed requests.
    /// @dev Used in checks: if the request matches the operation on Rollup contract and if provided number of requests is not too big
    uint64 public totalCommittedPriorityRequests;

    /// @notice Packs address and token id into single word to use as a key in balances mapping
    function packAddressAndTokenId(address _address, uint16 _tokenId) internal pure returns (bytes22) {
        return bytes22((uint176(_address) | (uint176(_tokenId) << 160)));
    }

    /// @notice Gets value from balancesToWithdraw
    function getBalanceToWithdraw(address _address, uint16 _tokenId) public view returns (uint128) {
        return balancesToWithdraw[packAddressAndTokenId(_address, _tokenId)].balanceToWithdraw;
    }
}

File 8 of 18 : Config.sol
pragma solidity ^0.5.0;


/// @title zkSync configuration constants
/// @author Matter Labs
contract Config {

    /// @notice ERC20 token withdrawal gas limit, used only for complete withdrawals
    uint256 constant ERC20_WITHDRAWAL_GAS_LIMIT = 250000;

    /// @notice ETH token withdrawal gas limit, used only for complete withdrawals
    uint256 constant ETH_WITHDRAWAL_GAS_LIMIT = 10000;

    /// @notice Bytes in one chunk
    uint8 constant CHUNK_BYTES = 9;

    /// @notice zkSync address length
    uint8 constant ADDRESS_BYTES = 20;

    uint8 constant PUBKEY_HASH_BYTES = 20;

    /// @notice Public key bytes length
    uint8 constant PUBKEY_BYTES = 32;

    /// @notice Ethereum signature r/s bytes length
    uint8 constant ETH_SIGN_RS_BYTES = 32;

    /// @notice Success flag bytes length
    uint8 constant SUCCESS_FLAG_BYTES = 1;

    /// @notice Max amount of tokens registered in the network (excluding ETH, which is hardcoded as tokenId = 0)
    uint16 constant MAX_AMOUNT_OF_REGISTERED_TOKENS = 128 - 1;

    /// @notice Max account id that could be registered in the network
    uint32 constant MAX_ACCOUNT_ID = (2 ** 24) - 1;

    /// @notice Expected average period of block creation
    uint256 constant BLOCK_PERIOD = 15 seconds;

    /// @notice ETH blocks verification expectation
    /// Blocks can be reverted if they are not verified for at least EXPECT_VERIFICATION_IN.
    /// If set to 0 validator can revert blocks at any time.
    uint256 constant EXPECT_VERIFICATION_IN = 0 hours / BLOCK_PERIOD;

    uint256 constant NOOP_BYTES = 1 * CHUNK_BYTES;
    uint256 constant DEPOSIT_BYTES = 6 * CHUNK_BYTES;
    uint256 constant TRANSFER_TO_NEW_BYTES = 6 * CHUNK_BYTES;
    uint256 constant PARTIAL_EXIT_BYTES = 6 * CHUNK_BYTES;
    uint256 constant TRANSFER_BYTES = 2 * CHUNK_BYTES;

    /// @notice Full exit operation length
    uint256 constant FULL_EXIT_BYTES = 6 * CHUNK_BYTES;

    /// @notice OnchainWithdrawal data length
    uint256 constant ONCHAIN_WITHDRAWAL_BYTES = 1 + 20 + 2 + 16; // (uint8 addToPendingWithdrawalsQueue, address _to, uint16 _tokenId, uint128 _amount)

    /// @notice ChangePubKey operation length
    uint256 constant CHANGE_PUBKEY_BYTES = 6 * CHUNK_BYTES;

    /// @notice Expiration delta for priority request to be satisfied (in seconds)
    /// NOTE: Priority expiration should be > (EXPECT_VERIFICATION_IN * BLOCK_PERIOD), otherwise incorrect block with priority op could not be reverted.
    uint256 constant PRIORITY_EXPIRATION_PERIOD = 3 days;

    /// @notice Expiration delta for priority request to be satisfied (in ETH blocks)
    uint256 constant PRIORITY_EXPIRATION = PRIORITY_EXPIRATION_PERIOD / BLOCK_PERIOD;

    /// @notice Maximum number of priority request to clear during verifying the block
    /// @dev Cause deleting storage slots cost 5k gas per each slot it's unprofitable to clear too many slots
    /// @dev Value based on the assumption of ~750k gas cost of verifying and 5 used storage slots per PriorityOperation structure
    uint64 constant MAX_PRIORITY_REQUESTS_TO_DELETE_IN_VERIFY = 6;

    /// @notice Reserved time for users to send full exit priority operation in case of an upgrade (in seconds)
    uint constant MASS_FULL_EXIT_PERIOD = 3 days;

    /// @notice Reserved time for users to withdraw funds from full exit priority operation in case of an upgrade (in seconds)
    uint constant TIME_TO_WITHDRAW_FUNDS_FROM_FULL_EXIT = 2 days;

    /// @notice Notice period before activation preparation status of upgrade mode (in seconds)
    // NOTE: we must reserve for users enough time to send full exit operation, wait maximum time for processing this operation and withdraw funds from it.
    uint constant UPGRADE_NOTICE_PERIOD = MASS_FULL_EXIT_PERIOD + PRIORITY_EXPIRATION_PERIOD + TIME_TO_WITHDRAW_FUNDS_FROM_FULL_EXIT;

}

File 9 of 18 : Events.sol
pragma solidity ^0.5.0;

import "./Upgradeable.sol";
import "./Operations.sol";


/// @title zkSync events
/// @author Matter Labs
interface Events {

    /// @notice Event emitted when a block is committed
    event BlockCommit(uint32 indexed blockNumber);

    /// @notice Event emitted when a block is verified
    event BlockVerification(uint32 indexed blockNumber);

    /// @notice Event emitted when user send a transaction to withdraw her funds from onchain balance
    event OnchainWithdrawal(
        address indexed owner,
        uint16 indexed tokenId,
        uint128 amount
    );

    /// @notice Event emitted when user send a transaction to deposit her funds
    event OnchainDeposit(
        address indexed sender,
        uint16 indexed tokenId,
        uint128 amount,
        address indexed owner
    );

    /// @notice Event emitted when user sends a authentication fact (e.g. pub-key hash)
    event FactAuth(
        address indexed sender,
        uint32 nonce,
        bytes fact
    );

    /// @notice Event emitted when blocks are reverted
    event BlocksRevert(
        uint32 totalBlocksVerified,
        uint32 totalBlocksCommitted
    );

    /// @notice Exodus mode entered event
    event ExodusMode();

    /// @notice New priority request event. Emitted when a request is placed into mapping
    event NewPriorityRequest(
        address sender,
        uint64 serialId,
        Operations.OpType opType,
        bytes pubData,
        uint256 expirationBlock
    );

    /// @notice Deposit committed event.
    event DepositCommit(
        uint32 indexed zkSyncBlockId,
        uint32 indexed accountId,
        address owner,
        uint16 indexed tokenId,
        uint128 amount
    );

    /// @notice Full exit committed event.
    event FullExitCommit(
        uint32 indexed zkSyncBlockId,
        uint32 indexed accountId,
        address owner,
        uint16 indexed tokenId,
        uint128 amount
    );

    /// @notice Pending withdrawals index range that were added in the verifyBlock operation.
    /// NOTE: processed indexes in the queue map are [queueStartIndex, queueEndIndex)
    event PendingWithdrawalsAdd(
        uint32 queueStartIndex,
        uint32 queueEndIndex
    );

    /// @notice Pending withdrawals index range that were executed in the completeWithdrawals operation.
    /// NOTE: processed indexes in the queue map are [queueStartIndex, queueEndIndex)
    event PendingWithdrawalsComplete(
        uint32 queueStartIndex,
        uint32 queueEndIndex
    );
}

/// @title Upgrade events
/// @author Matter Labs
interface UpgradeEvents {

    /// @notice Event emitted when new upgradeable contract is added to upgrade gatekeeper's list of managed contracts
    event NewUpgradable(
        uint indexed versionId,
        address indexed upgradeable
    );

    /// @notice Upgrade mode enter event
    event NoticePeriodStart(
        uint indexed versionId,
        address[] newTargets,
        uint noticePeriod // notice period (in seconds)
    );

    /// @notice Upgrade mode cancel event
    event UpgradeCancel(
        uint indexed versionId
    );

    /// @notice Upgrade mode preparation status event
    event PreparationStart(
        uint indexed versionId
    );

    /// @notice Upgrade mode complete event
    event UpgradeComplete(
        uint indexed versionId,
        address[] newTargets
    );

}

File 10 of 18 : Bytes.sol
pragma solidity ^0.5.0;

// Functions named bytesToX, except bytesToBytes20, where X is some type of size N < 32 (size of one word)
// implements the following algorithm:
// f(bytes memory input, uint offset) -> X out
// where byte representation of out is N bytes from input at the given offset
// 1) We compute memory location of the word W such that last N bytes of W is input[offset..offset+N]
// W_address = input + 32 (skip stored length of bytes) + offset - (32 - N) == input + offset + N
// 2) We load W from memory into out, last N bytes of W are placed into out

library Bytes {

    function toBytesFromUInt16(uint16 self) internal pure returns (bytes memory _bts) {
        return toBytesFromUIntTruncated(uint(self), 2);
    }

    function toBytesFromUInt24(uint24 self) internal pure returns (bytes memory _bts) {
        return toBytesFromUIntTruncated(uint(self), 3);
    }

    function toBytesFromUInt32(uint32 self) internal pure returns (bytes memory _bts) {
        return toBytesFromUIntTruncated(uint(self), 4);
    }

    function toBytesFromUInt128(uint128 self) internal pure returns (bytes memory _bts) {
        return toBytesFromUIntTruncated(uint(self), 16);
    }

    // Copies 'len' lower bytes from 'self' into a new 'bytes memory'.
    // Returns the newly created 'bytes memory'. The returned bytes will be of length 'len'.
    function toBytesFromUIntTruncated(uint self, uint8 byteLength) private pure returns (bytes memory bts) {
        require(byteLength <= 32, "bt211");
        bts = new bytes(byteLength);
        // Even though the bytes will allocate a full word, we don't want
        // any potential garbage bytes in there.
        uint data = self << ((32 - byteLength) * 8);
        assembly {
            mstore(add(bts, /*BYTES_HEADER_SIZE*/32), data)
        }
    }

    // Copies 'self' into a new 'bytes memory'.
    // Returns the newly created 'bytes memory'. The returned bytes will be of length '20'.
    function toBytesFromAddress(address self) internal pure returns (bytes memory bts) {
        bts = toBytesFromUIntTruncated(uint(self), 20);
    }

    // See comment at the top of this file for explanation of how this function works.
    // NOTE: theoretically possible overflow of (_start + 20)
    function bytesToAddress(bytes memory self, uint256 _start) internal pure returns (address addr) {
        uint256 offset = _start + 20;
        require(self.length >= offset, "bta11");
        assembly {
            addr := mload(add(self, offset))
        }
    }

    // Reasoning about why this function works is similar to that of other similar functions, except NOTE below.
    // NOTE: that bytes1..32 is stored in the beginning of the word unlike other primitive types
    // NOTE: theoretically possible overflow of (_start + 20)
    function bytesToBytes20(bytes memory self, uint256 _start) internal pure returns (bytes20 r) {
        require(self.length >= (_start + 20), "btb20");
        assembly {
            r := mload(add(add(self, 0x20), _start))
        }
    }

    // See comment at the top of this file for explanation of how this function works.
    // NOTE: theoretically possible overflow of (_start + 0x2)
    function bytesToUInt16(bytes memory _bytes, uint256 _start) internal pure returns (uint16 r) {
        uint256 offset = _start + 0x2;
        require(_bytes.length >= offset, "btu02");
        assembly {
            r := mload(add(_bytes, offset))
        }
    }

    // See comment at the top of this file for explanation of how this function works.
    // NOTE: theoretically possible overflow of (_start + 0x3)
    function bytesToUInt24(bytes memory _bytes, uint256 _start) internal pure returns (uint24 r) {
        uint256 offset = _start + 0x3;
        require(_bytes.length >= offset, "btu03");
        assembly {
            r := mload(add(_bytes, offset))
        }
    }

    // NOTE: theoretically possible overflow of (_start + 0x4)
    function bytesToUInt32(bytes memory _bytes, uint256 _start) internal pure returns (uint32 r) {
        uint256 offset = _start + 0x4;
        require(_bytes.length >= offset, "btu04");
        assembly {
            r := mload(add(_bytes, offset))
        }
    }

    // NOTE: theoretically possible overflow of (_start + 0x10)
    function bytesToUInt128(bytes memory _bytes, uint256 _start) internal pure returns (uint128 r) {
        uint256 offset = _start + 0x10;
        require(_bytes.length >= offset, "btu16");
        assembly {
            r := mload(add(_bytes, offset))
        }
    }

    // See comment at the top of this file for explanation of how this function works.
    // NOTE: theoretically possible overflow of (_start + 0x14)
    function bytesToUInt160(bytes memory _bytes, uint256 _start) internal pure returns (uint160 r) {
        uint256 offset = _start + 0x14;
        require(_bytes.length >= offset, "btu20");
        assembly {
            r := mload(add(_bytes, offset))
        }
    }

    // NOTE: theoretically possible overflow of (_start + 0x20)
    function bytesToBytes32(bytes memory  _bytes, uint256 _start) internal pure returns (bytes32 r) {
        uint256 offset = _start + 0x20;
        require(_bytes.length >= offset, "btb32");
        assembly {
            r := mload(add(_bytes, offset))
        }
    }

    // Original source code: https://github.com/GNSPS/solidity-bytes-utils/blob/master/contracts/BytesLib.sol#L228
    // Get slice from bytes arrays
    // Returns the newly created 'bytes memory'
    // NOTE: theoretically possible overflow of (_start + _length)
    function slice(
        bytes memory _bytes,
        uint _start,
        uint _length
    )
        internal
        pure
        returns (bytes memory)
    {
        require(_bytes.length >= (_start + _length), "bse11"); // bytes length is less then start byte + length bytes

        bytes memory tempBytes = new bytes(_length);

        if (_length != 0) {
            // TODO: Review this thoroughly.
            assembly {
                let slice_curr := add(tempBytes, 0x20)
                let slice_end := add(slice_curr, _length)

                for {
                    let array_current := add(_bytes, add(_start, 0x20))
                } lt(slice_curr, slice_end) {
                    slice_curr := add(slice_curr, 0x20)
                    array_current := add(array_current, 0x20)
                } {
                    mstore(slice_curr, mload(array_current))
                }
            }
        }

        return tempBytes;
    }

    /// Reads byte stream
    /// @return new_offset - offset + amount of bytes read
    /// @return data - actually read data
    // NOTE: theoretically possible overflow of (_offset + _length)
    function read(bytes memory _data, uint _offset, uint _length) internal pure returns (uint new_offset, bytes memory data) {
        data = slice(_data, _offset, _length);
        new_offset = _offset + _length;
    }

    // NOTE: theoretically possible overflow of (_offset + 1)
    function readBool(bytes memory _data, uint _offset) internal pure returns (uint new_offset, bool r) {
        new_offset = _offset + 1;
        r = uint8(_data[_offset]) != 0;
    }

    // NOTE: theoretically possible overflow of (_offset + 1)
    function readUint8(bytes memory _data, uint _offset) internal pure returns (uint new_offset, uint8 r) {
        new_offset = _offset + 1;
        r = uint8(_data[_offset]);
    }

    // NOTE: theoretically possible overflow of (_offset + 2)
    function readUInt16(bytes memory _data, uint _offset) internal pure returns (uint new_offset, uint16 r) {
        new_offset = _offset + 2;
        r = bytesToUInt16(_data, _offset);
    }

    // NOTE: theoretically possible overflow of (_offset + 3)
    function readUInt24(bytes memory _data, uint _offset) internal pure returns (uint new_offset, uint24 r) {
        new_offset = _offset + 3;
        r = bytesToUInt24(_data, _offset);
    }

    // NOTE: theoretically possible overflow of (_offset + 4)
    function readUInt32(bytes memory _data, uint _offset) internal pure returns (uint new_offset, uint32 r) {
        new_offset = _offset + 4;
        r = bytesToUInt32(_data, _offset);
    }

    // NOTE: theoretically possible overflow of (_offset + 16)
    function readUInt128(bytes memory _data, uint _offset) internal pure returns (uint new_offset, uint128 r) {
        new_offset = _offset + 16;
        r = bytesToUInt128(_data, _offset);
    }

    // NOTE: theoretically possible overflow of (_offset + 20)
    function readUInt160(bytes memory _data, uint _offset) internal pure returns (uint new_offset, uint160 r) {
        new_offset = _offset + 20;
        r = bytesToUInt160(_data, _offset);
    }

    // NOTE: theoretically possible overflow of (_offset + 20)
    function readAddress(bytes memory _data, uint _offset) internal pure returns (uint new_offset, address r) {
        new_offset = _offset + 20;
        r = bytesToAddress(_data, _offset);
    }

    // NOTE: theoretically possible overflow of (_offset + 20)
    function readBytes20(bytes memory _data, uint _offset) internal pure returns (uint new_offset, bytes20 r) {
        new_offset = _offset + 20;
        r = bytesToBytes20(_data, _offset);
    }

    // NOTE: theoretically possible overflow of (_offset + 32)
    function readBytes32(bytes memory _data, uint _offset) internal pure returns (uint new_offset, bytes32 r) {
        new_offset = _offset + 32;
        r = bytesToBytes32(_data, _offset);
    }

    // Helper function for hex conversion.
    function halfByteToHex(byte _byte) internal pure returns (byte _hexByte) {
        require(uint8(_byte) < 0x10, "hbh11");  // half byte's value is out of 0..15 range.

        // "FEDCBA9876543210" ASCII-encoded, shifted and automatically truncated.
        return byte (uint8 (0x66656463626139383736353433323130 >> (uint8 (_byte) * 8)));
    }

    // Convert bytes to ASCII hex representation
    function bytesToHexASCIIBytes(bytes memory  _input) internal pure returns (bytes memory _output) {
        bytes memory outStringBytes = new bytes(_input.length * 2);

        // code in `assembly` construction is equivalent of the next code:
        // for (uint i = 0; i < _input.length; ++i) {
        //     outStringBytes[i*2] = halfByteToHex(_input[i] >> 4);
        //     outStringBytes[i*2+1] = halfByteToHex(_input[i] & 0x0f);
        // }
        assembly {
            let input_curr := add(_input, 0x20)
            let input_end := add(input_curr, mload(_input))

            for {
                let out_curr := add(outStringBytes, 0x20)
            } lt(input_curr, input_end) {
                input_curr := add(input_curr, 0x01)
                out_curr := add(out_curr, 0x02)
            } {
                let curr_input_byte := shr(0xf8, mload(input_curr))
                // here outStringByte from each half of input byte calculates by the next:
                //
                // "FEDCBA9876543210" ASCII-encoded, shifted and automatically truncated.
                // outStringByte = byte (uint8 (0x66656463626139383736353433323130 >> (uint8 (_byteHalf) * 8)))
                mstore(out_curr,            shl(0xf8, shr(mul(shr(0x04, curr_input_byte), 0x08), 0x66656463626139383736353433323130)))
                mstore(add(out_curr, 0x01), shl(0xf8, shr(mul(and(0x0f, curr_input_byte), 0x08), 0x66656463626139383736353433323130)))
            }
        }
        return outStringBytes;
    }

    /// Trim bytes into single word
    function trim(bytes memory _data, uint _new_length) internal pure returns (uint r) {
        require(_new_length <= 0x20, "trm10");  // new_length is longer than word
        require(_data.length >= _new_length, "trm11");  // data is to short

        uint a;
        assembly {
            a := mload(add(_data, 0x20)) // load bytes into uint256
        }

        return a >> ((0x20 - _new_length) * 8);
    }
}

File 11 of 18 : Operations.sol
pragma solidity ^0.5.0;

import "./Bytes.sol";


/// @title zkSync operations tools
library Operations {

    // Circuit ops and their pubdata (chunks * bytes)

    /// @notice zkSync circuit operation type
    enum OpType {
        Noop,
        Deposit,
        TransferToNew,
        PartialExit,
        _CloseAccount, // used for correct op id offset
        Transfer,
        FullExit,
        ChangePubKey
    }

    // Byte lengths

    uint8 constant TOKEN_BYTES = 2;

    uint8 constant PUBKEY_BYTES = 32;

    uint8 constant NONCE_BYTES = 4;

    uint8 constant PUBKEY_HASH_BYTES = 20;

    uint8 constant ADDRESS_BYTES = 20;

    /// @notice Packed fee bytes lengths
    uint8 constant FEE_BYTES = 2;

    /// @notice zkSync account id bytes lengths
    uint8 constant ACCOUNT_ID_BYTES = 4;

    uint8 constant AMOUNT_BYTES = 16;

    /// @notice Signature (for example full exit signature) bytes length
    uint8 constant SIGNATURE_BYTES = 64;

    // Deposit pubdata
    struct Deposit {
        uint32 accountId;
        uint16 tokenId;
        uint128 amount;
        address owner;
    }

    uint public constant PACKED_DEPOSIT_PUBDATA_BYTES = 
        ACCOUNT_ID_BYTES + TOKEN_BYTES + AMOUNT_BYTES + ADDRESS_BYTES;

    /// Deserialize deposit pubdata
    function readDepositPubdata(bytes memory _data) internal pure
        returns (Deposit memory parsed)
    {
        // NOTE: there is no check that variable sizes are same as constants (i.e. TOKEN_BYTES), fix if possible.
        uint offset = 0;
        (offset, parsed.accountId) = Bytes.readUInt32(_data, offset); // accountId
        (offset, parsed.tokenId) = Bytes.readUInt16(_data, offset);   // tokenId
        (offset, parsed.amount) = Bytes.readUInt128(_data, offset);   // amount
        (offset, parsed.owner) = Bytes.readAddress(_data, offset);    // owner

        require(offset == PACKED_DEPOSIT_PUBDATA_BYTES, "rdp10"); // reading invalid deposit pubdata size
    }

    /// Serialize deposit pubdata
    function writeDepositPubdata(Deposit memory op) internal pure returns (bytes memory buf) {
        buf = abi.encodePacked(
            bytes4(0),   // accountId (ignored) (update when ACCOUNT_ID_BYTES is changed)
            op.tokenId,  // tokenId
            op.amount,   // amount
            op.owner     // owner
        );
    }

    /// @notice Check that deposit pubdata from request and block matches
    function depositPubdataMatch(bytes memory _lhs, bytes memory _rhs) internal pure returns (bool) {
        // We must ignore `accountId` because it is present in block pubdata but not in priority queue
        bytes memory lhs_trimmed = Bytes.slice(_lhs, ACCOUNT_ID_BYTES, PACKED_DEPOSIT_PUBDATA_BYTES - ACCOUNT_ID_BYTES);
        bytes memory rhs_trimmed = Bytes.slice(_rhs, ACCOUNT_ID_BYTES, PACKED_DEPOSIT_PUBDATA_BYTES - ACCOUNT_ID_BYTES);
        return keccak256(lhs_trimmed) == keccak256(rhs_trimmed);
    }

    // FullExit pubdata

    struct FullExit {
        uint32 accountId;
        address owner;
        uint16 tokenId;
        uint128 amount;
    }

    uint public constant PACKED_FULL_EXIT_PUBDATA_BYTES = 
        ACCOUNT_ID_BYTES + ADDRESS_BYTES + TOKEN_BYTES + AMOUNT_BYTES;

    function readFullExitPubdata(bytes memory _data) internal pure
        returns (FullExit memory parsed)
    {
        // NOTE: there is no check that variable sizes are same as constants (i.e. TOKEN_BYTES), fix if possible.
        uint offset = 0;
        (offset, parsed.accountId) = Bytes.readUInt32(_data, offset);      // accountId
        (offset, parsed.owner) = Bytes.readAddress(_data, offset);         // owner
        (offset, parsed.tokenId) = Bytes.readUInt16(_data, offset);        // tokenId
        (offset, parsed.amount) = Bytes.readUInt128(_data, offset);        // amount

        require(offset == PACKED_FULL_EXIT_PUBDATA_BYTES, "rfp10"); // reading invalid full exit pubdata size
    }

    function writeFullExitPubdata(FullExit memory op) internal pure returns (bytes memory buf) {
        buf = abi.encodePacked(
            op.accountId,  // accountId
            op.owner,      // owner
            op.tokenId,    // tokenId
            op.amount      // amount
        );
    }

    /// @notice Check that full exit pubdata from request and block matches
    function fullExitPubdataMatch(bytes memory _lhs, bytes memory _rhs) internal pure returns (bool) {
        // `amount` is ignored because it is present in block pubdata but not in priority queue
        uint lhs = Bytes.trim(_lhs, PACKED_FULL_EXIT_PUBDATA_BYTES - AMOUNT_BYTES);
        uint rhs = Bytes.trim(_rhs, PACKED_FULL_EXIT_PUBDATA_BYTES - AMOUNT_BYTES);
        return lhs == rhs;
    }

    // PartialExit pubdata
    
    struct PartialExit {
        //uint32 accountId; -- present in pubdata, ignored at serialization
        uint16 tokenId;
        uint128 amount;
        //uint16 fee; -- present in pubdata, ignored at serialization
        address owner;
    }

    function readPartialExitPubdata(bytes memory _data, uint _offset) internal pure
        returns (PartialExit memory parsed)
    {
        // NOTE: there is no check that variable sizes are same as constants (i.e. TOKEN_BYTES), fix if possible.
        uint offset = _offset + ACCOUNT_ID_BYTES;                   // accountId (ignored)
        (offset, parsed.tokenId) = Bytes.readUInt16(_data, offset); // tokenId
        (offset, parsed.amount) = Bytes.readUInt128(_data, offset); // amount
        offset += FEE_BYTES;                                        // fee (ignored)
        (offset, parsed.owner) = Bytes.readAddress(_data, offset);  // owner
    }

    function writePartialExitPubdata(PartialExit memory op) internal pure returns (bytes memory buf) {
        buf = abi.encodePacked(
            bytes4(0),  // accountId (ignored) (update when ACCOUNT_ID_BYTES is changed)
            op.tokenId, // tokenId
            op.amount,  // amount
            bytes2(0),  // fee (ignored)  (update when FEE_BYTES is changed)
            op.owner    // owner
        );
    }

    // ChangePubKey

    struct ChangePubKey {
        uint32 accountId;
        bytes20 pubKeyHash;
        address owner;
        uint32 nonce;
    }

    function readChangePubKeyPubdata(bytes memory _data, uint _offset) internal pure
        returns (ChangePubKey memory parsed)
    {
        uint offset = _offset;
        (offset, parsed.accountId) = Bytes.readUInt32(_data, offset);                // accountId
        (offset, parsed.pubKeyHash) = Bytes.readBytes20(_data, offset);              // pubKeyHash
        (offset, parsed.owner) = Bytes.readAddress(_data, offset);                   // owner
        (offset, parsed.nonce) = Bytes.readUInt32(_data, offset);                    // nonce
    }

    // Withdrawal data process

    function readWithdrawalData(bytes memory _data, uint _offset) internal pure
        returns (bool _addToPendingWithdrawalsQueue, address _to, uint16 _tokenId, uint128 _amount)
    {
        uint offset = _offset;
        (offset, _addToPendingWithdrawalsQueue) = Bytes.readBool(_data, offset);
        (offset, _to) = Bytes.readAddress(_data, offset);
        (offset, _tokenId) = Bytes.readUInt16(_data, offset);
        (offset, _amount) = Bytes.readUInt128(_data, offset);
    }

}

File 12 of 18 : UpgradeableMaster.sol
pragma solidity ^0.5.0;


/// @title Interface of the upgradeable master contract (defines notice period duration and allows finish upgrade during preparation of it)
/// @author Matter Labs
interface UpgradeableMaster {

    /// @notice Notice period before activation preparation status of upgrade mode
    function getNoticePeriod() external returns (uint);

    /// @notice Notifies contract that notice period started
    function upgradeNoticePeriodStarted() external;

    /// @notice Notifies contract that upgrade preparation status is activated
    function upgradePreparationStarted() external;

    /// @notice Notifies contract that upgrade canceled
    function upgradeCanceled() external;

    /// @notice Notifies contract that upgrade finishes
    function upgradeFinishes() external;

    /// @notice Checks that contract is ready for upgrade
    /// @return bool flag indicating that contract is ready for upgrade
    function isReadyForUpgrade() external returns (bool);

}

File 13 of 18 : IERC20.sol
pragma solidity ^0.5.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see {ERC20Detailed}.
 */
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 14 of 18 : Governance.sol
pragma solidity ^0.5.0;

import "./Config.sol";


/// @title Governance Contract
/// @author Matter Labs
contract Governance is Config {

    /// @notice Token added to Franklin net
    event NewToken(
        address indexed token,
        uint16 indexed tokenId
    );

    /// @notice Governor changed
    event NewGovernor(
        address newGovernor
    );

    /// @notice Validator's status changed
    event ValidatorStatusUpdate(
        address indexed validatorAddress,
        bool isActive
    );

    /// @notice Address which will exercise governance over the network i.e. add tokens, change validator set, conduct upgrades
    address public networkGovernor;

    /// @notice Total number of ERC20 tokens registered in the network (excluding ETH, which is hardcoded as tokenId = 0)
    uint16 public totalTokens;

    /// @notice List of registered tokens by tokenId
    mapping(uint16 => address) public tokenAddresses;

    /// @notice List of registered tokens by address
    mapping(address => uint16) public tokenIds;

    /// @notice List of permitted validators
    mapping(address => bool) public validators;

    constructor() public {}

    /// @notice Governance contract initialization. Can be external because Proxy contract intercepts illegal calls of this function.
    /// @param initializationParameters Encoded representation of initialization parameters:
    ///     _networkGovernor The address of network governor
    function initialize(bytes calldata initializationParameters) external {
        address _networkGovernor = abi.decode(initializationParameters, (address));

        networkGovernor = _networkGovernor;
    }

    /// @notice Governance contract upgrade. Can be external because Proxy contract intercepts illegal calls of this function.
    /// @param upgradeParameters Encoded representation of upgrade parameters
    function upgrade(bytes calldata upgradeParameters) external {}

    /// @notice Change current governor
    /// @param _newGovernor Address of the new governor
    function changeGovernor(address _newGovernor) external {
        requireGovernor(msg.sender);
        if (networkGovernor != _newGovernor) {
            networkGovernor = _newGovernor;
            emit NewGovernor(_newGovernor);
        }
    }

    /// @notice Add token to the list of networks tokens
    /// @param _token Token address
    function addToken(address _token) external {
        requireGovernor(msg.sender);
        require(tokenIds[_token] == 0, "gan11"); // token exists
        require(totalTokens < MAX_AMOUNT_OF_REGISTERED_TOKENS, "gan12"); // no free identifiers for tokens

        totalTokens++;
        uint16 newTokenId = totalTokens; // it is not `totalTokens - 1` because tokenId = 0 is reserved for eth

        tokenAddresses[newTokenId] = _token;
        tokenIds[_token] = newTokenId;
        emit NewToken(_token, newTokenId);
    }

    /// @notice Change validator status (active or not active)
    /// @param _validator Validator address
    /// @param _active Active flag
    function setValidator(address _validator, bool _active) external {
        requireGovernor(msg.sender);
        if (validators[_validator] != _active) {
            validators[_validator] = _active;
            emit ValidatorStatusUpdate(_validator, _active);
        }
    }

    /// @notice Check if specified address is is governor
    /// @param _address Address to check
    function requireGovernor(address _address) public view {
        require(_address == networkGovernor, "grr11"); // only by governor
    }

    /// @notice Checks if validator is active
    /// @param _address Validator address
    function requireActiveValidator(address _address) external view {
        require(validators[_address], "grr21"); // validator is not active
    }

    /// @notice Validate token id (must be less than or equal to total tokens amount)
    /// @param _tokenId Token id
    /// @return bool flag that indicates if token id is less than or equal to total tokens amount
    function isValidTokenId(uint16 _tokenId) external view returns (bool) {
        return _tokenId <= totalTokens;
    }

    /// @notice Validate token address
    /// @param _tokenAddr Token address
    /// @return tokens id
    function validateTokenAddress(address _tokenAddr) external view returns (uint16) {
        uint16 tokenId = tokenIds[_tokenAddr];
        require(tokenId != 0, "gvs11"); // 0 is not a valid token
        return tokenId;
    }

}

File 15 of 18 : Verifier.sol
pragma solidity ^0.5.0;

import "./KeysWithPlonkVerifier.sol";

// Hardcoded constants to avoid accessing store
contract Verifier is KeysWithPlonkVerifier {

    bool constant DUMMY_VERIFIER = false;

    function initialize(bytes calldata) external {
    }

    /// @notice Verifier contract upgrade. Can be external because Proxy contract intercepts illegal calls of this function.
    /// @param upgradeParameters Encoded representation of upgrade parameters
    function upgrade(bytes calldata upgradeParameters) external {}

    function isBlockSizeSupported(uint32 _size) public pure returns (bool) {
        if (DUMMY_VERIFIER) {
            return true;
        } else {
            return isBlockSizeSupportedInternal(_size);
        }
    }

    function verifyBlockProof(
        uint256[] calldata _proof,
        bytes32 _commitment,
        uint32 _chunks
    ) external view returns (bool) {
        if (DUMMY_VERIFIER) {
            uint oldGasValue = gasleft();
            uint tmp;
            while (gasleft() + 470000 > oldGasValue) {
                tmp += 1;
            }
            return true;
        }
        uint256[] memory inputs = new uint256[](1);
        uint256 mask = (~uint256(0)) >> 3;
        inputs[0] = uint256(_commitment) & mask;
        Proof memory proof = deserialize_proof(inputs, _proof);
        VerificationKey memory vk = getVkBlock(_chunks);
        require(vk.num_inputs == inputs.length);
        return verify(proof, vk);
    }

    function verifyExitProof(
        bytes32 _rootHash,
        uint32 _accountId,
        address _owner,
        uint16 _tokenId,
        uint128 _amount,
        uint256[] calldata _proof
    ) external view returns (bool) {
        bytes32 commitment = sha256(abi.encodePacked(_rootHash, _accountId, _owner, _tokenId, _amount));

        uint256[] memory inputs = new uint256[](1);
        uint256 mask = (~uint256(0)) >> 3;
        inputs[0] = uint256(commitment) & mask;
        Proof memory proof = deserialize_proof(inputs, _proof);
        VerificationKey memory vk = getVkExit();
        require(vk.num_inputs == inputs.length);
        return verify(proof, vk);
    }
}

File 16 of 18 : Upgradeable.sol
pragma solidity ^0.5.0;


/// @title Interface of the upgradeable contract
/// @author Matter Labs
interface Upgradeable {

    /// @notice Upgrades target of upgradeable contract
    /// @param newTarget New target
    /// @param newTargetInitializationParameters New target initialization parameters
    function upgradeTarget(address newTarget, bytes calldata newTargetInitializationParameters) external;

}

File 17 of 18 : KeysWithPlonkVerifier.sol
pragma solidity >=0.5.0 <0.7.0;

import "./PlonkCore.sol";

// Hardcoded constants to avoid accessing store
contract KeysWithPlonkVerifier is VerifierWithDeserialize {

    function isBlockSizeSupportedInternal(uint32 _size) internal pure returns (bool) {
        if (_size == uint32(6)) { return true; }
        else if (_size == uint32(30)) { return true; }
        else if (_size == uint32(74)) { return true; }
        else if (_size == uint32(150)) { return true; }
        else if (_size == uint32(334)) { return true; }
        else if (_size == uint32(678)) { return true; }
        else { return false; }
    }

    function getVkBlock(uint32 _chunks) internal pure returns (VerificationKey memory vk) {
        if (_chunks == uint32(6)) { return getVkBlock6(); }
        else if (_chunks == uint32(30)) { return getVkBlock30(); }
        else if (_chunks == uint32(74)) { return getVkBlock74(); }
        else if (_chunks == uint32(150)) { return getVkBlock150(); }
        else if (_chunks == uint32(334)) { return getVkBlock334(); }
        else if (_chunks == uint32(678)) { return getVkBlock678(); }
    }

    
    function getVkBlock6() internal pure returns(VerificationKey memory vk) {
        vk.domain_size = 2097152;
        vk.num_inputs = 1;
        vk.omega = PairingsBn254.new_fr(0x032750f8f3c2493d0828c7285d0258e1bdcaa463f4442a52747b5c96639659bb);
        vk.selector_commitments[0] = PairingsBn254.new_g1(
            0x0af568a35305efe9043e30a66e5dbf46219e16a04c7681e0291759114257a9a4,
            0x2f35e4f3c521dcd57b7f7cc1548df2a4877eda3d6bf6e47830b7b4c5c78247fa
        );
        vk.selector_commitments[1] = PairingsBn254.new_g1(
            0x15facf3c62fdc8eb795512905e6756fbdab12f583e92f847fe04ebed1de2b0d9,
            0x145ba3f0cd63989a960af1652ace370d8ebae9ccf8462780216625d812100623
        );
        vk.selector_commitments[2] = PairingsBn254.new_g1(
            0x16d73cc25f2f549e265a5cc871d5350a340e53bfab24118d30d6dd3276b9edf5,
            0x1eaf73c1e29c3c3a1702e2375bbee02458c04ae316a603c9509ac9f041bdf67e
        );
        vk.selector_commitments[3] = PairingsBn254.new_g1(
            0x1f652d9f3fb289cfaff303e35b53e4a1915f2a4f631115e572cfb7dd7e72c9a8,
            0x165827a3b413c30dd0e22f10b58e7e64774325e5a213821b953b20d26374b1b1
        );
        vk.selector_commitments[4] = PairingsBn254.new_g1(
            0x0bb9329eaae8b9979ccf377d312778494b03642e3a1f629f1c4a78dcc759b348,
            0x213616224ae180ef4c0010301e037e281689f84d5a9121191957eff36770d526
        );
        vk.selector_commitments[5] = PairingsBn254.new_g1(
            0x0b478d136e36e67ef049746e8b452afa88c13547cdc341eef713fa7e42f6dcd6,
            0x24ef9c90e617fcf3adf998dff4c3238f8fe564ba2da8d15ac3c673d0b16d9bd6
        );

        // we only have access to value of the d(x) witness polynomial on the next
        // trace step, so we only need one element here and deal with it in other places
        // by having this in mind
        vk.next_step_selector_commitments[0] = PairingsBn254.new_g1(
            0x09a2c2eeb91944b93013a95e6a63a780e881f101249375d9732ba74c6e54186b,
            0x2599f0b0d736bfb3f66cdff99c9f5557f7b82a1fa4029d0d5770d1d194019533
        );

         vk.permutation_commitments[0] = PairingsBn254.new_g1(
            0x199f1e85e793132f1ce19e86967efb1ed606e68b7af0478532fa182163fefa6e,
            0x21698d34ed8a715d0086ecab6c1b7fcf4d9a1d7995db29d517031084f2764f95
        );
        vk.permutation_commitments[1] = PairingsBn254.new_g1(
            0x2389c84e9eaf7f61ad69dd4d19299530c4027f083c6976b5e7cc7f3b7cb57b55,
            0x18ee0d9df2d37dda5e85a5764088e89ee8ce32eb7ff45173f0fd102c522d41e1
        );
        vk.permutation_commitments[2] = PairingsBn254.new_g1(
            0x0f922b9348896b282f12aff0610e39dfa1b6066aaeb5a04f0a5a29d2bb0096c8,
            0x1e24a9abbf50778a8d2fd51b37a8eae7836cde2c559740d6ec322c8584274442
        );
        vk.permutation_commitments[3] = PairingsBn254.new_g1(
            0x2abf5027b8f2a88015873d2b3f97ae97da5f771e800acf89098c5d2228086cf1,
            0x1e245aa8ee95af522f204a3e62b82cc62361cf604efac1dd27d49252d1d360c4
        );

        vk.permutation_non_residues[0] = PairingsBn254.new_fr(
            0x0000000000000000000000000000000000000000000000000000000000000005
        );
        vk.permutation_non_residues[1] = PairingsBn254.new_fr(
            0x0000000000000000000000000000000000000000000000000000000000000007
        );
        vk.permutation_non_residues[2] = PairingsBn254.new_fr(
            0x000000000000000000000000000000000000000000000000000000000000000a
        );

        vk.g2_x = PairingsBn254.new_g2(
            [0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1,
             0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0],
            [0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4,
             0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55]
        );
    }
    
    function getVkBlock30() internal pure returns(VerificationKey memory vk) {
        vk.domain_size = 4194304;
        vk.num_inputs = 1;
        vk.omega = PairingsBn254.new_fr(0x18c95f1ae6514e11a1b30fd7923947c5ffcec5347f16e91b4dd654168326bede);
        vk.selector_commitments[0] = PairingsBn254.new_g1(
            0x0dabeb092c842c9877aab11b2242490061cef35c2631e3c383f1ce13c386aaf3,
            0x0d34932557f52b84c523dc2474e79eb343f84718d7f20e519a85d10bdb4611eb
        );
        vk.selector_commitments[1] = PairingsBn254.new_g1(
            0x1c0ea096536ef84a9ee46457b44d4bf9f4b147e9cfd9157f9291d50e59de2512,
            0x0b84d8085ef5989f16bc03822d3c3232c2d5df22a0d0a3ac80e6338094909b3b
        );
        vk.selector_commitments[2] = PairingsBn254.new_g1(
            0x2f6dd701052fc5e95812f5c0da0bf96d5120d7dd5a60bfcc7705aeb212593949,
            0x1275cd37c2e0b36830d7a0a3000668064b28c3ff4071614d5992e7a9720fe5a8
        );
        vk.selector_commitments[3] = PairingsBn254.new_g1(
            0x1466533cc8c309aca62e5571d170e056b570358ba73bdf921d914a96deef85b1,
            0x2f1d1375359dcd5c881b144b64698f15e8227d3f4cb9507f463eecb14173942d
        );
        vk.selector_commitments[4] = PairingsBn254.new_g1(
            0x0d23903b411253d6e1ea85334f072b75da815db364e96b600003f3f95e3af56c,
            0x1130d37d579a1c54aab11ac4e7b7e3fb12e2632682c41f40042cf5e0de646e32
        );
        vk.selector_commitments[5] = PairingsBn254.new_g1(
            0x130a475c0d12c09535079832afded260636cea2d3acf638b3645f6f18b1defd8,
            0x0bf9f1bc4fe3d87628e43c5f87634164bb4a7baedeb578e8b036e72bc5da9038
        );

        // we only have access to value of the d(x) witness polynomial on the next
        // trace step, so we only need one element here and deal with it in other places
        // by having this in mind
        vk.next_step_selector_commitments[0] = PairingsBn254.new_g1(
            0x153b616b629aa926262a08d03f3626b2623b1a2aad95dba19d80878fe4d2701a,
            0x0ce4c47b8656ea235b974df7b7ec7e3cb62a952704ebcb084ecf521da22c1549
        );

         vk.permutation_commitments[0] = PairingsBn254.new_g1(
            0x0ec6a763e129c400eeaa8bf1d66498ff92286d1bed142f92c932f5ef8cf8c5e3,
            0x23a13322172b50c6f624e9c7c924260e2894f84ab928dbb718d0c391b0d43abf
        );
        vk.permutation_commitments[1] = PairingsBn254.new_g1(
            0x246a73716676323f05a5d6137eb98c7f6c8d6ca5f9b63c397271ce820175599e,
            0x08ac8dc778bb4998b6d8440fb25463d7810986439aae3f3ddc6e24b0e8a8da2f
        );
        vk.permutation_commitments[2] = PairingsBn254.new_g1(
            0x1174638606b9dc726499db27c34f317db4bd0475678827972fa0da4fab6da1f7,
            0x17ceb003ecee92a35fa0ab0989de9d6aafedd821c6d89a0dcded8b096f5b45cb
        );
        vk.permutation_commitments[3] = PairingsBn254.new_g1(
            0x1e7f3863aacbcbb3a43318c621b0abcae89a145bc950dd161fb793fb425ae8cb,
            0x2980f2f25fd142c92a55560529f7080e7d55ed8c3cfbb1cd421186c3c3f799e7
        );

        vk.permutation_non_residues[0] = PairingsBn254.new_fr(
            0x0000000000000000000000000000000000000000000000000000000000000005
        );
        vk.permutation_non_residues[1] = PairingsBn254.new_fr(
            0x0000000000000000000000000000000000000000000000000000000000000007
        );
        vk.permutation_non_residues[2] = PairingsBn254.new_fr(
            0x000000000000000000000000000000000000000000000000000000000000000a
        );

        vk.g2_x = PairingsBn254.new_g2(
            [0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1,
             0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0],
            [0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4,
             0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55]
        );
    }
    
    function getVkBlock74() internal pure returns(VerificationKey memory vk) {
        vk.domain_size = 8388608;
        vk.num_inputs = 1;
        vk.omega = PairingsBn254.new_fr(0x1283ba6f4b7b1a76ba2008fe823128bea4adb9269cbfd7c41c223be65bc60863);
        vk.selector_commitments[0] = PairingsBn254.new_g1(
            0x1021fcff6a718826f54ecb1ed30b237b453a8d16a68c5d473ddd1a98ce4d3ffe,
            0x1ff632b0f6b06f344c7790260938e21fefeda3c4428e4f3ffce28301de847934
        );
        vk.selector_commitments[1] = PairingsBn254.new_g1(
            0x04d1cc2c538b6bc75450f955d21550a948cb38b8aec7c9775795a96aabdb412e,
            0x159a35771ccd356ab60f186c9efc8767df370c28e2231ec98e6a674bc95f7612
        );
        vk.selector_commitments[2] = PairingsBn254.new_g1(
            0x23eeccd095551b0357be6eea8bd9ecabd4a446cb7993c545c7193a2d5bb8657f,
            0x00827f6f318c00d7dd2e4a7f3bd94810af906e62eb6844bd110e17ee1ec16f8d
        );
        vk.selector_commitments[3] = PairingsBn254.new_g1(
            0x1d3bdf4f220278fc7fc8be20ced77647dc38be36f8d9b84e61ddf46e1d593d14,
            0x2396a7d5704823939ead4a2bfc6510a7f6470e2a1f447072c9534d62372873f3
        );
        vk.selector_commitments[4] = PairingsBn254.new_g1(
            0x040be274be43c2d83ae606ec3636fec5c4e7d8c99becf7d33b52adbd0d724b8a,
            0x0dec58400efeed3381f71ad1e83582c139a8b728fa9e25ca61e92ef46a09e025
        );
        vk.selector_commitments[5] = PairingsBn254.new_g1(
            0x0adf559b5270e352f9ab28f549922da636aef8bdba57d67f85434dc56e78c744,
            0x2e70f0eda4beb23c457fb274b0aa553b82a94f07c6015ee589481cfa2b3496b1
        );

        // we only have access to value of the d(x) witness polynomial on the next
        // trace step, so we only need one element here and deal with it in other places
        // by having this in mind
        vk.next_step_selector_commitments[0] = PairingsBn254.new_g1(
            0x2a8d0d37052e369ff5f5f03b3263deae82cbb555557050c6332488ec2be812ae,
            0x2fa789399c26b85d1cf48961bbc44dca2eaf75016720f9e2ba78c1133fadf0bb
        );

         vk.permutation_commitments[0] = PairingsBn254.new_g1(
            0x238b4d00fa2d36e7ab351a32f91a2125622a5bb0ae9af7fdbd9b60cf000e6e91,
            0x08ff4499abe98d10e1b6b2fc77fa32333dd5f41cf726cdc71503e0eb8595f4de
        );
        vk.permutation_commitments[1] = PairingsBn254.new_g1(
            0x0cd7e807d8ed7749d99f27e58c871f6feb2036ed6cfcc5a411dc38c7fd307be6,
            0x292f00dd8d21c1ce8124bd9f82ab249dbbdb6f45c3696481ae38ee77b22f849b
        );
        vk.permutation_commitments[2] = PairingsBn254.new_g1(
            0x2809b958f09357f3a419ce2245cc5b38e8faecc1ec767d5c868349e588fe5d44,
            0x2624d43f0e037f39b0a6fb9f5ae4499849d54c54c0dc3ac8f9c292ac8551e6bc
        );
        vk.permutation_commitments[3] = PairingsBn254.new_g1(
            0x276a858b024e5d82607fac4ee82e97719b25fae9853e2c394236ebc15bdc07ed,
            0x11de57c72d139056394203bcac52a132a9d2a012edba72949518e3b986694a8e
        );

        vk.permutation_non_residues[0] = PairingsBn254.new_fr(
            0x0000000000000000000000000000000000000000000000000000000000000005
        );
        vk.permutation_non_residues[1] = PairingsBn254.new_fr(
            0x0000000000000000000000000000000000000000000000000000000000000007
        );
        vk.permutation_non_residues[2] = PairingsBn254.new_fr(
            0x000000000000000000000000000000000000000000000000000000000000000a
        );

        vk.g2_x = PairingsBn254.new_g2(
            [0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1,
             0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0],
            [0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4,
             0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55]
        );
    }
    
    function getVkBlock150() internal pure returns(VerificationKey memory vk) {
        vk.domain_size = 16777216;
        vk.num_inputs = 1;
        vk.omega = PairingsBn254.new_fr(0x1951441010b2b95a6e47a6075066a50a036f5ba978c050f2821df86636c0facb);
        vk.selector_commitments[0] = PairingsBn254.new_g1(
            0x2b980886069d87943728e229dd4c9e983a0ce1a319b5ab964fced0bc02e2cf96,
            0x176f6a4a15b95fa93edb949de5510ee84c50040e05c5ee1e2b928ec013d2c0da
        );
        vk.selector_commitments[1] = PairingsBn254.new_g1(
            0x251f54507ddd45d703e5a81b666217e0c3e9231fdbfd382188dafc03268931ce,
            0x27d916677565037db4532f2846e10f42cd20499ec54989c42a996c86429786c0
        );
        vk.selector_commitments[2] = PairingsBn254.new_g1(
            0x00e1d3e897a5f0fea282b120762ed656204c7b05c6716f92047c88991a6776f9,
            0x1c83d49caa16f271c2f7250bbc4bba028d4dfd65ed880bc294005253ea7c846a
        );
        vk.selector_commitments[3] = PairingsBn254.new_g1(
            0x29692360bdfa1c1fde3828cf2b903f6ec3853a1073368db46ab444edf5989cc4,
            0x1fb7acc4736be1008144d100c5d447cc55d36c988e6ca974afb2d6039ad19c71
        );
        vk.selector_commitments[4] = PairingsBn254.new_g1(
            0x2324d61f18207e8135bd2f290e4acd36fc9a977411da6c7e404702d120a4aa4a,
            0x12f7ce81186f570986229da30c136c85473d552fe1c214a7eb3b2d305b7b2ae5
        );
        vk.selector_commitments[5] = PairingsBn254.new_g1(
            0x1d1d3df125d46c06153985ada847816cdcafbf7c8f72d99ae779680bed23e935,
            0x1685aa96e1c7d4be8e4993d2b50e8ea76fca9166c223749492f31ebf22915853
        );

        // we only have access to value of the d(x) witness polynomial on the next
        // trace step, so we only need one element here and deal with it in other places
        // by having this in mind
        vk.next_step_selector_commitments[0] = PairingsBn254.new_g1(
            0x234111b09c5d38dd313eb1ef80a12cbbdc20bc6066310cd5109f93a4545852da,
            0x02441d140d85197884cc9cce20f80670cd94daf51153e61d99381ad85f9d3421
        );

         vk.permutation_commitments[0] = PairingsBn254.new_g1(
            0x02f194881a81ef07ab23dd4552157fb3b83a67df10ffd6916c6ac9f8f5a088ba,
            0x0cfb413a65eb6880ffb16277e56b6e1f2474bbb5e2de0a71f06a94118f54bdab
        );
        vk.permutation_commitments[1] = PairingsBn254.new_g1(
            0x1292198bff3ce83fc2410250e998a49ae2d15080555ab268e2714e7cd7e68078,
            0x206789f5461397abcaed25062e0881928a9ad05d02f031944dc3a3c3b0955eec
        );
        vk.permutation_commitments[2] = PairingsBn254.new_g1(
            0x2204220f2bfff0ff22d77c9c66c3fdc00b431e92e930dc65ba3a6b91a3350a98,
            0x0e46f948f7b703fd7c100575ed47db8d559b93fba62cefaa6f65458249b1e52c
        );
        vk.permutation_commitments[3] = PairingsBn254.new_g1(
            0x2b627b695c64b566e4f4b8f0be454d1de004cce7fa19e6f7fdcb2de2397e67d6,
            0x264b1bb8361351d44e34c89162185f489f8e823c649dbbd1f65a1d10e3e196af
        );

        vk.permutation_non_residues[0] = PairingsBn254.new_fr(
            0x0000000000000000000000000000000000000000000000000000000000000005
        );
        vk.permutation_non_residues[1] = PairingsBn254.new_fr(
            0x0000000000000000000000000000000000000000000000000000000000000007
        );
        vk.permutation_non_residues[2] = PairingsBn254.new_fr(
            0x000000000000000000000000000000000000000000000000000000000000000a
        );

        vk.g2_x = PairingsBn254.new_g2(
            [0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1,
             0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0],
            [0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4,
             0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55]
        );
    }
    
    function getVkBlock334() internal pure returns(VerificationKey memory vk) {
        vk.domain_size = 33554432;
        vk.num_inputs = 1;
        vk.omega = PairingsBn254.new_fr(0x0d94d63997367c97a8ed16c17adaae39262b9af83acb9e003f94c217303dd160);
        vk.selector_commitments[0] = PairingsBn254.new_g1(
            0x29d9574cd4b98e563db05a14d1ecf9dd7b8e3cd5d901e140d04181c9f53db97e,
            0x2ee352008474de4960ca513838e407cd27cbd5c5a8cffd67f67d8a49d4861279
        );
        vk.selector_commitments[1] = PairingsBn254.new_g1(
            0x1b1dffc6fde1dd941557412626ddebedd2bcb6f9f8cc9c19bc1f1cca2f9635c7,
            0x0f2a6292bb6dacecaa6cb3c71240504f417d8e45f8b345707486afb658fd9d4a
        );
        vk.selector_commitments[2] = PairingsBn254.new_g1(
            0x0210cb0963ab20ff896d704feb4aadf889ebfe3c3fe1555744ec562fc8bc24b6,
            0x156b1a7294328baadcb080d01237d031acf66f63c2d91659d16e1b80cbf3a890
        );
        vk.selector_commitments[3] = PairingsBn254.new_g1(
            0x1c3228a3e68fe3ade8c48d516595407359570842d2ab66127b77dc076488be5b,
            0x2497ee062b253369cdf12f373e8bd7c9bde6942074b7fea52d1751e9b0de7a24
        );
        vk.selector_commitments[4] = PairingsBn254.new_g1(
            0x291088d66f3e2f19861c488ab28c619a8fb0ead716cbf1182be4c857a738e37b,
            0x010eaf9bab2047a22c90b03c95a8d4f4f45ed0f3410777fc572ca249398017e5
        );
        vk.selector_commitments[5] = PairingsBn254.new_g1(
            0x18c2e15408ba31f91aec85db8edf934f6ad294b1ef641109f026090c7ce788af,
            0x215a339e53528e9c9247987610f93f0854de562fd78ba34aebd8e0e82d5a45a2
        );

        // we only have access to value of the d(x) witness polynomial on the next
        // trace step, so we only need one element here and deal with it in other places
        // by having this in mind
        vk.next_step_selector_commitments[0] = PairingsBn254.new_g1(
            0x14a4455b1da8964b29fe75d6b19283f00fd58d3db10afce417cca2a69cd993ae,
            0x12d468900ccdc72f0f2e7f41b9a29329c46dd8ba3b0344bf453e2d172a26bc9c
        );

         vk.permutation_commitments[0] = PairingsBn254.new_g1(
            0x04a3e03c4f3e964d756e69a0de2d331c8679cfbdce806849931efe547d493b4b,
            0x20871a71fdb6f7e12839bc53ff8b0559d30db42e523d1754121b2ee8f967361b
        );
        vk.permutation_commitments[1] = PairingsBn254.new_g1(
            0x1e8f25a49a753a938da78263003a4dc0e68492940abd9b6294da149c7c927216,
            0x0bcd44d08ffc48a289e87b0604c7a16b5e119e3c47b293c3c6c29762a4a5d326
        );
        vk.permutation_commitments[2] = PairingsBn254.new_g1(
            0x2f3b23257c3437e10631f5dc5da61a622f17dd1516294e013fe484a3adf42462,
            0x0b0a21cb5384dc0669f58d54671732385cf96065680255d46861f9a7456267f5
        );
        vk.permutation_commitments[3] = PairingsBn254.new_g1(
            0x01ec6c4541fb1b4342d219856f1805bf7b94de582b261b096ea2b11b62205633,
            0x05a9b67927c90079c45907f9ba67105b47b15dcf480b3bf3514582dc18d357bf
        );

        vk.permutation_non_residues[0] = PairingsBn254.new_fr(
            0x0000000000000000000000000000000000000000000000000000000000000005
        );
        vk.permutation_non_residues[1] = PairingsBn254.new_fr(
            0x0000000000000000000000000000000000000000000000000000000000000007
        );
        vk.permutation_non_residues[2] = PairingsBn254.new_fr(
            0x000000000000000000000000000000000000000000000000000000000000000a
        );

        vk.g2_x = PairingsBn254.new_g2(
            [0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1,
             0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0],
            [0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4,
             0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55]
        );
    }
    
    function getVkBlock678() internal pure returns(VerificationKey memory vk) {
        vk.domain_size = 67108864;
        vk.num_inputs = 1;
        vk.omega = PairingsBn254.new_fr(0x1dba8b5bdd64ef6ce29a9039aca3c0e524395c43b9227b96c75090cc6cc7ec97);
        vk.selector_commitments[0] = PairingsBn254.new_g1(
            0x10fac38e585fc150fa6f7470ff88f978bd906bd5454fd067381816c296f89870,
            0x1b5424e03353a60155d057d5b0303c2b0d78410cd2f7b0abeb2928b76f808816
        );
        vk.selector_commitments[1] = PairingsBn254.new_g1(
            0x0ff633c9b1ed5af3bd5882da5354dfcccd698066d4050ff0c7fd20aa9cd01218,
            0x2ab1ee7db81f3e504032e3e36e297c38d15e55171a49cee01ff42d1c954d63a5
        );
        vk.selector_commitments[2] = PairingsBn254.new_g1(
            0x03aafad8e4a648f6339fc48f229b8672c64dd64e7866263fa8c4e0e716961dea,
            0x03bc02bc248d3d3aa917b9eec4a335dc7b1c21ae694c6166911b7246fc95a539
        );
        vk.selector_commitments[3] = PairingsBn254.new_g1(
            0x303d788f44e34b61d5671389e8e4a7bfa4f13c02b8c2d345d0eba623e5a6f17f,
            0x00a6d7d77556ccff73f1ce9fd0ddce9eb8940731dbdca250fad108ffbccb744d
        );
        vk.selector_commitments[4] = PairingsBn254.new_g1(
            0x03cacd9bc51ff522d6cc654b17483cf5f044a15eec12f1837fcb9d7f717d5a67,
            0x0de3f25d9a6865cd7cc72e529edd802a0cee06d1b45830a294bd6a2240d4bdd0
        );
        vk.selector_commitments[5] = PairingsBn254.new_g1(
            0x02c54c3ac215172724f0b8138e212e793b28af7ae06b5b53c2f56b52cf32fff6,
            0x25093d56e5e5dfad1b1c75b94250fcb4fc430ba214bba40989855d142dcf29b2
        );

        // we only have access to value of the d(x) witness polynomial on the next
        // trace step, so we only need one element here and deal with it in other places
        // by having this in mind
        vk.next_step_selector_commitments[0] = PairingsBn254.new_g1(
            0x222cfccd491605b4b9e15a18b8b0d841c8c5104ed3f96a97d546b0b33cdc67db,
            0x0f4ea5620594b707d6d37c4292df6889bd835574abec790b97fd0af88b1d1edd
        );

         vk.permutation_commitments[0] = PairingsBn254.new_g1(
            0x230f568480422793e27ba60859477b363d50ae18c48ace23d6cfcf04abe29dd6,
            0x1c6c663735ff13ab1332598f552fc3d01410b18cfa9c6a7bb88df553c79a38b0
        );
        vk.permutation_commitments[1] = PairingsBn254.new_g1(
            0x0955c07d90bf6d48aa1aec00c060f9aec57f10fa76285684a16cd023192af01c,
            0x290ff005de85504f475b596b72bcf1623b71b30534cd360576626d6737f1b763
        );
        vk.permutation_commitments[2] = PairingsBn254.new_g1(
            0x0cac2104abcde1bf215788c18be6a5c2d73da416f8c5b6e0a2a2222a24deb32f,
            0x02dde54e719bc243cda9febc88187582a0983ff1a85d6f888bfe13e4567d9aa5
        );
        vk.permutation_commitments[3] = PairingsBn254.new_g1(
            0x27fce095aa4c68adbd01f5fd8e64864f6c1625cc577e13a2b80051947b2e8ff6,
            0x2583c01600426f9b3873ffef651187c82c0e55a6e5de762355a458fc388f4585
        );

        vk.permutation_non_residues[0] = PairingsBn254.new_fr(
            0x0000000000000000000000000000000000000000000000000000000000000005
        );
        vk.permutation_non_residues[1] = PairingsBn254.new_fr(
            0x0000000000000000000000000000000000000000000000000000000000000007
        );
        vk.permutation_non_residues[2] = PairingsBn254.new_fr(
            0x000000000000000000000000000000000000000000000000000000000000000a
        );

        vk.g2_x = PairingsBn254.new_g2(
            [0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1,
             0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0],
            [0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4,
             0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55]
        );
    }
    
    function getVkExit() internal pure returns(VerificationKey memory vk) {
        vk.domain_size = 262144;
        vk.num_inputs = 1;
        vk.omega = PairingsBn254.new_fr(0x0f60c8fe0414cb9379b2d39267945f6bd60d06a05216231b26a9fcf88ddbfebe);
        vk.selector_commitments[0] = PairingsBn254.new_g1(
            0x117ebe939b7336d17b69b05d5530e30326af39da45a989b078bb3d607707bf3e,
            0x18b16095a1c814fe2980170ff34490f1fd454e874caa87df2f739fb9c8d2e902
        );
        vk.selector_commitments[1] = PairingsBn254.new_g1(
            0x05ac70a10fc569cc8358bfb708c184446966c6b6a3e0d7c25183ded97f9e7933,
            0x0f6152282854e153588d45e784d216a423a624522a687741492ee0b807348e71
        );
        vk.selector_commitments[2] = PairingsBn254.new_g1(
            0x03cfa9d8f9b40e565435bee3c5b0e855c8612c5a89623557cc30f4588617d7bd,
            0x2292bb95c2cc2da55833b403a387e250a9575e32e4ce7d6caa954f12e6ce592a
        );
        vk.selector_commitments[3] = PairingsBn254.new_g1(
            0x04d04f495c69127b6cc6ecbfd23f77f178e7f4e2d2de3eab3e583a4997744cd9,
            0x09dcf5b3db29af5c5eef2759da26d3b6959cb8d80ada9f9b086f7cc39246ad2b
        );
        vk.selector_commitments[4] = PairingsBn254.new_g1(
            0x01ebab991522d407cfd4e8a1740b64617f0dfca50479bba2707c2ec4159039fc,
            0x2c8bd00a44c6120bbf8e57877013f2b5ee36b53eef4ea3b6748fd03568005946
        );
        vk.selector_commitments[5] = PairingsBn254.new_g1(
            0x07a7124d1fece66bd5428fcce25c22a4a9d5ceaa1e632565d9a062c39f005b5e,
            0x2044ae5306f0e114c48142b9b97001d94e3f2280db1b01a1e47ac1cf6bd5f99e
        );

        // we only have access to value of the d(x) witness polynomial on the next
        // trace step, so we only need one element here and deal with it in other places
        // by having this in mind
        vk.next_step_selector_commitments[0] = PairingsBn254.new_g1(
            0x1dd1549a639f052c4fbc95b7b7a40acf39928cad715580ba2b38baa116dacd9c,
            0x0f8e712990da1ce5195faaf80185ef0d5e430fdec9045a20af758cc8ecdac2e5
        );

         vk.permutation_commitments[0] = PairingsBn254.new_g1(
            0x0026b64066e39a22739be37fed73308ace0a5f38a0e2292dcc2309c818e8c89c,
            0x285101acca358974c2c7c9a8a3936e08fbd86779b877b416d9480c91518cb35b
        );
        vk.permutation_commitments[1] = PairingsBn254.new_g1(
            0x2159265ac6fcd4d0257673c3a85c17f4cf3ea13a3c9fb51e404037b13778d56f,
            0x25bf73e568ba3406ace2137195bb2176d9de87a48ae42520281aaef2ac2ef937
        );
        vk.permutation_commitments[2] = PairingsBn254.new_g1(
            0x068f29af99fc8bbf8c00659d34b6d34e4757af6edc10fc7647476cbd0ea9be63,
            0x2ef759b20cabf3da83d7f578d9e11ed60f7015440e77359db94475ddb303144d
        );
        vk.permutation_commitments[3] = PairingsBn254.new_g1(
            0x22793db6e98b9e37a1c5d78fcec67a2d8c527d34c5e9c8c1ff15007d30a4c133,
            0x1b683d60fd0750b3a45cdee5cbc4057204a02bd428e8071c92fe6694a40a5c1f
        );

        vk.permutation_non_residues[0] = PairingsBn254.new_fr(
            0x0000000000000000000000000000000000000000000000000000000000000005
        );
        vk.permutation_non_residues[1] = PairingsBn254.new_fr(
            0x0000000000000000000000000000000000000000000000000000000000000007
        );
        vk.permutation_non_residues[2] = PairingsBn254.new_fr(
            0x000000000000000000000000000000000000000000000000000000000000000a
        );

        vk.g2_x = PairingsBn254.new_g2(
            [0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1,
             0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0],
            [0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4,
             0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55]
        );
    }
    

}

File 18 of 18 : PlonkCore.sol
pragma solidity >=0.5.0 <0.7.0;

library PairingsBn254 {
    uint256 constant q_mod = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
    uint256 constant r_mod = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
    uint256 constant bn254_b_coeff = 3;

    struct G1Point {
        uint256 X;
        uint256 Y;
    }

    struct Fr {
        uint256 value;
    }

    function new_fr(uint256 fr) internal pure returns (Fr memory) {
        require(fr < r_mod);
        return Fr({value: fr});
    }

    function copy(Fr memory self) internal pure returns (Fr memory n) {
        n.value = self.value;
    }

    function assign(Fr memory self, Fr memory other) internal pure {
        self.value = other.value;
    }

    function inverse(Fr memory fr) internal view returns (Fr memory) {
        require(fr.value != 0);
        return pow(fr, r_mod-2);
    }

    function add_assign(Fr memory self, Fr memory other) internal pure {
        self.value = addmod(self.value, other.value, r_mod);
    }

    function sub_assign(Fr memory self, Fr memory other) internal pure {
        self.value = addmod(self.value, r_mod - other.value, r_mod);
    }

    function mul_assign(Fr memory self, Fr memory other) internal pure {
        self.value = mulmod(self.value, other.value, r_mod);
    }

    function pow(Fr memory self, uint256 power) internal view returns (Fr memory) {
        uint256[6] memory input = [32, 32, 32, self.value, power, r_mod];
        uint256[1] memory result;
        bool success;
        assembly {
            success := staticcall(gas(), 0x05, input, 0xc0, result, 0x20)
        }
        require(success);
        return Fr({value: result[0]});
    }

    // Encoding of field elements is: X[0] * z + X[1]
    struct G2Point {
        uint[2] X;
        uint[2] Y;
    }

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

    function new_g1(uint256 x, uint256 y) internal pure returns (G1Point memory) {
        return G1Point(x, y);
    }

    function new_g1_checked(uint256 x, uint256 y) internal pure returns (G1Point memory) {
        if (x == 0 && y == 0) {
            // point of infinity is (0,0)
            return G1Point(x, y);
        }

        // check encoding
        require(x < q_mod);
        require(y < q_mod);
        // check on curve
        uint256 lhs = mulmod(y, y, q_mod); // y^2
        uint256 rhs = mulmod(x, x, q_mod); // x^2
        rhs = mulmod(rhs, x, q_mod); // x^3
        rhs = addmod(rhs, bn254_b_coeff, q_mod); // x^3 + b
        require(lhs == rhs);

        return G1Point(x, y);
    }

    function new_g2(uint256[2] memory x, uint256[2] memory y) internal pure returns (G2Point memory) {
        return G2Point(x, y);
    }

    function copy_g1(G1Point memory self) internal pure returns (G1Point memory result) {
        result.X = self.X;
        result.Y = self.Y;
    }

    function P2() internal pure returns (G2Point memory) {
        // for some reason ethereum expects to have c1*v + c0 form

        return G2Point(
            [0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2,
            0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed],
            [0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b,
            0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa]
        );
    }

    function negate(G1Point memory self) internal pure {
        // The prime q in the base field F_q for G1
        if (self.Y == 0) {
            require(self.X == 0);
            return;
        }

        self.Y = q_mod - self.Y;
    }

    function point_add(G1Point memory p1, G1Point memory p2)
    internal view returns (G1Point memory r)
    {
        point_add_into_dest(p1, p2, r);
        return r;
    }

    function point_add_assign(G1Point memory p1, G1Point memory p2)
    internal view
    {
        point_add_into_dest(p1, p2, p1);
    }

    function point_add_into_dest(G1Point memory p1, G1Point memory p2, G1Point memory dest)
    internal view
    {
        if (p2.X == 0 && p2.Y == 0) {
            // we add zero, nothing happens
            dest.X = p1.X;
            dest.Y = p1.Y;
            return;
        } else if (p1.X == 0 && p1.Y == 0) {
            // we add into zero, and we add non-zero point
            dest.X = p2.X;
            dest.Y = p2.Y;
            return;
        } else {
            uint256[4] memory input;

            input[0] = p1.X;
            input[1] = p1.Y;
            input[2] = p2.X;
            input[3] = p2.Y;

            bool success = false;
            assembly {
                success := staticcall(gas(), 6, input, 0x80, dest, 0x40)
            }
            require(success);
        }
    }

    function point_sub_assign(G1Point memory p1, G1Point memory p2)
    internal view
    {
        point_sub_into_dest(p1, p2, p1);
    }

    function point_sub_into_dest(G1Point memory p1, G1Point memory p2, G1Point memory dest)
    internal view
    {
        if (p2.X == 0 && p2.Y == 0) {
            // we subtracted zero, nothing happens
            dest.X = p1.X;
            dest.Y = p1.Y;
            return;
        } else if (p1.X == 0 && p1.Y == 0) {
            // we subtract from zero, and we subtract non-zero point
            dest.X = p2.X;
            dest.Y = q_mod - p2.Y;
            return;
        } else {
            uint256[4] memory input;

            input[0] = p1.X;
            input[1] = p1.Y;
            input[2] = p2.X;
            input[3] = q_mod - p2.Y;

            bool success = false;
            assembly {
                success := staticcall(gas(), 6, input, 0x80, dest, 0x40)
            }
            require(success);
        }
    }

    function point_mul(G1Point memory p, Fr memory s)
    internal view returns (G1Point memory r)
    {
        point_mul_into_dest(p, s, r);
        return r;
    }

    function point_mul_assign(G1Point memory p, Fr memory s)
    internal view
    {
        point_mul_into_dest(p, s, p);
    }

    function point_mul_into_dest(G1Point memory p, Fr memory s, G1Point memory dest)
    internal view
    {
        uint[3] memory input;
        input[0] = p.X;
        input[1] = p.Y;
        input[2] = s.value;
        bool success;
        assembly {
            success := staticcall(gas(), 7, input, 0x60, dest, 0x40)
        }
        require(success);
    }

    function pairing(G1Point[] memory p1, G2Point[] memory p2)
    internal view returns (bool)
    {
        require(p1.length == p2.length);
        uint elements = p1.length;
        uint inputSize = elements * 6;
        uint[] memory input = new uint[](inputSize);
        for (uint i = 0; i < elements; i++)
        {
            input[i * 6 + 0] = p1[i].X;
            input[i * 6 + 1] = p1[i].Y;
            input[i * 6 + 2] = p2[i].X[0];
            input[i * 6 + 3] = p2[i].X[1];
            input[i * 6 + 4] = p2[i].Y[0];
            input[i * 6 + 5] = p2[i].Y[1];
        }
        uint[1] memory out;
        bool success;
        assembly {
            success := staticcall(gas(), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
        }
        require(success);
        return out[0] != 0;
    }

    /// Convenience method for a pairing check for two pairs.
    function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2)
    internal view returns (bool)
    {
        G1Point[] memory p1 = new G1Point[](2);
        G2Point[] memory p2 = new G2Point[](2);
        p1[0] = a1;
        p1[1] = b1;
        p2[0] = a2;
        p2[1] = b2;
        return pairing(p1, p2);
    }
}

library TranscriptLibrary {
    // flip                    0xe000000000000000000000000000000000000000000000000000000000000000;
    uint256 constant FR_MASK = 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;

    uint32 constant DST_0 = 0;
    uint32 constant DST_1 = 1;
    uint32 constant DST_CHALLENGE = 2;

    struct Transcript {
        bytes32 state_0;
        bytes32 state_1;
        uint32 challenge_counter;
    }

    function new_transcript() internal pure returns (Transcript memory t) {
        t.state_0 = bytes32(0);
        t.state_1 = bytes32(0);
        t.challenge_counter = 0;
    }

    function update_with_u256(Transcript memory self, uint256 value) internal pure {
        bytes32 old_state_0 = self.state_0;
        self.state_0 = keccak256(abi.encodePacked(DST_0, old_state_0, self.state_1, value));
        self.state_1 = keccak256(abi.encodePacked(DST_1, old_state_0, self.state_1, value));
    }

    function update_with_fr(Transcript memory self, PairingsBn254.Fr memory value) internal pure {
        update_with_u256(self, value.value);
    }

    function update_with_g1(Transcript memory self, PairingsBn254.G1Point memory p) internal pure {
        update_with_u256(self, p.X);
        update_with_u256(self, p.Y);
    }

    function get_challenge(Transcript memory self) internal pure returns(PairingsBn254.Fr memory challenge) {
        bytes32 query = keccak256(abi.encodePacked(DST_CHALLENGE, self.state_0, self.state_1, self.challenge_counter));
        self.challenge_counter += 1;
        challenge = PairingsBn254.Fr({value: uint256(query) & FR_MASK});
    }
}

contract Plonk4VerifierWithAccessToDNext {
    using PairingsBn254 for PairingsBn254.G1Point;
    using PairingsBn254 for PairingsBn254.G2Point;
    using PairingsBn254 for PairingsBn254.Fr;

    using TranscriptLibrary for TranscriptLibrary.Transcript;

    uint256 constant STATE_WIDTH = 4;
    uint256 constant ACCESSIBLE_STATE_POLYS_ON_NEXT_STEP = 1;

    struct VerificationKey {
        uint256 domain_size;
        uint256 num_inputs;
        PairingsBn254.Fr omega;
        PairingsBn254.G1Point[STATE_WIDTH+2] selector_commitments; // STATE_WIDTH for witness + multiplication + constant
        PairingsBn254.G1Point[ACCESSIBLE_STATE_POLYS_ON_NEXT_STEP] next_step_selector_commitments;
        PairingsBn254.G1Point[STATE_WIDTH] permutation_commitments;
        PairingsBn254.Fr[STATE_WIDTH-1] permutation_non_residues;
        PairingsBn254.G2Point g2_x;
    }

    struct Proof {
        uint256[] input_values;
        PairingsBn254.G1Point[STATE_WIDTH] wire_commitments;
        PairingsBn254.G1Point grand_product_commitment;
        PairingsBn254.G1Point[STATE_WIDTH] quotient_poly_commitments;
        PairingsBn254.Fr[STATE_WIDTH] wire_values_at_z;
        PairingsBn254.Fr[ACCESSIBLE_STATE_POLYS_ON_NEXT_STEP] wire_values_at_z_omega;
        PairingsBn254.Fr grand_product_at_z_omega;
        PairingsBn254.Fr quotient_polynomial_at_z;
        PairingsBn254.Fr linearization_polynomial_at_z;
        PairingsBn254.Fr[STATE_WIDTH-1] permutation_polynomials_at_z;

        PairingsBn254.G1Point opening_at_z_proof;
        PairingsBn254.G1Point opening_at_z_omega_proof;
    }

    struct PartialVerifierState {
        PairingsBn254.Fr alpha;
        PairingsBn254.Fr beta;
        PairingsBn254.Fr gamma;
        PairingsBn254.Fr v;
        PairingsBn254.Fr u;
        PairingsBn254.Fr z;
        PairingsBn254.Fr[] cached_lagrange_evals;
    }

    function evaluate_lagrange_poly_out_of_domain(
        uint256 poly_num,
        uint256 domain_size,
        PairingsBn254.Fr memory omega,
        PairingsBn254.Fr memory at
    ) internal view returns (PairingsBn254.Fr memory res) {
        require(poly_num < domain_size);
        PairingsBn254.Fr memory one = PairingsBn254.new_fr(1);
        PairingsBn254.Fr memory omega_power = omega.pow(poly_num);
        res = at.pow(domain_size);
        res.sub_assign(one);
        require(res.value != 0); // Vanishing polynomial can not be zero at point `at`
        res.mul_assign(omega_power);

        PairingsBn254.Fr memory den = PairingsBn254.copy(at);
        den.sub_assign(omega_power);
        den.mul_assign(PairingsBn254.new_fr(domain_size));

        den = den.inverse();

        res.mul_assign(den);
    }

    function batch_evaluate_lagrange_poly_out_of_domain(
        uint256[] memory poly_nums,
        uint256 domain_size,
        PairingsBn254.Fr memory omega,
        PairingsBn254.Fr memory at
    ) internal view returns (PairingsBn254.Fr[] memory res) {
        PairingsBn254.Fr memory one = PairingsBn254.new_fr(1);
        PairingsBn254.Fr memory tmp_1 = PairingsBn254.new_fr(0);
        PairingsBn254.Fr memory tmp_2 = PairingsBn254.new_fr(domain_size);
        PairingsBn254.Fr memory vanishing_at_z = at.pow(domain_size);
        vanishing_at_z.sub_assign(one);
        // we can not have random point z be in domain
        require(vanishing_at_z.value != 0);
        PairingsBn254.Fr[] memory nums = new PairingsBn254.Fr[](poly_nums.length);
        PairingsBn254.Fr[] memory dens = new PairingsBn254.Fr[](poly_nums.length);
        // numerators in a form omega^i * (z^n - 1)
        // denoms in a form (z - omega^i) * N
        for (uint i = 0; i < poly_nums.length; i++) {
            tmp_1 = omega.pow(poly_nums[i]); // power of omega
            nums[i].assign(vanishing_at_z);
            nums[i].mul_assign(tmp_1);

            dens[i].assign(at); // (X - omega^i) * N
            dens[i].sub_assign(tmp_1);
            dens[i].mul_assign(tmp_2); // mul by domain size
        }

        PairingsBn254.Fr[] memory partial_products = new PairingsBn254.Fr[](poly_nums.length);
        partial_products[0].assign(PairingsBn254.new_fr(1));
        for (uint i = 1; i < dens.length - 1; i++) {
            partial_products[i].assign(dens[i-1]);
            partial_products[i].mul_assign(dens[i]);
        }

        tmp_2.assign(partial_products[partial_products.length - 1]);
        tmp_2.mul_assign(dens[dens.length - 1]);
        tmp_2 = tmp_2.inverse(); // tmp_2 contains a^-1 * b^-1 (with! the last one)

        for (uint i = dens.length - 1; i < dens.length; i--) {
            dens[i].assign(tmp_2); // all inversed
            dens[i].mul_assign(partial_products[i]); // clear lowest terms
            tmp_2.mul_assign(dens[i]);
        }

        for (uint i = 0; i < nums.length; i++) {
            nums[i].mul_assign(dens[i]);
        }

        return nums;
    }

    function evaluate_vanishing(
        uint256 domain_size,
        PairingsBn254.Fr memory at
    ) internal view returns (PairingsBn254.Fr memory res) {
        res = at.pow(domain_size);
        res.sub_assign(PairingsBn254.new_fr(1));
    }

    function verify_at_z(
        PartialVerifierState memory state,
        Proof memory proof,
        VerificationKey memory vk
    ) internal view returns (bool) {
        PairingsBn254.Fr memory lhs = evaluate_vanishing(vk.domain_size, state.z);
        require(lhs.value != 0); // we can not check a polynomial relationship if point `z` is in the domain
        lhs.mul_assign(proof.quotient_polynomial_at_z);

        PairingsBn254.Fr memory quotient_challenge = PairingsBn254.new_fr(1);
        PairingsBn254.Fr memory rhs = PairingsBn254.copy(proof.linearization_polynomial_at_z);

        // public inputs
        PairingsBn254.Fr memory tmp = PairingsBn254.new_fr(0);
        for (uint256 i = 0; i < proof.input_values.length; i++) {
            tmp.assign(state.cached_lagrange_evals[i]);
            tmp.mul_assign(PairingsBn254.new_fr(proof.input_values[i]));
            rhs.add_assign(tmp);
        }

        quotient_challenge.mul_assign(state.alpha);

        PairingsBn254.Fr memory z_part = PairingsBn254.copy(proof.grand_product_at_z_omega);
        for (uint256 i = 0; i < proof.permutation_polynomials_at_z.length; i++) {
            tmp.assign(proof.permutation_polynomials_at_z[i]);
            tmp.mul_assign(state.beta);
            tmp.add_assign(state.gamma);
            tmp.add_assign(proof.wire_values_at_z[i]);

            z_part.mul_assign(tmp);
        }

        tmp.assign(state.gamma);
        // we need a wire value of the last polynomial in enumeration
        tmp.add_assign(proof.wire_values_at_z[STATE_WIDTH - 1]);

        z_part.mul_assign(tmp);
        z_part.mul_assign(quotient_challenge);

        rhs.sub_assign(z_part);

        quotient_challenge.mul_assign(state.alpha);

        tmp.assign(state.cached_lagrange_evals[0]);
        tmp.mul_assign(quotient_challenge);

        rhs.sub_assign(tmp);

        return lhs.value == rhs.value;
    }

    function reconstruct_d(
        PartialVerifierState memory state,
        Proof memory proof,
        VerificationKey memory vk
    ) internal view returns (PairingsBn254.G1Point memory res) {
        // we compute what power of v is used as a delinearization factor in batch opening of
        // commitments. Let's label W(x) = 1 / (x - z) *
        // [
        // t_0(x) + z^n * t_1(x) + z^2n * t_2(x) + z^3n * t_3(x) - t(z)
        // + v (r(x) - r(z))
        // + v^{2..5} * (witness(x) - witness(z))
        // + v^(6..8) * (permutation(x) - permutation(z))
        // ]
        // W'(x) = 1 / (x - z*omega) *
        // [
        // + v^9 (z(x) - z(z*omega)) <- we need this power
        // + v^10 * (d(x) - d(z*omega))
        // ]
        //
        // we pay a little for a few arithmetic operations to not introduce another constant
        uint256 power_for_z_omega_opening = 1 + 1 + STATE_WIDTH + STATE_WIDTH - 1;
        res = PairingsBn254.copy_g1(vk.selector_commitments[STATE_WIDTH + 1]);

        PairingsBn254.G1Point memory tmp_g1 = PairingsBn254.P1();
        PairingsBn254.Fr memory tmp_fr = PairingsBn254.new_fr(0);

        // addition gates
        for (uint256 i = 0; i < STATE_WIDTH; i++) {
            tmp_g1 = vk.selector_commitments[i].point_mul(proof.wire_values_at_z[i]);
            res.point_add_assign(tmp_g1);
        }

        // multiplication gate
        tmp_fr.assign(proof.wire_values_at_z[0]);
        tmp_fr.mul_assign(proof.wire_values_at_z[1]);
        tmp_g1 = vk.selector_commitments[STATE_WIDTH].point_mul(tmp_fr);
        res.point_add_assign(tmp_g1);

        // d_next
        tmp_g1 = vk.next_step_selector_commitments[0].point_mul(proof.wire_values_at_z_omega[0]);
        res.point_add_assign(tmp_g1);

        // z * non_res * beta + gamma + a
        PairingsBn254.Fr memory grand_product_part_at_z = PairingsBn254.copy(state.z);
        grand_product_part_at_z.mul_assign(state.beta);
        grand_product_part_at_z.add_assign(proof.wire_values_at_z[0]);
        grand_product_part_at_z.add_assign(state.gamma);
        for (uint256 i = 0; i < vk.permutation_non_residues.length; i++) {
            tmp_fr.assign(state.z);
            tmp_fr.mul_assign(vk.permutation_non_residues[i]);
            tmp_fr.mul_assign(state.beta);
            tmp_fr.add_assign(state.gamma);
            tmp_fr.add_assign(proof.wire_values_at_z[i+1]);

            grand_product_part_at_z.mul_assign(tmp_fr);
        }

        grand_product_part_at_z.mul_assign(state.alpha);

        tmp_fr.assign(state.cached_lagrange_evals[0]);
        tmp_fr.mul_assign(state.alpha);
        tmp_fr.mul_assign(state.alpha);

        grand_product_part_at_z.add_assign(tmp_fr);

        PairingsBn254.Fr memory grand_product_part_at_z_omega = state.v.pow(power_for_z_omega_opening);
        grand_product_part_at_z_omega.mul_assign(state.u);

        PairingsBn254.Fr memory last_permutation_part_at_z = PairingsBn254.new_fr(1);
        for (uint256 i = 0; i < proof.permutation_polynomials_at_z.length; i++) {
            tmp_fr.assign(state.beta);
            tmp_fr.mul_assign(proof.permutation_polynomials_at_z[i]);
            tmp_fr.add_assign(state.gamma);
            tmp_fr.add_assign(proof.wire_values_at_z[i]);

            last_permutation_part_at_z.mul_assign(tmp_fr);
        }

        last_permutation_part_at_z.mul_assign(state.beta);
        last_permutation_part_at_z.mul_assign(proof.grand_product_at_z_omega);
        last_permutation_part_at_z.mul_assign(state.alpha);

        // add to the linearization
        tmp_g1 = proof.grand_product_commitment.point_mul(grand_product_part_at_z);
        tmp_g1.point_sub_assign(vk.permutation_commitments[STATE_WIDTH - 1].point_mul(last_permutation_part_at_z));

        res.point_add_assign(tmp_g1);
        res.point_mul_assign(state.v);

        res.point_add_assign(proof.grand_product_commitment.point_mul(grand_product_part_at_z_omega));
    }

    function verify_commitments(
        PartialVerifierState memory state,
        Proof memory proof,
        VerificationKey memory vk
    ) internal view returns (bool) {
        PairingsBn254.G1Point memory d = reconstruct_d(state, proof, vk);

        PairingsBn254.Fr memory z_in_domain_size = state.z.pow(vk.domain_size);

        PairingsBn254.G1Point memory tmp_g1 = PairingsBn254.P1();

        PairingsBn254.Fr memory aggregation_challenge = PairingsBn254.new_fr(1);

        PairingsBn254.G1Point memory commitment_aggregation = PairingsBn254.copy_g1(proof.quotient_poly_commitments[0]);
        PairingsBn254.Fr memory tmp_fr = PairingsBn254.new_fr(1);
        for (uint i = 1; i < proof.quotient_poly_commitments.length; i++) {
            tmp_fr.mul_assign(z_in_domain_size);
            tmp_g1 = proof.quotient_poly_commitments[i].point_mul(tmp_fr);
            commitment_aggregation.point_add_assign(tmp_g1);
        }

        aggregation_challenge.mul_assign(state.v);
        commitment_aggregation.point_add_assign(d);

        for (uint i = 0; i < proof.wire_commitments.length; i++) {
            aggregation_challenge.mul_assign(state.v);
            tmp_g1 = proof.wire_commitments[i].point_mul(aggregation_challenge);
            commitment_aggregation.point_add_assign(tmp_g1);
        }

        for (uint i = 0; i < vk.permutation_commitments.length - 1; i++) {
            aggregation_challenge.mul_assign(state.v);
            tmp_g1 = vk.permutation_commitments[i].point_mul(aggregation_challenge);
            commitment_aggregation.point_add_assign(tmp_g1);
        }

        aggregation_challenge.mul_assign(state.v);

        aggregation_challenge.mul_assign(state.v);

        tmp_fr.assign(aggregation_challenge);
        tmp_fr.mul_assign(state.u);
        tmp_g1 = proof.wire_commitments[STATE_WIDTH - 1].point_mul(tmp_fr);
        commitment_aggregation.point_add_assign(tmp_g1);

        // collect opening values
        aggregation_challenge = PairingsBn254.new_fr(1);

        PairingsBn254.Fr memory aggregated_value = PairingsBn254.copy(proof.quotient_polynomial_at_z);

        aggregation_challenge.mul_assign(state.v);

        tmp_fr.assign(proof.linearization_polynomial_at_z);
        tmp_fr.mul_assign(aggregation_challenge);
        aggregated_value.add_assign(tmp_fr);

        for (uint i = 0; i < proof.wire_values_at_z.length; i++) {
            aggregation_challenge.mul_assign(state.v);

            tmp_fr.assign(proof.wire_values_at_z[i]);
            tmp_fr.mul_assign(aggregation_challenge);
            aggregated_value.add_assign(tmp_fr);
        }

        for (uint i = 0; i < proof.permutation_polynomials_at_z.length; i++) {
            aggregation_challenge.mul_assign(state.v);

            tmp_fr.assign(proof.permutation_polynomials_at_z[i]);
            tmp_fr.mul_assign(aggregation_challenge);
            aggregated_value.add_assign(tmp_fr);
        }

        aggregation_challenge.mul_assign(state.v);

        tmp_fr.assign(proof.grand_product_at_z_omega);
        tmp_fr.mul_assign(aggregation_challenge);
        tmp_fr.mul_assign(state.u);
        aggregated_value.add_assign(tmp_fr);

        aggregation_challenge.mul_assign(state.v);

        tmp_fr.assign(proof.wire_values_at_z_omega[0]);
        tmp_fr.mul_assign(aggregation_challenge);
        tmp_fr.mul_assign(state.u);
        aggregated_value.add_assign(tmp_fr);

        commitment_aggregation.point_sub_assign(PairingsBn254.P1().point_mul(aggregated_value));

        PairingsBn254.G1Point memory pair_with_generator = commitment_aggregation;
        pair_with_generator.point_add_assign(proof.opening_at_z_proof.point_mul(state.z));

        tmp_fr.assign(state.z);
        tmp_fr.mul_assign(vk.omega);
        tmp_fr.mul_assign(state.u);
        pair_with_generator.point_add_assign(proof.opening_at_z_omega_proof.point_mul(tmp_fr));

        PairingsBn254.G1Point memory pair_with_x = proof.opening_at_z_omega_proof.point_mul(state.u);
        pair_with_x.point_add_assign(proof.opening_at_z_proof);
        pair_with_x.negate();

        return PairingsBn254.pairingProd2(pair_with_generator, PairingsBn254.P2(), pair_with_x, vk.g2_x);
    }

    function verify_initial(
        PartialVerifierState memory state,
        Proof memory proof,
        VerificationKey memory vk
    ) internal view returns (bool) {
        require(proof.input_values.length == vk.num_inputs);
        require(vk.num_inputs >= 1);
        TranscriptLibrary.Transcript memory transcript = TranscriptLibrary.new_transcript();
        for (uint256 i = 0; i < vk.num_inputs; i++) {
            transcript.update_with_u256(proof.input_values[i]);
        }

        for (uint256 i = 0; i < proof.wire_commitments.length; i++) {
            transcript.update_with_g1(proof.wire_commitments[i]);
        }

        state.beta = transcript.get_challenge();
        state.gamma = transcript.get_challenge();

        transcript.update_with_g1(proof.grand_product_commitment);
        state.alpha = transcript.get_challenge();

        for (uint256 i = 0; i < proof.quotient_poly_commitments.length; i++) {
            transcript.update_with_g1(proof.quotient_poly_commitments[i]);
        }

        state.z = transcript.get_challenge();

        uint256[] memory lagrange_poly_numbers = new uint256[](vk.num_inputs);
        for (uint256 i = 0; i < lagrange_poly_numbers.length; i++) {
            lagrange_poly_numbers[i] = i;
        }

        state.cached_lagrange_evals = batch_evaluate_lagrange_poly_out_of_domain(
            lagrange_poly_numbers,
            vk.domain_size,
            vk.omega, state.z
        );

        bool valid = verify_at_z(state, proof, vk);

        if (valid == false) {
            return false;
        }

        for (uint256 i = 0; i < proof.wire_values_at_z.length; i++) {
            transcript.update_with_fr(proof.wire_values_at_z[i]);
        }

        for (uint256 i = 0; i < proof.wire_values_at_z_omega.length; i++) {
            transcript.update_with_fr(proof.wire_values_at_z_omega[i]);
        }

        for (uint256 i = 0; i < proof.permutation_polynomials_at_z.length; i++) {
            transcript.update_with_fr(proof.permutation_polynomials_at_z[i]);
        }

        transcript.update_with_fr(proof.quotient_polynomial_at_z);
        transcript.update_with_fr(proof.linearization_polynomial_at_z);

        state.v = transcript.get_challenge();
        transcript.update_with_g1(proof.opening_at_z_proof);
        transcript.update_with_g1(proof.opening_at_z_omega_proof);
        state.u = transcript.get_challenge();

        return true;
    }

    // This verifier is for a PLONK with a state width 4
    // and main gate equation
    // q_a(X) * a(X) +
    // q_b(X) * b(X) +
    // q_c(X) * c(X) +
    // q_d(X) * d(X) +
    // q_m(X) * a(X) * b(X) +
    // q_constants(X)+
    // q_d_next(X) * d(X*omega)
    // where q_{}(X) are selectors a, b, c, d - state (witness) polynomials
    // q_d_next(X) "peeks" into the next row of the trace, so it takes
    // the same d(X) polynomial, but shifted

    function verify(Proof memory proof, VerificationKey memory vk) internal view returns (bool) {
        PartialVerifierState memory state;

        bool valid = verify_initial(state, proof, vk);

        if (valid == false) {
            return false;
        }

        valid = verify_commitments(state, proof, vk);

        return valid;
    }
}

contract VerifierWithDeserialize is Plonk4VerifierWithAccessToDNext {
    uint256 constant SERIALIZED_PROOF_LENGTH = 33;

    function deserialize_proof(
        uint256[] memory public_inputs,
        uint256[] memory serialized_proof
    ) internal pure returns(Proof memory proof) {
        require(serialized_proof.length == SERIALIZED_PROOF_LENGTH);
        proof.input_values = new uint256[](public_inputs.length);
        for (uint256 i = 0; i < public_inputs.length; i++) {
            proof.input_values[i] = public_inputs[i];
        }

        uint256 j = 0;
        for (uint256 i = 0; i < STATE_WIDTH; i++) {
            proof.wire_commitments[i] = PairingsBn254.new_g1_checked(
                serialized_proof[j],
                serialized_proof[j+1]
            );

            j += 2;
        }

        proof.grand_product_commitment = PairingsBn254.new_g1_checked(
            serialized_proof[j],
            serialized_proof[j+1]
        );
        j += 2;

        for (uint256 i = 0; i < STATE_WIDTH; i++) {
            proof.quotient_poly_commitments[i] = PairingsBn254.new_g1_checked(
                serialized_proof[j],
                serialized_proof[j+1]
            );

            j += 2;
        }

        for (uint256 i = 0; i < STATE_WIDTH; i++) {
            proof.wire_values_at_z[i] = PairingsBn254.new_fr(
                serialized_proof[j]
            );

            j += 1;
        }

        for (uint256 i = 0; i < proof.wire_values_at_z_omega.length; i++) {
            proof.wire_values_at_z_omega[i] = PairingsBn254.new_fr(
                serialized_proof[j]
            );

            j += 1;
        }

        proof.grand_product_at_z_omega = PairingsBn254.new_fr(
            serialized_proof[j]
        );

        j += 1;

        proof.quotient_polynomial_at_z = PairingsBn254.new_fr(
            serialized_proof[j]
        );

        j += 1;

        proof.linearization_polynomial_at_z = PairingsBn254.new_fr(
            serialized_proof[j]
        );

        j += 1;

        for (uint256 i = 0; i < proof.permutation_polynomials_at_z.length; i++) {
            proof.permutation_polynomials_at_z[i] = PairingsBn254.new_fr(
                serialized_proof[j]
            );

            j += 1;
        }

        proof.opening_at_z_proof = PairingsBn254.new_g1_checked(
            serialized_proof[j],
            serialized_proof[j+1]
        );
        j += 2;

        proof.opening_at_z_omega_proof = PairingsBn254.new_g1_checked(
            serialized_proof[j],
            serialized_proof[j+1]
        );
    }
}

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

Contract Security Audit

Contract ABI

API
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"blockNumber","type":"uint32"}],"name":"BlockCommit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"blockNumber","type":"uint32"}],"name":"BlockVerification","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"totalBlocksVerified","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"totalBlocksCommitted","type":"uint32"}],"name":"BlocksRevert","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"zkSyncBlockId","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"accountId","type":"uint32"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint16","name":"tokenId","type":"uint16"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"DepositCommit","type":"event"},{"anonymous":false,"inputs":[],"name":"ExodusMode","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint32","name":"nonce","type":"uint32"},{"indexed":false,"internalType":"bytes","name":"fact","type":"bytes"}],"name":"FactAuth","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"zkSyncBlockId","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"accountId","type":"uint32"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint16","name":"tokenId","type":"uint16"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"FullExitCommit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint64","name":"serialId","type":"uint64"},{"indexed":false,"internalType":"enum Operations.OpType","name":"opType","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"pubData","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"expirationBlock","type":"uint256"}],"name":"NewPriorityRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"uint16","name":"tokenId","type":"uint16"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"OnchainDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint16","name":"tokenId","type":"uint16"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"OnchainWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"queueStartIndex","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"queueEndIndex","type":"uint32"}],"name":"PendingWithdrawalsAdd","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"queueStartIndex","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"queueEndIndex","type":"uint32"}],"name":"PendingWithdrawalsComplete","type":"event"},{"constant":true,"inputs":[],"name":"EMPTY_STRING_KECCAK","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint32","name":"","type":"uint32"}],"name":"authFacts","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes22","name":"","type":"bytes22"}],"name":"balancesToWithdraw","outputs":[{"internalType":"uint128","name":"balanceToWithdraw","type":"uint128"},{"internalType":"uint8","name":"gasReserveValue","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"blocks","outputs":[{"internalType":"uint32","name":"committedAtBlock","type":"uint32"},{"internalType":"uint64","name":"priorityOperations","type":"uint64"},{"internalType":"uint32","name":"chunks","type":"uint32"},{"internalType":"bytes32","name":"withdrawalsDataHash","type":"bytes32"},{"internalType":"bytes32","name":"commitment","type":"bytes32"},{"internalType":"bytes32","name":"stateRoot","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint64","name":"_n","type":"uint64"}],"name":"cancelOutstandingDepositsForExodusMode","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint32","name":"_blockNumber","type":"uint32"},{"internalType":"uint32","name":"_feeAccount","type":"uint32"},{"internalType":"bytes32[]","name":"_newBlockInfo","type":"bytes32[]"},{"internalType":"bytes","name":"_publicData","type":"bytes"},{"internalType":"bytes","name":"_ethWitness","type":"bytes"},{"internalType":"uint32[]","name":"_ethWitnessSizes","type":"uint32[]"}],"name":"commitBlock","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint32","name":"_n","type":"uint32"}],"name":"completeWithdrawals","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"uint104","name":"_amount","type":"uint104"},{"internalType":"address","name":"_franklinAddr","type":"address"}],"name":"depositERC20","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_franklinAddr","type":"address"}],"name":"depositETH","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint32","name":"_accountId","type":"uint32"},{"internalType":"uint16","name":"_tokenId","type":"uint16"},{"internalType":"uint128","name":"_amount","type":"uint128"},{"internalType":"uint256[]","name":"_proof","type":"uint256[]"}],"name":"exit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"uint16","name":"","type":"uint16"}],"name":"exited","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"exodusMode","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"firstPendingWithdrawalIndex","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"firstPriorityRequestId","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint32","name":"_accountId","type":"uint32"},{"internalType":"address","name":"_token","type":"address"}],"name":"fullExit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"uint16","name":"_tokenId","type":"uint16"}],"name":"getBalanceToWithdraw","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"getNoticePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"initializationParameters","type":"bytes"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"isReadyForUpgrade","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"numberOfPendingWithdrawals","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"pendingWithdrawals","outputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint16","name":"tokenId","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"priorityRequests","outputs":[{"internalType":"enum Operations.OpType","name":"opType","type":"uint8"},{"internalType":"bytes","name":"pubData","type":"bytes"},{"internalType":"uint256","name":"expirationBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint32","name":"_maxBlocksToRevert","type":"uint32"}],"name":"revertBlocks","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"_pubkey_hash","type":"bytes"},{"internalType":"uint32","name":"_nonce","type":"uint32"}],"name":"setAuthPubkeyHash","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalBlocksCommitted","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalBlocksVerified","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalCommittedPriorityRequests","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalOpenPriorityRequests","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"triggerExodusIfNeeded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"upgradeParameters","type":"bytes"}],"name":"upgrade","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"upgradeCanceled","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"upgradeFinishes","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"upgradeNoticePeriodStarted","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"upgradePreparationActivationTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"upgradePreparationActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"upgradePreparationStarted","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint32","name":"_blockNumber","type":"uint32"},{"internalType":"uint256[]","name":"_proof","type":"uint256[]"},{"internalType":"bytes","name":"_withdrawalsData","type":"bytes"}],"name":"verifyBlock","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"uint128","name":"_amount","type":"uint128"}],"name":"withdrawERC20","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint128","name":"_amount","type":"uint128"},{"internalType":"uint128","name":"_maxAmount","type":"uint128"}],"name":"withdrawERC20Guarded","outputs":[{"internalType":"uint128","name":"withdrawnAmount","type":"uint128"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint128","name":"_amount","type":"uint128"}],"name":"withdrawETH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b506159d380620000216000396000f3fe6080604052600436106102385760003560e01c80636b27a0441161012e578063b269b9ae116100ab578063d6973fc61161006f578063d6973fc614610be8578063e17376b514610c89578063fa6b53c314610cdb578063faf4d8cb14610d18578063ffeec23714610d2d57610238565b8063b269b9ae146109d5578063c488a09c14610b49578063c57b22be14610b7c578063c94c5b7c14610b91578063cd24ee0814610bd357610238565b80638ae20dc9116100f25780638ae20dc9146109ff578063922e149214610a3e5780639a83400d14610a53578063a2f9f1ce14610ac3578063a6289e5a14610b1957610238565b80636b27a044146108e457806378b91e70146108f95780637d4907981461090e578063871b8ff1146109d55780638773334c146109ea57610238565b806334f6bb1c116101bc5780634e913cd9116101805780634e913cd914610626578063595a5ebc146107a75780635cd0783e1461082857806367708dae1461089f5780636a387fc9146108b457610238565b806334f6bb1c146104f75780633b154b73146105285780633c06e5141461053d5780633c6461a914610552578063439fab91146105ab57610238565b80632a3174f4116102035780632a3174f4146104215780632b8c062a146104365780632d24006c146104705780632d2da8061461049e5780632f804bd2146104c457610238565b8060e21461023d5780630231c02c1461027e57806321ae605414610356578063253946451461037d578063264c0912146103f8575b600080fd5b34801561024957600080fd5b5061027c6004803603604081101561026057600080fd5b50803563ffffffff1690602001356001600160a01b0316610d42565b005b34801561028a57600080fd5b5061027c600480360360608110156102a157600080fd5b63ffffffff8235169190810190604081016020820135600160201b8111156102c857600080fd5b8201836020820111156102da57600080fd5b803590602001918460208302840111600160201b831117156102fb57600080fd5b919390929091602081019035600160201b81111561031857600080fd5b82018360208201111561032a57600080fd5b803590602001918460018302840111600160201b8311171561034b57600080fd5b509092509050610f36565b34801561036257600080fd5b5061036b61127a565b60408051918252519081900360200190f35b34801561038957600080fd5b5061027c600480360360208110156103a057600080fd5b810190602081018135600160201b8111156103ba57600080fd5b8201836020820111156103cc57600080fd5b803590602001918460018302840111600160201b831117156103ed57600080fd5b50909250905061129e565b34801561040457600080fd5b5061040d6112a2565b604080519115158252519081900360200190f35b34801561042d57600080fd5b5061036b6112ab565b34801561044257600080fd5b5061040d6004803603604081101561045957600080fd5b50803563ffffffff16906020013561ffff166112b3565b34801561047c57600080fd5b506104856112d3565b6040805163ffffffff9092168252519081900360200190f35b61027c600480360360208110156104b457600080fd5b50356001600160a01b03166112e6565b3480156104d057600080fd5b5061027c600480360360208110156104e757600080fd5b50356001600160401b031661137a565b34801561050357600080fd5b5061050c6116a7565b604080516001600160401b039092168252519081900360200190f35b34801561053457600080fd5b5061027c6116bd565b34801561054957600080fd5b506104856116bf565b34801561055e57600080fd5b506105866004803603602081101561057557600080fd5b50356001600160501b0319166116d2565b604080516001600160801b03909316835260ff90911660208301528051918290030190f35b3480156105b757600080fd5b5061027c600480360360208110156105ce57600080fd5b810190602081018135600160201b8111156105e857600080fd5b8201836020820111156105fa57600080fd5b803590602001918460018302840111600160201b8311171561061b57600080fd5b5090925090506116f9565b34801561063257600080fd5b5061027c600480360360c081101561064957600080fd5b63ffffffff8235811692602081013590911691810190606081016040820135600160201b81111561067957600080fd5b82018360208201111561068b57600080fd5b803590602001918460208302840111600160201b831117156106ac57600080fd5b919390929091602081019035600160201b8111156106c957600080fd5b8201836020820111156106db57600080fd5b803590602001918460018302840111600160201b831117156106fc57600080fd5b919390929091602081019035600160201b81111561071957600080fd5b82018360208201111561072b57600080fd5b803590602001918460018302840111600160201b8311171561074c57600080fd5b919390929091602081019035600160201b81111561076957600080fd5b82018360208201111561077b57600080fd5b803590602001918460208302840111600160201b8311171561079c57600080fd5b509092509050611780565b3480156107b357600080fd5b5061027c600480360360408110156107ca57600080fd5b810190602081018135600160201b8111156107e457600080fd5b8201836020820111156107f657600080fd5b803590602001918460018302840111600160201b8311171561081757600080fd5b91935091503563ffffffff16611a88565b34801561083457600080fd5b506108586004803603602081101561084b57600080fd5b503563ffffffff16611c3f565b6040805163ffffffff97881681526001600160401b03909616602087015293909516848401526060840191909152608083015260a082019290925290519081900360c00190f35b3480156108ab57600080fd5b5061050c611c88565b3480156108c057600080fd5b5061027c600480360360208110156108d757600080fd5b503563ffffffff16611c97565b3480156108f057600080fd5b5061040d612077565b34801561090557600080fd5b5061027c612123565b34801561091a57600080fd5b506109416004803603602081101561093157600080fd5b50356001600160401b0316612138565b6040518084600781111561095157fe5b60ff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b83811015610998578181015183820152602001610980565b50505050905090810190601f1680156109c55780820380516001836020036101000a031916815260200191505b5094505050505060405180910390f35b3480156109e157600080fd5b5061027c6121ec565b3480156109f657600080fd5b5061040d6121fb565b348015610a0b57600080fd5b5061036b60048036036040811015610a2257600080fd5b5080356001600160a01b0316906020013563ffffffff16612205565b348015610a4a57600080fd5b5061040d612222565b348015610a5f57600080fd5b50610aa760048036036080811015610a7657600080fd5b506001600160a01b0381358116916020810135909116906001600160801b036040820135811691606001351661222b565b604080516001600160801b039092168252519081900360200190f35b348015610acf57600080fd5b50610af360048036036020811015610ae657600080fd5b503563ffffffff16612415565b604080516001600160a01b03909316835261ffff90911660208301528051918290030190f35b348015610b2557600080fd5b5061027c60048036036020811015610b3c57600080fd5b503563ffffffff1661243d565b348015610b5557600080fd5b5061027c60048036036020811015610b6c57600080fd5b50356001600160801b031661275c565b348015610b8857600080fd5b5061050c612866565b348015610b9d57600080fd5b5061027c60048036036040811015610bb457600080fd5b5080356001600160a01b031690602001356001600160801b031661287c565b348015610bdf57600080fd5b50610485612a3e565b348015610bf457600080fd5b5061027c60048036036080811015610c0b57600080fd5b63ffffffff8235169161ffff602082013516916001600160801b036040830135169190810190608081016060820135600160201b811115610c4b57600080fd5b820183602082011115610c5d57600080fd5b803590602001918460208302840111600160201b83111715610c7e57600080fd5b509092509050612a4a565b348015610c9557600080fd5b5061027c60048036036060811015610cac57600080fd5b506001600160a01b0381358116916cffffffffffffffffffffffffff6020820135169160409091013516612d55565b348015610ce757600080fd5b50610aa760048036036040811015610cfe57600080fd5b5080356001600160a01b0316906020013561ffff16612fd6565b348015610d2457600080fd5b50610485613011565b348015610d3957600080fd5b5061036b613024565b60008051602061592c8339815191525480610d92576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c83398151915255610dac61302a565b62ffffff63ffffffff84161115610df2576040805162461bcd60e51b8152602060048201526005602482015264666565313160d81b604482015290519081900360640190fd5b60006001600160a01b038316610e0a57506000610e86565b600354604080516375698bb160e11b81526001600160a01b0386811660048301529151919092169163ead31762916024808301926020929190829003018186803b158015610e5757600080fd5b505afa158015610e6b573d6000803e3d6000fd5b505050506040513d6020811015610e8157600080fd5b505190505b610e8e61579c565b60405180608001604052808663ffffffff168152602001336001600160a01b031681526020018361ffff16815260200160006001600160801b031681525090506060610ed98261306a565b9050610ee66006826130ff565b6000610ef233856132c2565b6001600160501b0319166000908152600460205260409020805460ff60801b191660ff60801b1790555050600160008051602061592c833981519152555050505050565b60008051602061592c8339815191525480610f86576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c83398151915255610fa061302a565b600660089054906101000a900463ffffffff1660010163ffffffff168663ffffffff1614610ffd576040805162461bcd60e51b815260206004820152600560248201526466766b313160d81b604482015290519081900360640190fd5b60035460408051634b18bd0f60e01b815233600482015290516001600160a01b0390921691634b18bd0f91602480820192600092909190829003018186803b15801561104857600080fd5b505afa15801561105c573d6000803e3d6000fd5b50506002805463ffffffff808b166000908152600760209081526040918290209485015494549151633711baa560e21b815260248101869052600160601b90920490921660448201819052606060048301908152606483018c90526001600160a01b03909416965063dc46ea9495508b948b949093919290918291608401908790870280828437600081840152601f19601f8201169050808301925050509550505050505060206040518083038186803b15801561111957600080fd5b505afa15801561112d573d6000803e3d6000fd5b505050506040513d602081101561114357600080fd5b505161117e576040805162461bcd60e51b815260206004820152600560248201526466766b313360d81b604482015290519081900360640190fd5b6111d383838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525063ffffffff8c1681526007602052604090206001015492506132df915050565b63ffffffff861660009081526007602052604090205461120290600160201b90046001600160401b03166135ee565b6006805463ffffffff600160401b80830482166001018216026bffffffff00000000000000001990921691909117909155604051908716907f0cdbd8bd7813095001c5fe7917bd69d834dc01db7c1dfcf52ca135bd2038441390600090a2600160008051602061592c83398151915255505050505050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081565b5050565b60095460ff1681565b620a8c005b90565b600860209081526000928352604080842090915290825290205460ff1681565b600654600160401b900463ffffffff1681565b60008051602061592c8339815191525480611336576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c8339815191525561135061302a565b611364600061135e3461372e565b84613772565b600160008051602061592c833981519152555050565b60008051602061592c83398151915254806113ca576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c8339815191525560095460ff1661141b576040805162461bcd60e51b8152602060048201526005602482015264636f65303160d81b604482015290519081900360640190fd5b600c5460009061143b90600160401b90046001600160401b031684613829565b90506000816001600160401b031611611483576040805162461bcd60e51b815260206004820152600560248201526431b7b2981960d91b604482015290519081900360640190fd5b600c546001600160401b03165b600c546001600160401b039081168301811690821610156116475760016001600160401b0382166000908152600b602052604090205460ff1660078111156114d457fe5b1415611607576114e261579c565b6115ab600b6000846001600160401b03166001600160401b031681526020019081526020016000206001018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156115a15780601f10611576576101008083540402835291602001916115a1565b820191906000526020600020905b81548152906001019060200180831161158457829003601f168201915b5050505050613853565b905060006115c1826060015183602001516132c2565b6040928301516001600160501b031991909116600090815260046020529290922080546001600160801b031981166001600160801b039182169094011692909217909155505b6001600160401b0381166000908152600b60205260408120805460ff191681559061163560018301826157c3565b50600060029190910155600101611490565b50600c805467ffffffffffffffff60401b1967ffffffffffffffff1982166001600160401b039283168501831617908116600160401b91829004831694909403909116029190911790555050600160008051602061592c83398151915255565b600c54600160801b90046001600160401b031681565b565b600654600160201b900463ffffffff1681565b6004602052600090815260409020546001600160801b03811690600160801b900460ff1682565b6117016138fd565b60008060008484606081101561171657600080fd5b50600280546001600160a01b0360208481013582166001600160a01b031993841617909355600380548535909216919092161790556000805260079052604001357f6d5257204ebe7d88fd91ae87941cb2dd9d8062b64ae5a2bd2d28ec40b9fbf6e2555050505050565b60008051602061592c83398151915254806117d0576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c833981519152556117ea61302a565b6006600c9054906101000a900463ffffffff1660010163ffffffff168b63ffffffff1614611847576040805162461bcd60e51b815260206004820152600560248201526466636b313160d81b604482015290519081900360640190fd5b60035460408051634b18bd0f60e01b815233600482015290516001600160a01b0390921691634b18bd0f91602480820192600092909190829003018186803b15801561189257600080fd5b505afa1580156118a6573d6000803e3d6000fd5b5050506001891490506118e8576040805162461bcd60e51b815260206004820152600560248201526466636b313360d81b604482015290519081900360640190fd5b606087878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505090506000600c60109054906101000a90046001600160401b0316905060006119bf8e848a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c91829185019084908082843760009201919091525061391192505050565b600c54909150600160801b90046001600160401b03168290036119f78f8f8f8f6000816119e857fe5b90506020020135878686613fd4565b6006600c81819054906101000a900463ffffffff168092919060010191906101000a81548163ffffffff021916908363ffffffff160217905550508e63ffffffff167f81a92942d0f9c33b897a438384c9c3d88be397776138efa3ba1a4fc8b626842460405160405180910390a250505050600160008051602061592c833981519152555050505050505050505050565b60008051602061592c8339815191525480611ad8576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c8339815191525560148314611b27576040805162461bcd60e51b8152602060048201526005602482015264061686631360dc1b604482015290519081900360640190fd5b336000908152600a6020908152604080832063ffffffff8616845290915290205415611b82576040805162461bcd60e51b8152602060048201526005602482015264616866313160d81b604482015290519081900360640190fd5b83836040518083838082843760408051919093018190038120336000818152600a602090815286822063ffffffff8d16808452908252918790209390935583529082018481529382018a905295507f9ea39b45a0cc96a2139996ec8dd30326216111249750781e563ae27c31ae87669450879350899289925060608201848480828437600083820152604051601f909101601f1916909201829003965090945050505050a2600160008051602061592c8339815191525550505050565b600760205260009081526040902080546001820154600283015460039093015463ffffffff808416946001600160401b03600160201b86041694600160601b9004909116929186565b600c546001600160401b031681565b60008051602061592c8339815191525480611ce7576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c833981519152556000611d1783600660049054906101000a900463ffffffff166141c3565b60068054600160201b80820463ffffffff908116859003811690910267ffffffff00000000198316178082168501821663ffffffff199091161790925591925016805b82820163ffffffff168163ffffffff16101561200d5763ffffffff8116600090815260056020526040812080546001600160b01b0319811690915561ffff600160a01b820416916001600160a01b0390911690611db782846132c2565b6001600160501b031981166000908152600460205260409020549091506001600160801b03168015611ffe576001600160501b03198216600090815260046020526040812080546001600160801b03808216859003166001600160801b031990911617905561ffff8516611e415783611e39816001600160801b0385166141de565b915050611fbe565b600354604080516310603dad60e01b815261ffff8816600482015290516000926001600160a01b0316916310603dad916024808301926020929190829003018186803b158015611e9057600080fd5b505afa158015611ea4573d6000803e3d6000fd5b505050506040513d6020811015611eba57600080fd5b5051604080516001600160a01b038084166024830152881660448201526001600160801b038616606482018190526084808301919091528251808303909101815260a490910182526020810180516001600160e01b0316639a83400d60e01b1781529151815193945030936203d0909382918083835b60208310611f4f5780518252601f199092019160209182019101611f30565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038160008787f1925050503d8060008114611fb2576040519150601f19603f3d011682016040523d82523d6000602084013e611fb7565b606091505b5090925050505b80611ffc576001600160501b03198316600090815260046020526040902080546001600160801b038082168501166001600160801b03199091161790555b505b50505050806001019050611d5a565b5063ffffffff82161561205f576040805163ffffffff808416825284840116602082015281517f9b5478c99b5ca41beec4f6f6084126d6f9e26382d017b4bb67c37c9e8453a313929181900390910190a15b5050600160008051602061592c833981519152555050565b600c546001600160401b03166000908152600b6020526040812060020154819043108015906120c25750600c546001600160401b03166000908152600b602052604090206002015415155b905080156121155760095460ff1661210b576009805460ff191660011790556040517fc71028c67eb0ef128ea270a59a674629e767d51c1af44ed6753fd2fad2c7b67790600090a15b60019150506112b0565b60009150506112b0565b5090565b6000805460ff19166001908117909155429055565b600b602090815260009182526040918290208054600180830180548651600261010094831615949094026000190190911692909204601f810186900486028301860190965285825260ff9092169492939092908301828280156121dc5780601f106121b1576101008083540402835291602001916121dc565b820191906000526020600020905b8154815290600101906020018083116121bf57829003601f168201915b5050505050908060020154905083565b6000805460ff19168155600155565b60095460ff161590565b600a60209081526000928352604080842090915290825290205481565b60005460ff1681565b6000333014612269576040805162461bcd60e51b8152602060048201526005602482015264077746731360dc1b604482015290519081900360640190fd5b604080516370a0823160e01b815230600482015290516000916001600160a01b038816916370a0823191602480820192602092909190829003018186803b1580156122b357600080fd5b505afa1580156122c7573d6000803e3d6000fd5b505050506040513d60208110156122dd57600080fd5b505190506122f586866001600160801b038716614243565b61232e576040805162461bcd60e51b8152602060048201526005602482015264777467313160d81b604482015290519081900360640190fd5b604080516370a0823160e01b815230600482015290516000916001600160a01b038916916370a0823191602480820192602092909190829003018186803b15801561237857600080fd5b505afa15801561238c573d6000803e3d6000fd5b505050506040513d60208110156123a257600080fd5b5051905060006123b8838363ffffffff61436a16565b9050846001600160801b0316811115612400576040805162461bcd60e51b81526020600482015260056024820152643bba33989960d91b604482015290519081900360640190fd5b6124098161372e565b98975050505050505050565b6005602052600090815260409020546001600160a01b03811690600160a01b900461ffff1682565b60008051602061592c833981519152548061248d576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c833981519152556124a76143ac565b6124e0576040805162461bcd60e51b8152602060048201526005602482015264726273313160d81b604482015290519081900360640190fd5b60035460408051634b18bd0f60e01b815233600482015290516001600160a01b0390921691634b18bd0f91602480820192600092909190829003018186803b15801561252b57600080fd5b505afa15801561253f573d6000803e3d6000fd5b505060065463ffffffff600160601b8204811693506000925061256e918691600160401b9091041684036141c3565b600654909150600090600160601b900463ffffffff168290036001015b8363ffffffff168163ffffffff161161269d576125a661580a565b5063ffffffff808216600090815260076020908152604091829020825160c08101845281548086168083526001600160401b03600160201b83041694830194909452600160601b900490941692840192909252600182015460608401526002820154608084015260039091015460a0830152612651576040805162461bcd60e51b815260206004820152600560248201526466726b313160d81b604482015290519081900360640190fd5b60209081015163ffffffff8316600090815260079092526040822080546001600160801b031916815560018082018490556002820184905560039091019290925592909201910161258b565b506006805463ffffffff600160601b808304821686900382160263ffffffff60601b199092169190911791829055600c80546001600160401b03600160801b80830482168790039091160267ffffffffffffffff60801b1990911617905560408051600160401b90930482168352948490039081166020830152845190947f6f3a8259cce1ea2680115053d21c971aa1764295a45850f520525f2bfdf3c9d3928290030190a1505050600160008051602061592c833981519152555050565b60008051602061592c83398151915254806127ac576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c833981519152556127ca60008333614431565b604051600090339084908381818185875af1925050503d806000811461280c576040519150601f19603f3d011682016040523d82523d6000602084013e612811565b606091505b505090508061284f576040805162461bcd60e51b8152602060048201526005602482015264667765313160d81b604482015290519081900360640190fd5b50600160008051602061592c833981519152555050565b600c54600160401b90046001600160401b031681565b60008051602061592c83398151915254806128cc576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c833981519152819055600354604080516375698bb160e11b81526001600160a01b0387811660048301529151919092169163ead31762916024808301926020929190829003018186803b15801561292d57600080fd5b505afa158015612941573d6000803e3d6000fd5b505050506040513d602081101561295757600080fd5b50519050600061296733836132c2565b6001600160501b031981166000908152600460208181526040808420548151639a83400d60e01b81526001600160a01b038c16948101949094523360248501526001600160801b038a8116604486015216606484018190529051949550933092639a83400d92608480830193919282900301818787803b1580156129ea57600080fd5b505af11580156129fe573d6000803e3d6000fd5b505050506040513d6020811015612a1457600080fd5b50519050612a23848233614431565b50505050600160008051602061592c83398151915255505050565b60065463ffffffff1681565b60008051602061592c8339815191525480612a9a576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c833981519152556000612ab833876132c2565b60095490915060ff16612afa576040805162461bcd60e51b8152602060048201526005602482015264666574313160d81b604482015290519081900360640190fd5b63ffffffff8716600090815260086020908152604080832061ffff8a16845290915290205460ff1615612b5c576040805162461bcd60e51b81526020600482015260056024820152643332ba189960d91b604482015290519081900360640190fd5b60025460065463ffffffff600160401b909104811660009081526007602090815260409182902060030154915163c81a27ad60e01b815260048101838152938c166024820152336044820181905261ffff8c1660648301526001600160801b038b16608483015260c060a4830190815260c483018a90526001600160a01b039096169563c81a27ad958e9492938e938e938e938e93909260e4909101908590850280828437600081840152601f19601f8201169050808301925050509850505050505050505060206040518083038186803b158015612c3a57600080fd5b505afa158015612c4e573d6000803e3d6000fd5b505050506040513d6020811015612c6457600080fd5b5051612c9f576040805162461bcd60e51b8152602060048201526005602482015264666574313360d81b604482015290519081900360640190fd5b6001600160501b031981166000908152600460205260409020546001600160801b0316612cd2818763ffffffff6144f416565b6001600160501b0319909216600090815260046020908152604080832080546001600160801b03969096166001600160801b03199096169590951790945563ffffffff90991681526008895282812061ffff909816815296909752909420805460ff1916600190811790915560008051602061592c833981519152555050505050565b60008051602061592c8339815191525480612da5576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c83398151915255612dbf61302a565b600354604080516375698bb160e11b81526001600160a01b0387811660048301529151600093929092169163ead3176291602480820192602092909190829003018186803b158015612e1057600080fd5b505afa158015612e24573d6000803e3d6000fd5b505050506040513d6020811015612e3a57600080fd5b5051604080516370a0823160e01b815230600482015290519192506000916001600160a01b038816916370a08231916024808301926020929190829003018186803b158015612e8857600080fd5b505afa158015612e9c573d6000803e3d6000fd5b505050506040513d6020811015612eb257600080fd5b50519050612ee2863330612ed46cffffffffffffffffffffffffff8a1661372e565b6001600160801b031661455a565b612f1b576040805162461bcd60e51b8152602060048201526005602482015264333218189960d91b604482015290519081900360640190fd5b604080516370a0823160e01b815230600482015290516000916001600160a01b038916916370a0823191602480820192602092909190829003018186803b158015612f6557600080fd5b505afa158015612f79573d6000803e3d6000fd5b505050506040513d6020811015612f8f57600080fd5b505190506000612fad612fa8838563ffffffff61436a16565b61372e565b9050612fba848288613772565b50505050600160008051602061592c8339815191525550505050565b600060046000612fe685856132c2565b6001600160501b03191681526020810191909152604001600020546001600160801b03169392505050565b600654600160601b900463ffffffff1681565b60015481565b60095460ff16156116bd576040805162461bcd60e51b8152602060048201526005602482015264667265313160d81b604482015290519081900360640190fd5b60608160000151826020015183604001518460600151604051602001808563ffffffff1663ffffffff1660e01b8152600401846001600160a01b03166001600160a01b031660601b81526014018361ffff1661ffff1660f01b8152600201826001600160801b03166001600160801b031660801b81526010019450505050506040516020818303038152906040529050919050565b600c5460408051606081019091524361438001916001600160401b03808216600160401b9092041601908085600781111561313657fe5b8152602080820186905260409182018590526001600160401b0384166000908152600b9091522081518154829060ff1916600183600781111561317557fe5b02179055506020828101518051613192926001850192019061583f565b50604082015181600201559050507fd0943372c08b438a88d4b39d77216901079eda9ca59d45349841c099083b6830338286868660405180866001600160a01b03166001600160a01b03168152602001856001600160401b03166001600160401b0316815260200184600781111561320657fe5b60ff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b8381101561324d578181015183820152602001613235565b50505050905090810190601f16801561327a5780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a15050600c805460016001600160401b03600160401b808404821692909201160267ffffffffffffffff60401b199091161790555050565b60a01b61ffff60a01b166001600160a01b03919091161760501b90565b60278251816132ea57fe5b0615613325576040805162461bcd60e51b8152602060048201526005602482015264706f77313160d81b604482015290519081900360640190fd5b6006547fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47090600090600160201b900463ffffffff165b8451821015613517576000806000806133748987614687565b9350935093509350600061338884846132c2565b6001600160501b03198116600090815260046020526040908190205481518083019092529192506001600160801b0390911690806133cc838663ffffffff6144f416565b6001600160801b03908116825260ff60209283018190526001600160501b0319861660009081526004845260409020845181549590940151909116600160801b0260ff60801b19939092166001600160801b0319909416939093179190911617905585156134ae576040805180820182526001600160a01b03878116825261ffff878116602080850191825260065463ffffffff9081168e011660009081526005909152949094209251835494516001600160a01b031990951692169190911761ffff60a01b1916600160a01b93909116929092029190911790556001909601955b505060408051602080820199909952941515858201526001600160a01b03909316606085015261ffff90911660808401526001600160801b031660a0808401919091528151808403909101815260c090920190528051930192909220916027919091019061335b565b838314613553576040805162461bcd60e51b81526020600482015260056024820152643837bb989960d91b604482015290519081900360640190fd5b60065463ffffffff828116600160201b90920416146135c3576006546040805163ffffffff808416600160201b9094048116840181168252928401909216602083015280517fc4faeb4e73f28a46e4a5fa2db5b89c39698816488534ab7f0717c46f0852c3669281900390910190a15b6006805463ffffffff909216600160201b0267ffffffff000000001990921691909117905550505050565b600c546001600160401b03600160401b90910481169082161115613641576040805162461bcd60e51b8152602060048201526005602482015264706373323160d81b604482015290519081900360640190fd5b600061364e826006613829565b600c549091506001600160401b0316805b8282016001600160401b0316816001600160401b031610156136bb576001600160401b0381166000908152600b60205260408120805460ff19168155906136a960018301826157c3565b5060006002919091015560010161365f565b5050600c8054600160801b6001600160401b03600160401b808404821687900382160267ffffffffffffffff60401b19909316929092178083168601831667ffffffffffffffff19909116178181048316959095039091160267ffffffffffffffff60801b199093169290921790915550565b6000600160801b821061211f5760405162461bcd60e51b815260040180806020018281038252602781526020018061594c6027913960400191505060405180910390fd5b61377a61579c565b6040518060800160405280600063ffffffff1681526020018561ffff168152602001846001600160801b03168152602001836001600160a01b0316815250905060606137c5826146ce565b90506137d26001826130ff565b604080516001600160801b038616815290516001600160a01b0385169161ffff88169133917fb6866b029f3aa29cd9e2bff8159a8ccaa4389f7a087c710968e0b200c0c73b08919081900360200190a45050505050565b6000816001600160401b0316836001600160401b03161061384a578161384c565b825b9392505050565b61385b61579c565b60006138678382614738565b63ffffffff168352905061387b8382614751565b61ffff16602084015290506138908382614761565b6001600160801b0316604084015290506138aa8382614771565b6001600160a01b031660608401529050602a81146138f7576040805162461bcd60e51b8152602060048201526005602482015264072647031360dc1b604482015290519081900360640190fd5b50919050565b600160008051602061592c83398151915255565b82516000906009900615613954576040805162461bcd60e51b8152602060048201526005602482015264666373313160d81b604482015290519081900360640190fd5b50600c5483517fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470916001600160401b03808216600160801b9092041601906020868101918291908801016000805b82851015613e7557845160f81c60058160078111156139bd57fe5b14156139cf5760129590950194613e6f565b60008160078111156139dd57fe5b14156139ef5760099590950194613e6f565b60028160078111156139fd57fe5b1415613a0f5760369590950194613e6f565b8486036001826007811115613a2057fe5b1415613a93576060613a378d600184016035614781565b9050613a4161579c565b613a4a82613853565b9050613a568f8261482b565b613a5e6158b9565b50604080518082019091526001815260208101839052613a7e818c6148b5565b50506001909801975060369690960195613e6d565b6003826007811115613aa157fe5b1415613b2b57613aaf6158d1565b613abc8d83600101614ab6565b604080820151825160209384015183518086019f909f5260018f8501526001600160a01b0390921660608f015261ffff1660808e01526001600160801b031660a0808e01919091528151808e03909101815260c0909c0190528a519a0199909920985060369690960195613e6d565b6006826007811115613b3957fe5b1415613c37576060613b508d600184016035614781565b9050613b5a61579c565b613b6382614b12565b9050613b6f8f82614bb6565b60008090508b818360200151846040015185606001516040516020018086815260200185151515158152602001846001600160a01b03166001600160a01b031681526020018361ffff1661ffff168152602001826001600160801b03166001600160801b0316815260200195505050505050604051602081830303815290604052805190602001209b50613c016158b9565b50604080518082019091526006815260208101849052613c21818d6148b5565b5050600190990198505060369690960195613e6d565b6007826007811115613c4557fe5b1415613e385789518361ffff1610613c8c576040805162461bcd60e51b8152602060048201526005602482015264666373313360d81b604482015290519081900360640190fd5b613c9461579c565b613ca18d83600101614c40565b90508a8461ffff1681518110613cb357fe5b602002602001015163ffffffff16600014613d5f576060613cfb8d876001600160401b03168e8861ffff1681518110613ce857fe5b602002602001015163ffffffff16614781565b90506000613d1c828460200151856060015186604001518760000151614cb0565b905080613d58576040805162461bcd60e51b8152602060048201526005602482015264667070313560d81b604482015290519081900360640190fd5b5050613dfc565b602080820151604080516001600160601b0319909216828401528051808303601401815260349092018152815191830191909120818401516001600160a01b03166000908152600a8452828120606086015163ffffffff1682529093529120541480613dfa576040805162461bcd60e51b8152602060048201526005602482015264333838189b60d91b604482015290519081900360640190fd5b505b8a8461ffff1681518110613e0c57fe5b602002602001015163ffffffff16850194508380600101945050600960060260ff168801975050613e6d565b6040805162461bcd60e51b8152602060048201526005602482015264199c1c0c4d60da1b604482015290519081900360640190fd5b505b506139a2565b828514613eb1576040805162461bcd60e51b81526020600482015260056024820152643331b9989960d91b604482015290519081900360640190fd5b8851826001600160401b031614613ef7576040805162461bcd60e51b81526020600482015260056024820152641998dccc4d60da1b604482015290519081900360640190fd5b87518161ffff1614613f38576040805162461bcd60e51b8152602060048201526005602482015264666373313560d81b604482015290519081900360640190fd5b600c546001600160401b03808216600160401b90920481169190910181169087161115613f94576040805162461bcd60e51b81526020600482015260056024820152643331b9989b60d91b604482015290519081900360640190fd5b5050600c80546001600160401b03808216909603909516600160801b0267ffffffffffffffff60801b199095169490941790935550919695505050505050565b82516009900615614014576040805162461bcd60e51b8152602060048201526005602482015264063626231360dc1b604482015290519081900360640190fd5b82516002546040805163e54ee6b160e01b815263ffffffff6009909404938416600482015290516001600160a01b039092169163e54ee6b191602480820192602092909190829003018186803b15801561406d57600080fd5b505afa158015614081573d6000803e3d6000fd5b505050506040513d602081101561409757600080fd5b50516140d2576040805162461bcd60e51b8152602060048201526005602482015264636362313160d81b604482015290519081900360640190fd5b63ffffffff6000198801166000908152600760205260408120600301546140fe90899089908989614ecc565b6040805160c0810182524363ffffffff90811682526001600160401b03968716602080840191825296821683850190815260608401998a526080840195865260a084019b8c529c821660009081526007909752929095209051815492519b5163ffffffff19909316908616176bffffffffffffffff000000001916600160201b9b9096169a909a029490941763ffffffff60601b1916600160601b94909316939093029190911787555090516001860155516002850155505160039092019190915550565b60008163ffffffff168363ffffffff161061384a578161384c565b6040516000906127109082906001600160a01b038616908390869084818181858888f193505050503d8060008114614232576040519150601f19603f3d011682016040523d82523d6000602084013e614237565b606091505b50909695505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485946060948a16939092909182918083835b602083106142c25780518252601f1990920191602091820191016142a3565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614324576040519150601f19603f3d011682016040523d82523d6000602084013e614329565b606091505b50915091506000815160001480614353575081806020019051602081101561435057600080fd5b50515b905082801561435f5750805b979650505050505050565b600061384c83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061511c565b60065460009063ffffffff600160401b82048116600160601b909204161180156143fb5750600654600163ffffffff600160401b90920482160181166000908152600760205260409020541615155b801561442c5750600654600160401b900463ffffffff90811660010181166000908152600760205260409020541643115b905090565b600061443d82856132c2565b6001600160501b031981166000908152600460205260409020549091506001600160801b0316614473818563ffffffff6151b316565b6001600160501b0319831660009081526004602090815260409182902080546001600160801b0319166001600160801b0394851617905581519287168352905161ffff8816926001600160a01b038716927f3ac065a1e69cd78fa12ba7269660a2894da2ec7f1ff1135ed5ca04de4b4e389e92918290030190a35050505050565b60008282016001600160801b03808516908216101561384c576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1781529251825160009485946060948b16939092909182918083835b602083106145e15780518252601f1990920191602091820191016145c2565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614643576040519150601f19603f3d011682016040523d82523d6000602084013e614648565b606091505b50915091506000815160001480614672575081806020019051602081101561466f57600080fd5b50515b90508280156124095750979650505050505050565b60008080808461469787826151f5565b955090506146a58782614771565b945090506146b38782614751565b935090506146c18782614761565b9598949750929550505050565b602081810151604080840151606094850151825160009581019590955260f09390931b6001600160f01b031916602485015260801b6001600160801b0319166026840152921b6001600160601b03191660368201528151808203602a018152604a90910190915290565b6004810160006147488484615221565b90509250929050565b6002810160006147488484615273565b60108101600061474884846152ba565b6014810160006147488484615301565b6060818301845110156147c3576040805162461bcd60e51b8152602060048201526005602482015264627365313160d81b604482015290519081900360640190fd5b6060826040519080825280601f01601f1916602001820160405280156147f0576020820181803883390190505b509050821561482357602081018381016020860187015b8183101561481f578051835260209283019201614807565b5050505b949350505050565b806020015161ffff16816000015163ffffffff168363ffffffff167fc4e73a5b67a0594d06ea2b5c311c2aa44aa340dd4dd9ec5a1a718dc391b644708460600151856040015160405180836001600160a01b03166001600160a01b03168152602001826001600160801b03166001600160801b031681526020019250505060405180910390a45050565b6001600160401b0381166000908152600b60209081526040918290208054600191820180548551600261010095831615959095026000190190911693909304601f810185900485028401850190955284835260ff909116936060938301828280156149615780601f1061493657610100808354040283529160200191614961565b820191906000526020600020905b81548152906001019060200180831161494457829003601f168201915b505050505090508360000151600781111561497857fe5b82600781111561498457fe5b146149be576040805162461bcd60e51b8152602060048201526005602482015264373b38189960d91b604482015290519081900360640190fd5b6001845160078111156149cd57fe5b1415614a1f576149e1818560200151615348565b614a1a576040805162461bcd60e51b8152602060048201526005602482015264766e70313360d81b604482015290519081900360640190fd5b614ab0565b600684516007811115614a2e57fe5b1415614a7b57614a42818560200151615387565b614a1a576040805162461bcd60e51b81526020600482015260056024820152641d9b9c0c4d60da1b604482015290519081900360640190fd5b6040805162461bcd60e51b8152602060048201526005602482015264766e70313560d81b604482015290519081900360640190fd5b50505050565b614abe6158d1565b60048201614acc8482614751565b61ffff1683529050614ade8482614761565b6001600160801b031660208401526002019050614afb8482614771565b6001600160a01b0316604084015250909392505050565b614b1a61579c565b6000614b268382614738565b63ffffffff1683529050614b3a8382614771565b6001600160a01b031660208401529050614b548382614751565b61ffff1660408401529050614b698382614761565b6001600160801b031660608401529050602a81146138f7576040805162461bcd60e51b8152602060048201526005602482015264072667031360dc1b604482015290519081900360640190fd5b806040015161ffff16816000015163ffffffff168363ffffffff167f66fc63d751ecbefca61d4e2e7c534e4f29c61aed8ece23ed635277a7ea6f9bc48460200151856060015160405180836001600160a01b03166001600160a01b03168152602001826001600160801b03166001600160801b031681526020019250505060405180910390a45050565b614c4861579c565b81614c538482614738565b63ffffffff1683529050614c6784826153b0565b6001600160601b03191660208401529050614c828482614771565b6001600160a01b031660408401529050614c9c8482614738565b63ffffffff16606084015250909392505050565b604080516001600160601b031986166020820152815180820360140181526034909101909152600090606090614ce5906153c0565b614cf6614cf18761546a565b6153c0565b614d02614cf18661546a565b60405160200180807f19457468657265756d205369676e6564204d6573736167653a0a313532000000815250601d01807f5265676973746572207a6b53796e63207075626b65793a0a0a0000000000000081525060190184805190602001908083835b60208310614d845780518252601f199092019160209182019101614d65565b51815160209384036101000a6000190180199092169116179052600560f91b91909301908152680dcdedcc6ca744060f60bb1b60018201528551600a90910192860191508083835b60208310614deb5780518252601f199092019160209182019101614dcc565b51815160209384036101000a6000190180199092169116179052600560f91b919093019081526d0c2c6c6deeadce840d2c8744060f60931b60018201528451600f90910192850191508083835b60208310614e575780518252601f199092019160209182019101614e38565b5181516020939093036101000a600019018019909116921691909117905261050560f11b920191825250600201602c6159738239602c01935050505060405160208183030381529060405290506000614eb08883615483565b6001600160a01b03908116908616149250505095945050505050565b60008060028763ffffffff168763ffffffff1660405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310614f345780518252601f199092019160209182019101614f15565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015614f73573d6000803e3d6000fd5b5050506040513d6020811015614f8857600080fd5b5051604080516020818101849052818301899052825180830384018152606090920192839052815193945060029391929182918401908083835b60208310614fe15780518252601f199092019160209182019101614fc2565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015615020573d6000803e3d6000fd5b5050506040513d602081101561503557600080fd5b5051604080516020818101849052818301889052825180830384018152606090920192839052815193945060029391929182918401908083835b6020831061508e5780518252601f19909201916020918201910161506f565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa1580156150cd573d6000803e3d6000fd5b5050506040513d60208110156150e257600080fd5b50516040518451828652919250906020828282018760025afa81865280801561510a5761510c565bfe5b5050905198975050505050505050565b600081848411156151ab5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015615170578181015183820152602001615158565b50505050905090810190601f16801561519d5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600061384c83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061557f565b60008082600101915083838151811061520a57fe5b0160200151919460f89290921c1515935090915050565b6000808260040190508084511015615268576040805162461bcd60e51b8152602060048201526005602482015264189d1d4c0d60da1b604482015290519081900360640190fd5b929092015192915050565b6000808260020190508084511015615268576040805162461bcd60e51b8152602060048201526005602482015264313a3a981960d91b604482015290519081900360640190fd5b6000808260100190508084511015615268576040805162461bcd60e51b8152602060048201526005602482015264313a3a989b60d91b604482015290519081900360640190fd5b6000808260140190508084511015615268576040805162461bcd60e51b8152602060048201526005602482015264627461313160d81b604482015290519081900360640190fd5b600060606153598460046026614781565b9050606061536a8460046026614781565b905080805190602001208280519060200120149250505092915050565b60008061539584601a6155e4565b905060006153a484601a6155e4565b91909114949350505050565b6014810160006147488484615672565b60608082516002026040519080825280601f01601f1916602001820160405280156153f2576020820181803883390190505b5090506020830183518101602083015b8183101561546057825160f81c6f6665646362613938373635343332313060088260041c021c60f81b82526f66656463626139383736353433323130600882600f16021c60f81b600183015250600183019250600281019050615402565b5091949350505050565b606061547d8263ffffffff1660046156be565b92915050565b600082516041146154c3576040805162461bcd60e51b8152602060048201526005602482015264076657331360dc1b604482015290519081900360640190fd5b600080806154d1868261574a565b935090506154df868261574a565b809350819250505060008682815181106154f557fe5b602001015160f81c60f81b60f81c90506001868051906020012082868660405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015615569573d6000803e3d6000fd5b5050604051601f19015198975050505050505050565b6000836001600160801b0316836001600160801b0316111582906151ab5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315615170578181015183820152602001615158565b60006020821115615624576040805162461bcd60e51b8152602060048201526005602482015264074726d31360dc1b604482015290519081900360640190fd5b8183511015615662576040805162461bcd60e51b815260206004820152600560248201526474726d313160d81b604482015290519081900360640190fd5b5060209182015191036008021c90565b600081601401835110156156b5576040805162461bcd60e51b8152602060048201526005602482015264062746232360dc1b604482015290519081900360640190fd5b50016020015190565b606060208260ff161115615701576040805162461bcd60e51b8152602060048201526005602482015264627432313160d81b604482015290519081900360640190fd5b8160ff166040519080825280601f01601f19166020018201604052801561572f576020820181803883390190505b5060ff6008602094850302169390931b918301919091525090565b60208101600061474884846000808260200190508084511015615268576040805162461bcd60e51b8152602060048201526005602482015264313a31199960d91b604482015290519081900360640190fd5b60408051608081018252600080825260208201819052918101829052606081019190915290565b50805460018160011615610100020316600290046000825580601f106157e95750615807565b601f01602090049060005260206000209081019061580791906158f1565b50565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061588057805160ff19168380011785556158ad565b828001600101855582156158ad579182015b828111156158ad578251825591602001919060010190615892565b5061211f9291506158f1565b60408051808201909152600081526060602082015290565b604080516060810182526000808252602082018190529181019190915290565b6112b091905b8082111561211f57600081556001016158f756fe5265656e7472616e637947756172643a207265656e7472616e742063616c6c008e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf453616665436173743a2076616c756520646f65736e27742066697420696e2031323820626974734f6e6c79207369676e2074686973206d65737361676520666f722061207472757374656420636c69656e7421a265627a7a72315820a71825d1c66a9c01cb73565bea646b85c86cee11d9eaa152a0ca2e5c5691721a64736f6c63430005100032

Deployed Bytecode

0x6080604052600436106102385760003560e01c80636b27a0441161012e578063b269b9ae116100ab578063d6973fc61161006f578063d6973fc614610be8578063e17376b514610c89578063fa6b53c314610cdb578063faf4d8cb14610d18578063ffeec23714610d2d57610238565b8063b269b9ae146109d5578063c488a09c14610b49578063c57b22be14610b7c578063c94c5b7c14610b91578063cd24ee0814610bd357610238565b80638ae20dc9116100f25780638ae20dc9146109ff578063922e149214610a3e5780639a83400d14610a53578063a2f9f1ce14610ac3578063a6289e5a14610b1957610238565b80636b27a044146108e457806378b91e70146108f95780637d4907981461090e578063871b8ff1146109d55780638773334c146109ea57610238565b806334f6bb1c116101bc5780634e913cd9116101805780634e913cd914610626578063595a5ebc146107a75780635cd0783e1461082857806367708dae1461089f5780636a387fc9146108b457610238565b806334f6bb1c146104f75780633b154b73146105285780633c06e5141461053d5780633c6461a914610552578063439fab91146105ab57610238565b80632a3174f4116102035780632a3174f4146104215780632b8c062a146104365780632d24006c146104705780632d2da8061461049e5780632f804bd2146104c457610238565b8060e21461023d5780630231c02c1461027e57806321ae605414610356578063253946451461037d578063264c0912146103f8575b600080fd5b34801561024957600080fd5b5061027c6004803603604081101561026057600080fd5b50803563ffffffff1690602001356001600160a01b0316610d42565b005b34801561028a57600080fd5b5061027c600480360360608110156102a157600080fd5b63ffffffff8235169190810190604081016020820135600160201b8111156102c857600080fd5b8201836020820111156102da57600080fd5b803590602001918460208302840111600160201b831117156102fb57600080fd5b919390929091602081019035600160201b81111561031857600080fd5b82018360208201111561032a57600080fd5b803590602001918460018302840111600160201b8311171561034b57600080fd5b509092509050610f36565b34801561036257600080fd5b5061036b61127a565b60408051918252519081900360200190f35b34801561038957600080fd5b5061027c600480360360208110156103a057600080fd5b810190602081018135600160201b8111156103ba57600080fd5b8201836020820111156103cc57600080fd5b803590602001918460018302840111600160201b831117156103ed57600080fd5b50909250905061129e565b34801561040457600080fd5b5061040d6112a2565b604080519115158252519081900360200190f35b34801561042d57600080fd5b5061036b6112ab565b34801561044257600080fd5b5061040d6004803603604081101561045957600080fd5b50803563ffffffff16906020013561ffff166112b3565b34801561047c57600080fd5b506104856112d3565b6040805163ffffffff9092168252519081900360200190f35b61027c600480360360208110156104b457600080fd5b50356001600160a01b03166112e6565b3480156104d057600080fd5b5061027c600480360360208110156104e757600080fd5b50356001600160401b031661137a565b34801561050357600080fd5b5061050c6116a7565b604080516001600160401b039092168252519081900360200190f35b34801561053457600080fd5b5061027c6116bd565b34801561054957600080fd5b506104856116bf565b34801561055e57600080fd5b506105866004803603602081101561057557600080fd5b50356001600160501b0319166116d2565b604080516001600160801b03909316835260ff90911660208301528051918290030190f35b3480156105b757600080fd5b5061027c600480360360208110156105ce57600080fd5b810190602081018135600160201b8111156105e857600080fd5b8201836020820111156105fa57600080fd5b803590602001918460018302840111600160201b8311171561061b57600080fd5b5090925090506116f9565b34801561063257600080fd5b5061027c600480360360c081101561064957600080fd5b63ffffffff8235811692602081013590911691810190606081016040820135600160201b81111561067957600080fd5b82018360208201111561068b57600080fd5b803590602001918460208302840111600160201b831117156106ac57600080fd5b919390929091602081019035600160201b8111156106c957600080fd5b8201836020820111156106db57600080fd5b803590602001918460018302840111600160201b831117156106fc57600080fd5b919390929091602081019035600160201b81111561071957600080fd5b82018360208201111561072b57600080fd5b803590602001918460018302840111600160201b8311171561074c57600080fd5b919390929091602081019035600160201b81111561076957600080fd5b82018360208201111561077b57600080fd5b803590602001918460208302840111600160201b8311171561079c57600080fd5b509092509050611780565b3480156107b357600080fd5b5061027c600480360360408110156107ca57600080fd5b810190602081018135600160201b8111156107e457600080fd5b8201836020820111156107f657600080fd5b803590602001918460018302840111600160201b8311171561081757600080fd5b91935091503563ffffffff16611a88565b34801561083457600080fd5b506108586004803603602081101561084b57600080fd5b503563ffffffff16611c3f565b6040805163ffffffff97881681526001600160401b03909616602087015293909516848401526060840191909152608083015260a082019290925290519081900360c00190f35b3480156108ab57600080fd5b5061050c611c88565b3480156108c057600080fd5b5061027c600480360360208110156108d757600080fd5b503563ffffffff16611c97565b3480156108f057600080fd5b5061040d612077565b34801561090557600080fd5b5061027c612123565b34801561091a57600080fd5b506109416004803603602081101561093157600080fd5b50356001600160401b0316612138565b6040518084600781111561095157fe5b60ff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b83811015610998578181015183820152602001610980565b50505050905090810190601f1680156109c55780820380516001836020036101000a031916815260200191505b5094505050505060405180910390f35b3480156109e157600080fd5b5061027c6121ec565b3480156109f657600080fd5b5061040d6121fb565b348015610a0b57600080fd5b5061036b60048036036040811015610a2257600080fd5b5080356001600160a01b0316906020013563ffffffff16612205565b348015610a4a57600080fd5b5061040d612222565b348015610a5f57600080fd5b50610aa760048036036080811015610a7657600080fd5b506001600160a01b0381358116916020810135909116906001600160801b036040820135811691606001351661222b565b604080516001600160801b039092168252519081900360200190f35b348015610acf57600080fd5b50610af360048036036020811015610ae657600080fd5b503563ffffffff16612415565b604080516001600160a01b03909316835261ffff90911660208301528051918290030190f35b348015610b2557600080fd5b5061027c60048036036020811015610b3c57600080fd5b503563ffffffff1661243d565b348015610b5557600080fd5b5061027c60048036036020811015610b6c57600080fd5b50356001600160801b031661275c565b348015610b8857600080fd5b5061050c612866565b348015610b9d57600080fd5b5061027c60048036036040811015610bb457600080fd5b5080356001600160a01b031690602001356001600160801b031661287c565b348015610bdf57600080fd5b50610485612a3e565b348015610bf457600080fd5b5061027c60048036036080811015610c0b57600080fd5b63ffffffff8235169161ffff602082013516916001600160801b036040830135169190810190608081016060820135600160201b811115610c4b57600080fd5b820183602082011115610c5d57600080fd5b803590602001918460208302840111600160201b83111715610c7e57600080fd5b509092509050612a4a565b348015610c9557600080fd5b5061027c60048036036060811015610cac57600080fd5b506001600160a01b0381358116916cffffffffffffffffffffffffff6020820135169160409091013516612d55565b348015610ce757600080fd5b50610aa760048036036040811015610cfe57600080fd5b5080356001600160a01b0316906020013561ffff16612fd6565b348015610d2457600080fd5b50610485613011565b348015610d3957600080fd5b5061036b613024565b60008051602061592c8339815191525480610d92576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c83398151915255610dac61302a565b62ffffff63ffffffff84161115610df2576040805162461bcd60e51b8152602060048201526005602482015264666565313160d81b604482015290519081900360640190fd5b60006001600160a01b038316610e0a57506000610e86565b600354604080516375698bb160e11b81526001600160a01b0386811660048301529151919092169163ead31762916024808301926020929190829003018186803b158015610e5757600080fd5b505afa158015610e6b573d6000803e3d6000fd5b505050506040513d6020811015610e8157600080fd5b505190505b610e8e61579c565b60405180608001604052808663ffffffff168152602001336001600160a01b031681526020018361ffff16815260200160006001600160801b031681525090506060610ed98261306a565b9050610ee66006826130ff565b6000610ef233856132c2565b6001600160501b0319166000908152600460205260409020805460ff60801b191660ff60801b1790555050600160008051602061592c833981519152555050505050565b60008051602061592c8339815191525480610f86576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c83398151915255610fa061302a565b600660089054906101000a900463ffffffff1660010163ffffffff168663ffffffff1614610ffd576040805162461bcd60e51b815260206004820152600560248201526466766b313160d81b604482015290519081900360640190fd5b60035460408051634b18bd0f60e01b815233600482015290516001600160a01b0390921691634b18bd0f91602480820192600092909190829003018186803b15801561104857600080fd5b505afa15801561105c573d6000803e3d6000fd5b50506002805463ffffffff808b166000908152600760209081526040918290209485015494549151633711baa560e21b815260248101869052600160601b90920490921660448201819052606060048301908152606483018c90526001600160a01b03909416965063dc46ea9495508b948b949093919290918291608401908790870280828437600081840152601f19601f8201169050808301925050509550505050505060206040518083038186803b15801561111957600080fd5b505afa15801561112d573d6000803e3d6000fd5b505050506040513d602081101561114357600080fd5b505161117e576040805162461bcd60e51b815260206004820152600560248201526466766b313360d81b604482015290519081900360640190fd5b6111d383838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525063ffffffff8c1681526007602052604090206001015492506132df915050565b63ffffffff861660009081526007602052604090205461120290600160201b90046001600160401b03166135ee565b6006805463ffffffff600160401b80830482166001018216026bffffffff00000000000000001990921691909117909155604051908716907f0cdbd8bd7813095001c5fe7917bd69d834dc01db7c1dfcf52ca135bd2038441390600090a2600160008051602061592c83398151915255505050505050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081565b5050565b60095460ff1681565b620a8c005b90565b600860209081526000928352604080842090915290825290205460ff1681565b600654600160401b900463ffffffff1681565b60008051602061592c8339815191525480611336576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c8339815191525561135061302a565b611364600061135e3461372e565b84613772565b600160008051602061592c833981519152555050565b60008051602061592c83398151915254806113ca576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c8339815191525560095460ff1661141b576040805162461bcd60e51b8152602060048201526005602482015264636f65303160d81b604482015290519081900360640190fd5b600c5460009061143b90600160401b90046001600160401b031684613829565b90506000816001600160401b031611611483576040805162461bcd60e51b815260206004820152600560248201526431b7b2981960d91b604482015290519081900360640190fd5b600c546001600160401b03165b600c546001600160401b039081168301811690821610156116475760016001600160401b0382166000908152600b602052604090205460ff1660078111156114d457fe5b1415611607576114e261579c565b6115ab600b6000846001600160401b03166001600160401b031681526020019081526020016000206001018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156115a15780601f10611576576101008083540402835291602001916115a1565b820191906000526020600020905b81548152906001019060200180831161158457829003601f168201915b5050505050613853565b905060006115c1826060015183602001516132c2565b6040928301516001600160501b031991909116600090815260046020529290922080546001600160801b031981166001600160801b039182169094011692909217909155505b6001600160401b0381166000908152600b60205260408120805460ff191681559061163560018301826157c3565b50600060029190910155600101611490565b50600c805467ffffffffffffffff60401b1967ffffffffffffffff1982166001600160401b039283168501831617908116600160401b91829004831694909403909116029190911790555050600160008051602061592c83398151915255565b600c54600160801b90046001600160401b031681565b565b600654600160201b900463ffffffff1681565b6004602052600090815260409020546001600160801b03811690600160801b900460ff1682565b6117016138fd565b60008060008484606081101561171657600080fd5b50600280546001600160a01b0360208481013582166001600160a01b031993841617909355600380548535909216919092161790556000805260079052604001357f6d5257204ebe7d88fd91ae87941cb2dd9d8062b64ae5a2bd2d28ec40b9fbf6e2555050505050565b60008051602061592c83398151915254806117d0576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c833981519152556117ea61302a565b6006600c9054906101000a900463ffffffff1660010163ffffffff168b63ffffffff1614611847576040805162461bcd60e51b815260206004820152600560248201526466636b313160d81b604482015290519081900360640190fd5b60035460408051634b18bd0f60e01b815233600482015290516001600160a01b0390921691634b18bd0f91602480820192600092909190829003018186803b15801561189257600080fd5b505afa1580156118a6573d6000803e3d6000fd5b5050506001891490506118e8576040805162461bcd60e51b815260206004820152600560248201526466636b313360d81b604482015290519081900360640190fd5b606087878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505090506000600c60109054906101000a90046001600160401b0316905060006119bf8e848a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c91829185019084908082843760009201919091525061391192505050565b600c54909150600160801b90046001600160401b03168290036119f78f8f8f8f6000816119e857fe5b90506020020135878686613fd4565b6006600c81819054906101000a900463ffffffff168092919060010191906101000a81548163ffffffff021916908363ffffffff160217905550508e63ffffffff167f81a92942d0f9c33b897a438384c9c3d88be397776138efa3ba1a4fc8b626842460405160405180910390a250505050600160008051602061592c833981519152555050505050505050505050565b60008051602061592c8339815191525480611ad8576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c8339815191525560148314611b27576040805162461bcd60e51b8152602060048201526005602482015264061686631360dc1b604482015290519081900360640190fd5b336000908152600a6020908152604080832063ffffffff8616845290915290205415611b82576040805162461bcd60e51b8152602060048201526005602482015264616866313160d81b604482015290519081900360640190fd5b83836040518083838082843760408051919093018190038120336000818152600a602090815286822063ffffffff8d16808452908252918790209390935583529082018481529382018a905295507f9ea39b45a0cc96a2139996ec8dd30326216111249750781e563ae27c31ae87669450879350899289925060608201848480828437600083820152604051601f909101601f1916909201829003965090945050505050a2600160008051602061592c8339815191525550505050565b600760205260009081526040902080546001820154600283015460039093015463ffffffff808416946001600160401b03600160201b86041694600160601b9004909116929186565b600c546001600160401b031681565b60008051602061592c8339815191525480611ce7576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c833981519152556000611d1783600660049054906101000a900463ffffffff166141c3565b60068054600160201b80820463ffffffff908116859003811690910267ffffffff00000000198316178082168501821663ffffffff199091161790925591925016805b82820163ffffffff168163ffffffff16101561200d5763ffffffff8116600090815260056020526040812080546001600160b01b0319811690915561ffff600160a01b820416916001600160a01b0390911690611db782846132c2565b6001600160501b031981166000908152600460205260409020549091506001600160801b03168015611ffe576001600160501b03198216600090815260046020526040812080546001600160801b03808216859003166001600160801b031990911617905561ffff8516611e415783611e39816001600160801b0385166141de565b915050611fbe565b600354604080516310603dad60e01b815261ffff8816600482015290516000926001600160a01b0316916310603dad916024808301926020929190829003018186803b158015611e9057600080fd5b505afa158015611ea4573d6000803e3d6000fd5b505050506040513d6020811015611eba57600080fd5b5051604080516001600160a01b038084166024830152881660448201526001600160801b038616606482018190526084808301919091528251808303909101815260a490910182526020810180516001600160e01b0316639a83400d60e01b1781529151815193945030936203d0909382918083835b60208310611f4f5780518252601f199092019160209182019101611f30565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038160008787f1925050503d8060008114611fb2576040519150601f19603f3d011682016040523d82523d6000602084013e611fb7565b606091505b5090925050505b80611ffc576001600160501b03198316600090815260046020526040902080546001600160801b038082168501166001600160801b03199091161790555b505b50505050806001019050611d5a565b5063ffffffff82161561205f576040805163ffffffff808416825284840116602082015281517f9b5478c99b5ca41beec4f6f6084126d6f9e26382d017b4bb67c37c9e8453a313929181900390910190a15b5050600160008051602061592c833981519152555050565b600c546001600160401b03166000908152600b6020526040812060020154819043108015906120c25750600c546001600160401b03166000908152600b602052604090206002015415155b905080156121155760095460ff1661210b576009805460ff191660011790556040517fc71028c67eb0ef128ea270a59a674629e767d51c1af44ed6753fd2fad2c7b67790600090a15b60019150506112b0565b60009150506112b0565b5090565b6000805460ff19166001908117909155429055565b600b602090815260009182526040918290208054600180830180548651600261010094831615949094026000190190911692909204601f810186900486028301860190965285825260ff9092169492939092908301828280156121dc5780601f106121b1576101008083540402835291602001916121dc565b820191906000526020600020905b8154815290600101906020018083116121bf57829003601f168201915b5050505050908060020154905083565b6000805460ff19168155600155565b60095460ff161590565b600a60209081526000928352604080842090915290825290205481565b60005460ff1681565b6000333014612269576040805162461bcd60e51b8152602060048201526005602482015264077746731360dc1b604482015290519081900360640190fd5b604080516370a0823160e01b815230600482015290516000916001600160a01b038816916370a0823191602480820192602092909190829003018186803b1580156122b357600080fd5b505afa1580156122c7573d6000803e3d6000fd5b505050506040513d60208110156122dd57600080fd5b505190506122f586866001600160801b038716614243565b61232e576040805162461bcd60e51b8152602060048201526005602482015264777467313160d81b604482015290519081900360640190fd5b604080516370a0823160e01b815230600482015290516000916001600160a01b038916916370a0823191602480820192602092909190829003018186803b15801561237857600080fd5b505afa15801561238c573d6000803e3d6000fd5b505050506040513d60208110156123a257600080fd5b5051905060006123b8838363ffffffff61436a16565b9050846001600160801b0316811115612400576040805162461bcd60e51b81526020600482015260056024820152643bba33989960d91b604482015290519081900360640190fd5b6124098161372e565b98975050505050505050565b6005602052600090815260409020546001600160a01b03811690600160a01b900461ffff1682565b60008051602061592c833981519152548061248d576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c833981519152556124a76143ac565b6124e0576040805162461bcd60e51b8152602060048201526005602482015264726273313160d81b604482015290519081900360640190fd5b60035460408051634b18bd0f60e01b815233600482015290516001600160a01b0390921691634b18bd0f91602480820192600092909190829003018186803b15801561252b57600080fd5b505afa15801561253f573d6000803e3d6000fd5b505060065463ffffffff600160601b8204811693506000925061256e918691600160401b9091041684036141c3565b600654909150600090600160601b900463ffffffff168290036001015b8363ffffffff168163ffffffff161161269d576125a661580a565b5063ffffffff808216600090815260076020908152604091829020825160c08101845281548086168083526001600160401b03600160201b83041694830194909452600160601b900490941692840192909252600182015460608401526002820154608084015260039091015460a0830152612651576040805162461bcd60e51b815260206004820152600560248201526466726b313160d81b604482015290519081900360640190fd5b60209081015163ffffffff8316600090815260079092526040822080546001600160801b031916815560018082018490556002820184905560039091019290925592909201910161258b565b506006805463ffffffff600160601b808304821686900382160263ffffffff60601b199092169190911791829055600c80546001600160401b03600160801b80830482168790039091160267ffffffffffffffff60801b1990911617905560408051600160401b90930482168352948490039081166020830152845190947f6f3a8259cce1ea2680115053d21c971aa1764295a45850f520525f2bfdf3c9d3928290030190a1505050600160008051602061592c833981519152555050565b60008051602061592c83398151915254806127ac576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c833981519152556127ca60008333614431565b604051600090339084908381818185875af1925050503d806000811461280c576040519150601f19603f3d011682016040523d82523d6000602084013e612811565b606091505b505090508061284f576040805162461bcd60e51b8152602060048201526005602482015264667765313160d81b604482015290519081900360640190fd5b50600160008051602061592c833981519152555050565b600c54600160401b90046001600160401b031681565b60008051602061592c83398151915254806128cc576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c833981519152819055600354604080516375698bb160e11b81526001600160a01b0387811660048301529151919092169163ead31762916024808301926020929190829003018186803b15801561292d57600080fd5b505afa158015612941573d6000803e3d6000fd5b505050506040513d602081101561295757600080fd5b50519050600061296733836132c2565b6001600160501b031981166000908152600460208181526040808420548151639a83400d60e01b81526001600160a01b038c16948101949094523360248501526001600160801b038a8116604486015216606484018190529051949550933092639a83400d92608480830193919282900301818787803b1580156129ea57600080fd5b505af11580156129fe573d6000803e3d6000fd5b505050506040513d6020811015612a1457600080fd5b50519050612a23848233614431565b50505050600160008051602061592c83398151915255505050565b60065463ffffffff1681565b60008051602061592c8339815191525480612a9a576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c833981519152556000612ab833876132c2565b60095490915060ff16612afa576040805162461bcd60e51b8152602060048201526005602482015264666574313160d81b604482015290519081900360640190fd5b63ffffffff8716600090815260086020908152604080832061ffff8a16845290915290205460ff1615612b5c576040805162461bcd60e51b81526020600482015260056024820152643332ba189960d91b604482015290519081900360640190fd5b60025460065463ffffffff600160401b909104811660009081526007602090815260409182902060030154915163c81a27ad60e01b815260048101838152938c166024820152336044820181905261ffff8c1660648301526001600160801b038b16608483015260c060a4830190815260c483018a90526001600160a01b039096169563c81a27ad958e9492938e938e938e938e93909260e4909101908590850280828437600081840152601f19601f8201169050808301925050509850505050505050505060206040518083038186803b158015612c3a57600080fd5b505afa158015612c4e573d6000803e3d6000fd5b505050506040513d6020811015612c6457600080fd5b5051612c9f576040805162461bcd60e51b8152602060048201526005602482015264666574313360d81b604482015290519081900360640190fd5b6001600160501b031981166000908152600460205260409020546001600160801b0316612cd2818763ffffffff6144f416565b6001600160501b0319909216600090815260046020908152604080832080546001600160801b03969096166001600160801b03199096169590951790945563ffffffff90991681526008895282812061ffff909816815296909752909420805460ff1916600190811790915560008051602061592c833981519152555050505050565b60008051602061592c8339815191525480612da5576040805162461bcd60e51b815260206004820152601f602482015260008051602061590c833981519152604482015290519081900360640190fd5b600060008051602061592c83398151915255612dbf61302a565b600354604080516375698bb160e11b81526001600160a01b0387811660048301529151600093929092169163ead3176291602480820192602092909190829003018186803b158015612e1057600080fd5b505afa158015612e24573d6000803e3d6000fd5b505050506040513d6020811015612e3a57600080fd5b5051604080516370a0823160e01b815230600482015290519192506000916001600160a01b038816916370a08231916024808301926020929190829003018186803b158015612e8857600080fd5b505afa158015612e9c573d6000803e3d6000fd5b505050506040513d6020811015612eb257600080fd5b50519050612ee2863330612ed46cffffffffffffffffffffffffff8a1661372e565b6001600160801b031661455a565b612f1b576040805162461bcd60e51b8152602060048201526005602482015264333218189960d91b604482015290519081900360640190fd5b604080516370a0823160e01b815230600482015290516000916001600160a01b038916916370a0823191602480820192602092909190829003018186803b158015612f6557600080fd5b505afa158015612f79573d6000803e3d6000fd5b505050506040513d6020811015612f8f57600080fd5b505190506000612fad612fa8838563ffffffff61436a16565b61372e565b9050612fba848288613772565b50505050600160008051602061592c8339815191525550505050565b600060046000612fe685856132c2565b6001600160501b03191681526020810191909152604001600020546001600160801b03169392505050565b600654600160601b900463ffffffff1681565b60015481565b60095460ff16156116bd576040805162461bcd60e51b8152602060048201526005602482015264667265313160d81b604482015290519081900360640190fd5b60608160000151826020015183604001518460600151604051602001808563ffffffff1663ffffffff1660e01b8152600401846001600160a01b03166001600160a01b031660601b81526014018361ffff1661ffff1660f01b8152600201826001600160801b03166001600160801b031660801b81526010019450505050506040516020818303038152906040529050919050565b600c5460408051606081019091524361438001916001600160401b03808216600160401b9092041601908085600781111561313657fe5b8152602080820186905260409182018590526001600160401b0384166000908152600b9091522081518154829060ff1916600183600781111561317557fe5b02179055506020828101518051613192926001850192019061583f565b50604082015181600201559050507fd0943372c08b438a88d4b39d77216901079eda9ca59d45349841c099083b6830338286868660405180866001600160a01b03166001600160a01b03168152602001856001600160401b03166001600160401b0316815260200184600781111561320657fe5b60ff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b8381101561324d578181015183820152602001613235565b50505050905090810190601f16801561327a5780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a15050600c805460016001600160401b03600160401b808404821692909201160267ffffffffffffffff60401b199091161790555050565b60a01b61ffff60a01b166001600160a01b03919091161760501b90565b60278251816132ea57fe5b0615613325576040805162461bcd60e51b8152602060048201526005602482015264706f77313160d81b604482015290519081900360640190fd5b6006547fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47090600090600160201b900463ffffffff165b8451821015613517576000806000806133748987614687565b9350935093509350600061338884846132c2565b6001600160501b03198116600090815260046020526040908190205481518083019092529192506001600160801b0390911690806133cc838663ffffffff6144f416565b6001600160801b03908116825260ff60209283018190526001600160501b0319861660009081526004845260409020845181549590940151909116600160801b0260ff60801b19939092166001600160801b0319909416939093179190911617905585156134ae576040805180820182526001600160a01b03878116825261ffff878116602080850191825260065463ffffffff9081168e011660009081526005909152949094209251835494516001600160a01b031990951692169190911761ffff60a01b1916600160a01b93909116929092029190911790556001909601955b505060408051602080820199909952941515858201526001600160a01b03909316606085015261ffff90911660808401526001600160801b031660a0808401919091528151808403909101815260c090920190528051930192909220916027919091019061335b565b838314613553576040805162461bcd60e51b81526020600482015260056024820152643837bb989960d91b604482015290519081900360640190fd5b60065463ffffffff828116600160201b90920416146135c3576006546040805163ffffffff808416600160201b9094048116840181168252928401909216602083015280517fc4faeb4e73f28a46e4a5fa2db5b89c39698816488534ab7f0717c46f0852c3669281900390910190a15b6006805463ffffffff909216600160201b0267ffffffff000000001990921691909117905550505050565b600c546001600160401b03600160401b90910481169082161115613641576040805162461bcd60e51b8152602060048201526005602482015264706373323160d81b604482015290519081900360640190fd5b600061364e826006613829565b600c549091506001600160401b0316805b8282016001600160401b0316816001600160401b031610156136bb576001600160401b0381166000908152600b60205260408120805460ff19168155906136a960018301826157c3565b5060006002919091015560010161365f565b5050600c8054600160801b6001600160401b03600160401b808404821687900382160267ffffffffffffffff60401b19909316929092178083168601831667ffffffffffffffff19909116178181048316959095039091160267ffffffffffffffff60801b199093169290921790915550565b6000600160801b821061211f5760405162461bcd60e51b815260040180806020018281038252602781526020018061594c6027913960400191505060405180910390fd5b61377a61579c565b6040518060800160405280600063ffffffff1681526020018561ffff168152602001846001600160801b03168152602001836001600160a01b0316815250905060606137c5826146ce565b90506137d26001826130ff565b604080516001600160801b038616815290516001600160a01b0385169161ffff88169133917fb6866b029f3aa29cd9e2bff8159a8ccaa4389f7a087c710968e0b200c0c73b08919081900360200190a45050505050565b6000816001600160401b0316836001600160401b03161061384a578161384c565b825b9392505050565b61385b61579c565b60006138678382614738565b63ffffffff168352905061387b8382614751565b61ffff16602084015290506138908382614761565b6001600160801b0316604084015290506138aa8382614771565b6001600160a01b031660608401529050602a81146138f7576040805162461bcd60e51b8152602060048201526005602482015264072647031360dc1b604482015290519081900360640190fd5b50919050565b600160008051602061592c83398151915255565b82516000906009900615613954576040805162461bcd60e51b8152602060048201526005602482015264666373313160d81b604482015290519081900360640190fd5b50600c5483517fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470916001600160401b03808216600160801b9092041601906020868101918291908801016000805b82851015613e7557845160f81c60058160078111156139bd57fe5b14156139cf5760129590950194613e6f565b60008160078111156139dd57fe5b14156139ef5760099590950194613e6f565b60028160078111156139fd57fe5b1415613a0f5760369590950194613e6f565b8486036001826007811115613a2057fe5b1415613a93576060613a378d600184016035614781565b9050613a4161579c565b613a4a82613853565b9050613a568f8261482b565b613a5e6158b9565b50604080518082019091526001815260208101839052613a7e818c6148b5565b50506001909801975060369690960195613e6d565b6003826007811115613aa157fe5b1415613b2b57613aaf6158d1565b613abc8d83600101614ab6565b604080820151825160209384015183518086019f909f5260018f8501526001600160a01b0390921660608f015261ffff1660808e01526001600160801b031660a0808e01919091528151808e03909101815260c0909c0190528a519a0199909920985060369690960195613e6d565b6006826007811115613b3957fe5b1415613c37576060613b508d600184016035614781565b9050613b5a61579c565b613b6382614b12565b9050613b6f8f82614bb6565b60008090508b818360200151846040015185606001516040516020018086815260200185151515158152602001846001600160a01b03166001600160a01b031681526020018361ffff1661ffff168152602001826001600160801b03166001600160801b0316815260200195505050505050604051602081830303815290604052805190602001209b50613c016158b9565b50604080518082019091526006815260208101849052613c21818d6148b5565b5050600190990198505060369690960195613e6d565b6007826007811115613c4557fe5b1415613e385789518361ffff1610613c8c576040805162461bcd60e51b8152602060048201526005602482015264666373313360d81b604482015290519081900360640190fd5b613c9461579c565b613ca18d83600101614c40565b90508a8461ffff1681518110613cb357fe5b602002602001015163ffffffff16600014613d5f576060613cfb8d876001600160401b03168e8861ffff1681518110613ce857fe5b602002602001015163ffffffff16614781565b90506000613d1c828460200151856060015186604001518760000151614cb0565b905080613d58576040805162461bcd60e51b8152602060048201526005602482015264667070313560d81b604482015290519081900360640190fd5b5050613dfc565b602080820151604080516001600160601b0319909216828401528051808303601401815260349092018152815191830191909120818401516001600160a01b03166000908152600a8452828120606086015163ffffffff1682529093529120541480613dfa576040805162461bcd60e51b8152602060048201526005602482015264333838189b60d91b604482015290519081900360640190fd5b505b8a8461ffff1681518110613e0c57fe5b602002602001015163ffffffff16850194508380600101945050600960060260ff168801975050613e6d565b6040805162461bcd60e51b8152602060048201526005602482015264199c1c0c4d60da1b604482015290519081900360640190fd5b505b506139a2565b828514613eb1576040805162461bcd60e51b81526020600482015260056024820152643331b9989960d91b604482015290519081900360640190fd5b8851826001600160401b031614613ef7576040805162461bcd60e51b81526020600482015260056024820152641998dccc4d60da1b604482015290519081900360640190fd5b87518161ffff1614613f38576040805162461bcd60e51b8152602060048201526005602482015264666373313560d81b604482015290519081900360640190fd5b600c546001600160401b03808216600160401b90920481169190910181169087161115613f94576040805162461bcd60e51b81526020600482015260056024820152643331b9989b60d91b604482015290519081900360640190fd5b5050600c80546001600160401b03808216909603909516600160801b0267ffffffffffffffff60801b199095169490941790935550919695505050505050565b82516009900615614014576040805162461bcd60e51b8152602060048201526005602482015264063626231360dc1b604482015290519081900360640190fd5b82516002546040805163e54ee6b160e01b815263ffffffff6009909404938416600482015290516001600160a01b039092169163e54ee6b191602480820192602092909190829003018186803b15801561406d57600080fd5b505afa158015614081573d6000803e3d6000fd5b505050506040513d602081101561409757600080fd5b50516140d2576040805162461bcd60e51b8152602060048201526005602482015264636362313160d81b604482015290519081900360640190fd5b63ffffffff6000198801166000908152600760205260408120600301546140fe90899089908989614ecc565b6040805160c0810182524363ffffffff90811682526001600160401b03968716602080840191825296821683850190815260608401998a526080840195865260a084019b8c529c821660009081526007909752929095209051815492519b5163ffffffff19909316908616176bffffffffffffffff000000001916600160201b9b9096169a909a029490941763ffffffff60601b1916600160601b94909316939093029190911787555090516001860155516002850155505160039092019190915550565b60008163ffffffff168363ffffffff161061384a578161384c565b6040516000906127109082906001600160a01b038616908390869084818181858888f193505050503d8060008114614232576040519150601f19603f3d011682016040523d82523d6000602084013e614237565b606091505b50909695505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485946060948a16939092909182918083835b602083106142c25780518252601f1990920191602091820191016142a3565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614324576040519150601f19603f3d011682016040523d82523d6000602084013e614329565b606091505b50915091506000815160001480614353575081806020019051602081101561435057600080fd5b50515b905082801561435f5750805b979650505050505050565b600061384c83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061511c565b60065460009063ffffffff600160401b82048116600160601b909204161180156143fb5750600654600163ffffffff600160401b90920482160181166000908152600760205260409020541615155b801561442c5750600654600160401b900463ffffffff90811660010181166000908152600760205260409020541643115b905090565b600061443d82856132c2565b6001600160501b031981166000908152600460205260409020549091506001600160801b0316614473818563ffffffff6151b316565b6001600160501b0319831660009081526004602090815260409182902080546001600160801b0319166001600160801b0394851617905581519287168352905161ffff8816926001600160a01b038716927f3ac065a1e69cd78fa12ba7269660a2894da2ec7f1ff1135ed5ca04de4b4e389e92918290030190a35050505050565b60008282016001600160801b03808516908216101561384c576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1781529251825160009485946060948b16939092909182918083835b602083106145e15780518252601f1990920191602091820191016145c2565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614643576040519150601f19603f3d011682016040523d82523d6000602084013e614648565b606091505b50915091506000815160001480614672575081806020019051602081101561466f57600080fd5b50515b90508280156124095750979650505050505050565b60008080808461469787826151f5565b955090506146a58782614771565b945090506146b38782614751565b935090506146c18782614761565b9598949750929550505050565b602081810151604080840151606094850151825160009581019590955260f09390931b6001600160f01b031916602485015260801b6001600160801b0319166026840152921b6001600160601b03191660368201528151808203602a018152604a90910190915290565b6004810160006147488484615221565b90509250929050565b6002810160006147488484615273565b60108101600061474884846152ba565b6014810160006147488484615301565b6060818301845110156147c3576040805162461bcd60e51b8152602060048201526005602482015264627365313160d81b604482015290519081900360640190fd5b6060826040519080825280601f01601f1916602001820160405280156147f0576020820181803883390190505b509050821561482357602081018381016020860187015b8183101561481f578051835260209283019201614807565b5050505b949350505050565b806020015161ffff16816000015163ffffffff168363ffffffff167fc4e73a5b67a0594d06ea2b5c311c2aa44aa340dd4dd9ec5a1a718dc391b644708460600151856040015160405180836001600160a01b03166001600160a01b03168152602001826001600160801b03166001600160801b031681526020019250505060405180910390a45050565b6001600160401b0381166000908152600b60209081526040918290208054600191820180548551600261010095831615959095026000190190911693909304601f810185900485028401850190955284835260ff909116936060938301828280156149615780601f1061493657610100808354040283529160200191614961565b820191906000526020600020905b81548152906001019060200180831161494457829003601f168201915b505050505090508360000151600781111561497857fe5b82600781111561498457fe5b146149be576040805162461bcd60e51b8152602060048201526005602482015264373b38189960d91b604482015290519081900360640190fd5b6001845160078111156149cd57fe5b1415614a1f576149e1818560200151615348565b614a1a576040805162461bcd60e51b8152602060048201526005602482015264766e70313360d81b604482015290519081900360640190fd5b614ab0565b600684516007811115614a2e57fe5b1415614a7b57614a42818560200151615387565b614a1a576040805162461bcd60e51b81526020600482015260056024820152641d9b9c0c4d60da1b604482015290519081900360640190fd5b6040805162461bcd60e51b8152602060048201526005602482015264766e70313560d81b604482015290519081900360640190fd5b50505050565b614abe6158d1565b60048201614acc8482614751565b61ffff1683529050614ade8482614761565b6001600160801b031660208401526002019050614afb8482614771565b6001600160a01b0316604084015250909392505050565b614b1a61579c565b6000614b268382614738565b63ffffffff1683529050614b3a8382614771565b6001600160a01b031660208401529050614b548382614751565b61ffff1660408401529050614b698382614761565b6001600160801b031660608401529050602a81146138f7576040805162461bcd60e51b8152602060048201526005602482015264072667031360dc1b604482015290519081900360640190fd5b806040015161ffff16816000015163ffffffff168363ffffffff167f66fc63d751ecbefca61d4e2e7c534e4f29c61aed8ece23ed635277a7ea6f9bc48460200151856060015160405180836001600160a01b03166001600160a01b03168152602001826001600160801b03166001600160801b031681526020019250505060405180910390a45050565b614c4861579c565b81614c538482614738565b63ffffffff1683529050614c6784826153b0565b6001600160601b03191660208401529050614c828482614771565b6001600160a01b031660408401529050614c9c8482614738565b63ffffffff16606084015250909392505050565b604080516001600160601b031986166020820152815180820360140181526034909101909152600090606090614ce5906153c0565b614cf6614cf18761546a565b6153c0565b614d02614cf18661546a565b60405160200180807f19457468657265756d205369676e6564204d6573736167653a0a313532000000815250601d01807f5265676973746572207a6b53796e63207075626b65793a0a0a0000000000000081525060190184805190602001908083835b60208310614d845780518252601f199092019160209182019101614d65565b51815160209384036101000a6000190180199092169116179052600560f91b91909301908152680dcdedcc6ca744060f60bb1b60018201528551600a90910192860191508083835b60208310614deb5780518252601f199092019160209182019101614dcc565b51815160209384036101000a6000190180199092169116179052600560f91b919093019081526d0c2c6c6deeadce840d2c8744060f60931b60018201528451600f90910192850191508083835b60208310614e575780518252601f199092019160209182019101614e38565b5181516020939093036101000a600019018019909116921691909117905261050560f11b920191825250600201602c6159738239602c01935050505060405160208183030381529060405290506000614eb08883615483565b6001600160a01b03908116908616149250505095945050505050565b60008060028763ffffffff168763ffffffff1660405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310614f345780518252601f199092019160209182019101614f15565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015614f73573d6000803e3d6000fd5b5050506040513d6020811015614f8857600080fd5b5051604080516020818101849052818301899052825180830384018152606090920192839052815193945060029391929182918401908083835b60208310614fe15780518252601f199092019160209182019101614fc2565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015615020573d6000803e3d6000fd5b5050506040513d602081101561503557600080fd5b5051604080516020818101849052818301889052825180830384018152606090920192839052815193945060029391929182918401908083835b6020831061508e5780518252601f19909201916020918201910161506f565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa1580156150cd573d6000803e3d6000fd5b5050506040513d60208110156150e257600080fd5b50516040518451828652919250906020828282018760025afa81865280801561510a5761510c565bfe5b5050905198975050505050505050565b600081848411156151ab5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015615170578181015183820152602001615158565b50505050905090810190601f16801561519d5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600061384c83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061557f565b60008082600101915083838151811061520a57fe5b0160200151919460f89290921c1515935090915050565b6000808260040190508084511015615268576040805162461bcd60e51b8152602060048201526005602482015264189d1d4c0d60da1b604482015290519081900360640190fd5b929092015192915050565b6000808260020190508084511015615268576040805162461bcd60e51b8152602060048201526005602482015264313a3a981960d91b604482015290519081900360640190fd5b6000808260100190508084511015615268576040805162461bcd60e51b8152602060048201526005602482015264313a3a989b60d91b604482015290519081900360640190fd5b6000808260140190508084511015615268576040805162461bcd60e51b8152602060048201526005602482015264627461313160d81b604482015290519081900360640190fd5b600060606153598460046026614781565b9050606061536a8460046026614781565b905080805190602001208280519060200120149250505092915050565b60008061539584601a6155e4565b905060006153a484601a6155e4565b91909114949350505050565b6014810160006147488484615672565b60608082516002026040519080825280601f01601f1916602001820160405280156153f2576020820181803883390190505b5090506020830183518101602083015b8183101561546057825160f81c6f6665646362613938373635343332313060088260041c021c60f81b82526f66656463626139383736353433323130600882600f16021c60f81b600183015250600183019250600281019050615402565b5091949350505050565b606061547d8263ffffffff1660046156be565b92915050565b600082516041146154c3576040805162461bcd60e51b8152602060048201526005602482015264076657331360dc1b604482015290519081900360640190fd5b600080806154d1868261574a565b935090506154df868261574a565b809350819250505060008682815181106154f557fe5b602001015160f81c60f81b60f81c90506001868051906020012082868660405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015615569573d6000803e3d6000fd5b5050604051601f19015198975050505050505050565b6000836001600160801b0316836001600160801b0316111582906151ab5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315615170578181015183820152602001615158565b60006020821115615624576040805162461bcd60e51b8152602060048201526005602482015264074726d31360dc1b604482015290519081900360640190fd5b8183511015615662576040805162461bcd60e51b815260206004820152600560248201526474726d313160d81b604482015290519081900360640190fd5b5060209182015191036008021c90565b600081601401835110156156b5576040805162461bcd60e51b8152602060048201526005602482015264062746232360dc1b604482015290519081900360640190fd5b50016020015190565b606060208260ff161115615701576040805162461bcd60e51b8152602060048201526005602482015264627432313160d81b604482015290519081900360640190fd5b8160ff166040519080825280601f01601f19166020018201604052801561572f576020820181803883390190505b5060ff6008602094850302169390931b918301919091525090565b60208101600061474884846000808260200190508084511015615268576040805162461bcd60e51b8152602060048201526005602482015264313a31199960d91b604482015290519081900360640190fd5b60408051608081018252600080825260208201819052918101829052606081019190915290565b50805460018160011615610100020316600290046000825580601f106157e95750615807565b601f01602090049060005260206000209081019061580791906158f1565b50565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061588057805160ff19168380011785556158ad565b828001600101855582156158ad579182015b828111156158ad578251825591602001919060010190615892565b5061211f9291506158f1565b60408051808201909152600081526060602082015290565b604080516060810182526000808252602082018190529181019190915290565b6112b091905b8082111561211f57600081556001016158f756fe5265656e7472616e637947756172643a207265656e7472616e742063616c6c008e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf453616665436173743a2076616c756520646f65736e27742066697420696e2031323820626974734f6e6c79207369676e2074686973206d65737361676520666f722061207472757374656420636c69656e7421a265627a7a72315820a71825d1c66a9c01cb73565bea646b85c86cee11d9eaa152a0ca2e5c5691721a64736f6c63430005100032

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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.