More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 157 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Deposit ETH | 17656535 | 556 days ago | IN | 0.0001 ETH | 0.00086374 | ||||
Deposit ETH | 17501091 | 578 days ago | IN | 0.0001 ETH | 0.00086374 | ||||
Request L2Transa... | 17016740 | 646 days ago | IN | 0.005 ETH | 0.00046166 | ||||
Deposit ETH | 17011087 | 647 days ago | IN | 0.00000099 ETH | 0.00134898 | ||||
Deposit ETH | 17004465 | 648 days ago | IN | 0.0001 ETH | 0.0012793 | ||||
Deposit ETH | 16941435 | 657 days ago | IN | 0.002 ETH | 0.00318017 | ||||
Deposit ETH | 16923535 | 659 days ago | IN | 0.005 ETH | 0.00319848 | ||||
Deposit ETH | 16921268 | 660 days ago | IN | 0.0001 ETH | 0.00195142 | ||||
Deposit ETH | 16907642 | 662 days ago | IN | 0.0000002 ETH | 0.00084231 | ||||
Deposit ETH | 16907629 | 662 days ago | IN | 0.00002 ETH | 0.00083549 | ||||
Deposit ETH | 16907622 | 662 days ago | IN | 0.0003 ETH | 0.00076771 | ||||
Deposit ETH | 16907613 | 662 days ago | IN | 1 wei | 0.00080165 | ||||
Deposit ETH | 16907588 | 662 days ago | IN | 0 ETH | 0.00034395 | ||||
Deposit ETH | 16180705 | 763 days ago | IN | 0.0000001 ETH | 0.00077332 | ||||
Deposit ETH | 16132045 | 770 days ago | IN | 0.012 ETH | 0.00085265 | ||||
Deposit ETH | 16132045 | 770 days ago | IN | 0.012 ETH | 0.00085265 | ||||
Deposit ETH | 16132045 | 770 days ago | IN | 0.012 ETH | 0.00085265 | ||||
Deposit ETH | 16132044 | 770 days ago | IN | 0.012 ETH | 0.00075886 | ||||
Deposit ETH | 16132044 | 770 days ago | IN | 0.012 ETH | 0.00075886 | ||||
Deposit ETH | 16132044 | 770 days ago | IN | 0.012 ETH | 0.00075886 | ||||
Deposit ETH | 16132044 | 770 days ago | IN | 0.012 ETH | 0.00075886 | ||||
Deposit ETH | 16132042 | 770 days ago | IN | 0.012 ETH | 0.00080255 | ||||
Deposit ETH | 16132042 | 770 days ago | IN | 0.012 ETH | 0.00080255 | ||||
Deposit ETH | 16132042 | 770 days ago | IN | 0.012 ETH | 0.00080255 | ||||
Deposit ETH | 16132041 | 770 days ago | IN | 0.012 ETH | 0.00082029 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
15365285 | 881 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
ZkSync
Compiler Version
v0.7.6+commit.7338295f
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; // SPDX-License-Identifier: MIT OR Apache-2.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"; import "./AdditionalZkSync.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 private constant EMPTY_STRING_KECCAK = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; /// @notice Data needed to process onchain operation from block public data. /// @notice Onchain operations is operations that need some processing on L1: Deposits, Withdrawals, ChangePubKey. /// @param ethWitness Some external data that can be needed for operation processing /// @param publicDataOffset Byte offset in public data for onchain operation struct OnchainOperationData { bytes ethWitness; uint32 publicDataOffset; } /// @notice Data needed to commit new block struct CommitBlockInfo { bytes32 newStateHash; bytes publicData; uint256 timestamp; OnchainOperationData[] onchainOperations; uint32 blockNumber; uint32 feeAccount; } /// @notice Data needed to execute committed and verified block /// @param commitmentsInSlot verified commitments in one slot /// @param commitmentIdx index such that commitmentsInSlot[commitmentIdx] is current block commitment struct ExecuteBlockInfo { StoredBlockInfo storedBlock; bytes[] pendingOnchainOpsPubdata; } /// @notice Recursive proof input data (individual commitments are constructed onchain) struct ProofInput { uint256[] recursiveInput; uint256[] proof; uint256[] commitments; uint8[] vkIndexes; uint256[16] subproofsLimbs; } // Upgrade functional /// @notice Notice period before activation preparation status of upgrade mode function getNoticePeriod() external pure override returns (uint256) { return 0; } /// @notice Notification that upgrade notice period started /// @dev Can be external because Proxy contract intercepts illegal calls of this function function upgradeNoticePeriodStarted() external override { upgradeStartTimestamp = block.timestamp; } /// @notice Notification that upgrade preparation status is activated /// @dev Can be external because Proxy contract intercepts illegal calls of this function function upgradePreparationStarted() external override { require(block.timestamp >= upgradeStartTimestamp.add(approvedUpgradeNoticePeriod)); upgradePreparationActive = true; upgradePreparationActivationTime = block.timestamp; } /// @dev When upgrade is finished or canceled we must clean upgrade-related state. function clearUpgradeStatus() internal { upgradePreparationActive = false; upgradePreparationActivationTime = 0; approvedUpgradeNoticePeriod = UPGRADE_NOTICE_PERIOD; emit NoticePeriodChange(approvedUpgradeNoticePeriod); upgradeStartTimestamp = 0; for (uint256 i = 0; i < SECURITY_COUNCIL_MEMBERS_NUMBER; ++i) { securityCouncilApproves[i] = false; } numberOfApprovalsFromSecurityCouncil = 0; } /// @notice Notification that upgrade canceled /// @dev Can be external because Proxy contract intercepts illegal calls of this function function upgradeCanceled() external override { clearUpgradeStatus(); } /// @notice Notification that upgrade finishes /// @dev Can be external because Proxy contract intercepts illegal calls of this function function upgradeFinishes() external override { clearUpgradeStatus(); } /// @notice Checks that contract is ready for upgrade /// @return bool flag indicating that contract is ready for upgrade function isReadyForUpgrade() external pure override returns (bool) { return true; } constructor() { initializeReentrancyGuard(); } /// @notice zkSync contract initialization. Can be external because Proxy contract intercepts illegal calls of this function. /// @param initializationParameters Encoded representation of initialization parameters: /// @dev _governanceAddress The address of Governance contract /// @dev _verifierAddress The address of Verifier contract /// @dev _genesisStateHash Genesis blocks (first block) state tree root hash function initialize(bytes calldata initializationParameters) external { initializeReentrancyGuard(); ( address _governanceAddress, address _verifierAddress, address _additionalZkSync, bytes32 _genesisStateHash ) = abi.decode(initializationParameters, (address, address, address, bytes32)); verifier = Verifier(_verifierAddress); governance = Governance(_governanceAddress); additionalZkSync = AdditionalZkSync(_additionalZkSync); StoredBlockInfo memory storedBlockZero = StoredBlockInfo( 0, 0, EMPTY_STRING_KECCAK, 0, _genesisStateHash, bytes32(0) ); storedBlockHashes[0] = hashStoredBlockInfo(storedBlockZero); approvedUpgradeNoticePeriod = UPGRADE_NOTICE_PERIOD; emit NoticePeriodChange(approvedUpgradeNoticePeriod); } /// @notice zkSync contract upgrade. Can be external because Proxy contract intercepts illegal calls of this function. /// @param upgradeParameters Encoded representation of upgrade parameters // solhint-disable-next-line no-empty-blocks function upgrade(bytes calldata upgradeParameters) external nonReentrant { // Silencing the warning "Unused function parameter" upgradeParameters; approvedUpgradeNoticePeriod = UPGRADE_NOTICE_PERIOD; additionalZkSync = AdditionalZkSync(0x2eaa1377e0fC95dE998B9fA7611E9D67ebA534fD); } function cutUpgradeNoticePeriod(bytes32 targetsHash) external { // All functions delegated to additional contract should NOT be nonReentrant // Silencing the warning "Unused function parameter" targetsHash; delegateAdditional(); } function cutUpgradeNoticePeriodBySignature(bytes[] calldata signatures) external { // All functions delegated to additional contract should NOT be nonReentrant // Silencing the warning "Unused function parameter" signatures; delegateAdditional(); } /// @notice Sends tokens /// @dev NOTE: will revert if transfer call fails or rollup balance difference (before and after transfer) is bigger than _maxAmount /// @dev This function is used to allow tokens to spend zkSync contract balance up to amount that is requested /// @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 transferERC20( IERC20 _token, address _to, uint128 _amount, uint128 _maxAmount ) external returns (uint128 withdrawnAmount) { require(msg.sender == address(this), "5"); // can be called only from this contract as one "external" call (to revert all this function state changes if it is needed) uint256 balanceBefore = _token.balanceOf(address(this)); _token.transfer(_to, _amount); uint256 balanceAfter = _token.balanceOf(address(this)); uint256 balanceDiff = balanceBefore.sub(balanceAfter); require(balanceDiff > 0, "c1"); // transfer is considered successful only if the balance of the contract decreased after transfer require(balanceDiff <= _maxAmount, "7"); // rollup balance difference (before and after transfer) is bigger than `_maxAmount` // It is safe to convert `balanceDiff` to `uint128` without additional checks, because `balanceDiff <= _maxAmount` return uint128(balanceDiff); } /// @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, bytes[] calldata _depositsPubdata) external { // All functions delegated to additional contract should NOT be nonReentrant // Silencing the warning "Unused function parameter" _n; _depositsPubdata; delegateAdditional(); } /// @notice Deposit ETH to Layer 2 - transfer ether from user into contract, validate it, register deposit /// @param _zkSyncAddress The receiver Layer 2 address function depositETH(address _zkSyncAddress) external payable { require(_zkSyncAddress != SPECIAL_ACCOUNT_ADDRESS, "P"); require(msg.value > 0, "M"); // Zero-value deposits are forbidden by zkSync rollup logic requireActive(); registerDeposit(0, SafeCast.toUint128(msg.value), _zkSyncAddress); } /// @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 _zkSyncAddress Receiver Layer 2 address function depositERC20( IERC20 _token, uint104 _amount, address _zkSyncAddress ) external nonReentrant { require(_zkSyncAddress != SPECIAL_ACCOUNT_ADDRESS, "P"); requireActive(); // Get token id by its address uint16 tokenId = governance.validateTokenAddress(address(_token)); require(!governance.pausedTokens(tokenId), "b"); // token deposits are paused uint256 balanceBefore = _token.balanceOf(address(this)); _token.transferFrom(msg.sender, address(this), _amount); uint256 balanceAfter = _token.balanceOf(address(this)); uint128 depositAmount = SafeCast.toUint128(balanceAfter.sub(balanceBefore)); require(depositAmount > 0 && depositAmount <= MAX_DEPOSIT_AMOUNT, "C"); registerDeposit(tokenId, depositAmount, _zkSyncAddress); } /// @notice Returns amount of tokens that can be withdrawn by `address` from zkSync contract /// @param _address Address of the tokens owner /// @param _token Address of token, zero address is used for ETH function getPendingBalance(address _address, address _token) public view returns (uint128) { uint16 tokenId = 0; if (_token != address(0)) { tokenId = governance.validateTokenAddress(_token); } return pendingBalances[packAddressAndTokenId(_address, tokenId)].balanceToWithdraw; } /// @notice Withdraws tokens from zkSync contract to the owner /// @param _owner Address of the tokens owner /// @param _token Address of tokens, zero address is used for ETH /// @param _amount Amount to withdraw to request. /// NOTE: We will call ERC20.transfer(.., _amount), but if according to internal logic of ERC20 token zkSync contract /// balance will be decreased by value more then _amount we will try to subtract this value from user pending balance function withdrawPendingBalance( address payable _owner, address _token, uint128 _amount ) external nonReentrant { uint16 tokenId = 0; if (_token != address(0)) { tokenId = governance.validateTokenAddress(_token); } bytes22 packedBalanceKey = packAddressAndTokenId(_owner, tokenId); uint128 balance = pendingBalances[packedBalanceKey].balanceToWithdraw; uint128 amount = Utils.minU128(balance, _amount); require(amount > 0, "f1"); // Nothing to withdraw if (tokenId == 0) { (bool success, ) = _owner.call{value: amount}(""); require(success, "d"); // ETH withdraw failed } else { // We will allow withdrawals of `value` such that: // `value` <= user pending balance // `value` can be bigger then `amount` requested if token takes fee from sender in addition to `amount` requested amount = this.transferERC20(IERC20(_token), _owner, amount, balance); } pendingBalances[packedBalanceKey].balanceToWithdraw = balance - amount; emit Withdrawal(_owner, tokenId, amount); } /// @notice Withdraws NFT from zkSync contract to the owner /// @param _tokenId Id of NFT token function withdrawPendingNFTBalance(uint32 _tokenId) external nonReentrant { Operations.WithdrawNFT memory op = pendingWithdrawnNFTs[_tokenId]; require(op.creatorAddress != address(0), "op"); // No NFT to withdraw NFTFactory _factory = governance.getNFTFactory(op.creatorAccountId, op.creatorAddress); // Save withdrawn nfts for future deposits withdrawnNFTs[_tokenId] = address(_factory); delete pendingWithdrawnNFTs[_tokenId]; _factory.mintNFTFromZkSync( op.creatorAddress, op.receiver, op.creatorAccountId, op.serialId, op.contentHash, op.tokenId ); emit WithdrawalNFT(op.tokenId); } /// @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 requestFullExit(uint32 _accountId, address _token) public nonReentrant { requireActive(); require(_accountId <= MAX_ACCOUNT_ID, "e"); require(_accountId != SPECIAL_ACCOUNT_ID, "v"); // request full exit for nft storage account 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 nftCreatorAccountId: uint32(0), // unknown at this point nftCreatorAddress: address(0), // unknown at this point nftSerialId: uint32(0), // unknown at this point nftContentHash: bytes32(0) // unknown at this point }); bytes memory pubData = Operations.writeFullExitPubdataForPriorityQueue(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); pendingBalances[packedBalanceKey].gasReserveValue = FILLED_GAS_RESERVE_VALUE; } /// @notice Register full exit nft request - pack pubdata, add priority request /// @param _accountId Numerical id of the account /// @param _tokenId NFT token id in zkSync network function requestFullExitNFT(uint32 _accountId, uint32 _tokenId) public nonReentrant { requireActive(); require(_accountId <= MAX_ACCOUNT_ID, "e"); require(_accountId != SPECIAL_ACCOUNT_ID, "v"); // request full exit nft for nft storage account require(MAX_FUNGIBLE_TOKEN_ID < _tokenId && _tokenId < SPECIAL_NFT_TOKEN_ID, "T"); // request full exit nft for invalid token id // Priority Queue request Operations.FullExit memory op = Operations.FullExit({ accountId: _accountId, owner: msg.sender, tokenId: _tokenId, amount: 0, // unknown at this point nftCreatorAccountId: uint32(0), // unknown at this point nftCreatorAddress: address(0), // unknown at this point nftSerialId: uint32(0), // unknown at this point nftContentHash: bytes32(0) // unknown at this point }); bytes memory pubData = Operations.writeFullExitPubdataForPriorityQueue(op); addPriorityRequest(Operations.OpType.FullExit, pubData); } /// @dev Process one block commit using previous block StoredBlockInfo, /// @dev returns new block StoredBlockInfo function commitOneBlock(StoredBlockInfo memory _previousBlock, CommitBlockInfo calldata _newBlock) internal view returns (StoredBlockInfo memory storedNewBlock) { require(_newBlock.blockNumber == _previousBlock.blockNumber + 1, "f"); // only commit next block // Check timestamp of the new block { require(_newBlock.timestamp >= _previousBlock.timestamp, "g"); // Block should be after previous block bool timestampNotTooSmall = block.timestamp.sub(COMMIT_TIMESTAMP_NOT_OLDER) <= _newBlock.timestamp; bool timestampNotTooBig = _newBlock.timestamp <= block.timestamp.add(COMMIT_TIMESTAMP_APPROXIMATION_DELTA); require(timestampNotTooSmall && timestampNotTooBig, "h"); // New block timestamp is not valid } // Check onchain operations ( bytes32 pendingOnchainOpsHash, uint64 priorityReqCommitted, bytes memory onchainOpsOffsetCommitment ) = collectOnchainOps(_newBlock); // Create block commitment for verification proof bytes32 commitment = createBlockCommitment(_previousBlock, _newBlock, onchainOpsOffsetCommitment); return StoredBlockInfo( _newBlock.blockNumber, priorityReqCommitted, pendingOnchainOpsHash, _newBlock.timestamp, _newBlock.newStateHash, commitment ); } /// @notice Commit block /// @notice 1. Checks onchain operations, timestamp. /// @notice 2. Store block commitments function commitBlocks(StoredBlockInfo memory _lastCommittedBlockData, CommitBlockInfo[] calldata _newBlocksData) external nonReentrant { requireActive(); governance.requireActiveValidator(msg.sender); // Check that we commit blocks after last committed block require(storedBlockHashes[totalBlocksCommitted] == hashStoredBlockInfo(_lastCommittedBlockData), "i"); // incorrect previous block data uint32 newBlocksDataLength = uint32(_newBlocksData.length); for (uint256 i = 0; i < newBlocksDataLength; ++i) { _lastCommittedBlockData = commitOneBlock(_lastCommittedBlockData, _newBlocksData[i]); totalCommittedPriorityRequests += _lastCommittedBlockData.priorityOperations; storedBlockHashes[_lastCommittedBlockData.blockNumber] = hashStoredBlockInfo(_lastCommittedBlockData); emit BlockCommit(_lastCommittedBlockData.blockNumber); } totalBlocksCommitted += newBlocksDataLength; require(totalCommittedPriorityRequests <= totalOpenPriorityRequests, "j"); } /// @dev Save NFT as pending to withdraw function storePendingNFT(Operations.WithdrawNFT memory op) internal { pendingWithdrawnNFTs[op.tokenId] = op; emit WithdrawalNFTPending(op.tokenId); } /// @dev Increase `_recipient` balance to withdraw function increasePendingBalance( uint16 _tokenId, address _recipient, uint128 _amount, Operations.WithdrawalType _withdrawalType ) internal { bytes22 packedBalanceKey = packAddressAndTokenId(_recipient, _tokenId); increaseBalanceToWithdraw(packedBalanceKey, _amount); emit WithdrawalPending(_tokenId, _recipient, _amount, _withdrawalType); } /// @dev Executes one block /// @dev 1. Processes all priority operations or save them as pending /// @dev 2. Finalizes block on Ethereum /// @dev _executedBlockIdx is index in the array of the blocks that we want to execute together function executeOneBlock(ExecuteBlockInfo calldata _blockExecuteData, uint256 _executedBlockIdx) internal { // Ensure block was committed require( hashStoredBlockInfo(_blockExecuteData.storedBlock) == storedBlockHashes[_blockExecuteData.storedBlock.blockNumber], "exe10" // executing block should be committed ); require(_blockExecuteData.storedBlock.blockNumber == totalBlocksExecuted + _executedBlockIdx + 1, "k"); // Execute blocks in order bytes32 pendingOnchainOpsHash = EMPTY_STRING_KECCAK; uint256 pendingOnchainOpsPubdataLength = _blockExecuteData.pendingOnchainOpsPubdata.length; for (uint256 i = 0; i < pendingOnchainOpsPubdataLength; ++i) { bytes calldata pubData = _blockExecuteData.pendingOnchainOpsPubdata[i]; Operations.OpType opType = Operations.OpType(uint8(pubData[0])); if (opType == Operations.OpType.PartialExit) { Operations.PartialExit memory op = Operations.readPartialExitPubdata(pubData); // Circuit guarantees that partial exits are available only for fungible tokens require(op.tokenId <= MAX_FUNGIBLE_TOKEN_ID, "mf1"); increasePendingBalance(uint16(op.tokenId), op.owner, op.amount, Operations.WithdrawalType.PartialExit); } else if (opType == Operations.OpType.ForcedExit) { Operations.ForcedExit memory op = Operations.readForcedExitPubdata(pubData); // Circuit guarantees that forced exits are available only for fungible tokens require(op.tokenId <= MAX_FUNGIBLE_TOKEN_ID, "mf2"); increasePendingBalance(uint16(op.tokenId), op.target, op.amount, Operations.WithdrawalType.ForcedExit); } else if (opType == Operations.OpType.FullExit) { Operations.FullExit memory op = Operations.readFullExitPubdata(pubData); if (op.tokenId <= MAX_FUNGIBLE_TOKEN_ID) { increasePendingBalance(uint16(op.tokenId), op.owner, op.amount, Operations.WithdrawalType.FullExit); } else { if (op.amount == 1) { Operations.WithdrawNFT memory withdrawNftOp = Operations.WithdrawNFT( op.nftCreatorAccountId, op.nftCreatorAddress, op.nftSerialId, op.nftContentHash, op.owner, op.tokenId ); storePendingNFT(withdrawNftOp); } } } else if (opType == Operations.OpType.WithdrawNFT) { Operations.WithdrawNFT memory op = Operations.readWithdrawNFTPubdata(pubData); storePendingNFT(op); } else { revert("l"); // unsupported op in block execution } pendingOnchainOpsHash = Utils.concatHash(pendingOnchainOpsHash, pubData); } require(pendingOnchainOpsHash == _blockExecuteData.storedBlock.pendingOnchainOperationsHash, "m"); // incorrect onchain ops executed } /// @notice Execute blocks, completing priority operations and processing withdrawals. /// @notice 1. Processes all pending operations (Send Exits, Complete priority requests) /// @notice 2. Finalizes block on Ethereum function executeBlocks(ExecuteBlockInfo[] calldata _blocksData) external nonReentrant { requireActive(); governance.requireActiveValidator(msg.sender); uint64 priorityRequestsExecuted = 0; uint32 nBlocks = uint32(_blocksData.length); for (uint256 i = 0; i < nBlocks; ++i) { executeOneBlock(_blocksData[i], i); priorityRequestsExecuted += _blocksData[i].storedBlock.priorityOperations; emit BlockVerification(_blocksData[i].storedBlock.blockNumber); } firstPriorityRequestId += priorityRequestsExecuted; totalCommittedPriorityRequests -= priorityRequestsExecuted; totalOpenPriorityRequests -= priorityRequestsExecuted; totalBlocksExecuted += nBlocks; require(totalBlocksExecuted <= totalBlocksProven, "n"); // Can't execute blocks more then committed and proven currently. } /// @notice Blocks commitment verification. /// @notice Only verifies block commitments without any other processing function proveBlocks(StoredBlockInfo[] calldata _committedBlocks, ProofInput memory _proof) external nonReentrant { requireActive(); uint256 i; uint32 currentTotalBlocksProven = totalBlocksProven; // Preventing "stack too deep error" { // Ignoring the _committedBlocks that are already proven. bytes32 firstUnverifiedBlockHash = storedBlockHashes[currentTotalBlocksProven + 1]; while (hashStoredBlockInfo(_committedBlocks[i]) != firstUnverifiedBlockHash) { ++i; require(i < _committedBlocks.length, "o2"); // Revert if the first unverified block is not among committed ones. } } uint256 committedBlocksLength = _committedBlocks.length; while (i < committedBlocksLength) { require(hashStoredBlockInfo(_committedBlocks[i]) == storedBlockHashes[currentTotalBlocksProven + 1], "o1"); ++currentTotalBlocksProven; require(_proof.commitments[i] & INPUT_MASK == uint256(_committedBlocks[i].commitment) & INPUT_MASK, "o"); // incorrect block commitment in proof ++i; } bool success = verifier.verifyAggregatedBlockProof( _proof.recursiveInput, _proof.proof, _proof.vkIndexes, _proof.commitments, _proof.subproofsLimbs ); require(success, "p"); // Aggregated proof verification fail require(currentTotalBlocksProven <= totalBlocksCommitted, "q"); totalBlocksProven = currentTotalBlocksProven; } /// @notice Reverts unverified blocks function revertBlocks(StoredBlockInfo[] calldata _blocksToRevert) external { // All functions delegated to additional contract should NOT be nonReentrant // Silencing the warning "Unused function parameter" _blocksToRevert; delegateAdditional(); } /// @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 activateExodusMode() external nonReentrant returns (bool) { if (exodusMode) { return false; } bool trigger = block.number >= priorityRequests[firstPriorityRequestId].expirationBlock && priorityRequests[firstPriorityRequestId].expirationBlock != 0; if (trigger) { exodusMode = true; emit ExodusMode(); } return trigger; } /// @notice Withdraws token from ZkSync to root chain in case of exodus mode. User must provide proof that he owns funds /// @param _storedBlockInfo Last verified block /// @param _owner Owner of the account /// @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 performExodus( StoredBlockInfo calldata _storedBlockInfo, address _owner, uint32 _accountId, uint32 _tokenId, uint128 _amount, uint32 _nftCreatorAccountId, address _nftCreatorAddress, uint32 _nftSerialId, bytes32 _nftContentHash, uint256[] calldata _proof ) external { // All functions delegated to additional should NOT be nonReentrant // Silencing the warning "Unused function parameter" _storedBlockInfo; _owner; _accountId; _tokenId; _amount; _nftCreatorAccountId; _nftCreatorAddress; _nftSerialId; _nftContentHash; _proof; delegateAdditional(); } /// @notice Set data for changing pubkey hash using onchain authorization. /// Transaction author (msg.sender) should be L2 account address /// @notice New pubkey hash can be reset, to do that user should send two transactions: /// 1) First `setAuthPubkeyHash` transaction for already used `_nonce` will set timer. /// 2) After `AUTH_FACT_RESET_TIMELOCK` time is passed second `setAuthPubkeyHash` transaction will reset pubkey hash for `_nonce`. /// @param _pubkeyHash New pubkey hash /// @param _nonce Nonce of the change pubkey L2 transaction function setAuthPubkeyHash(bytes calldata _pubkeyHash, uint32 _nonce) external { // All functions delegated to additional contract should NOT be nonReentrant // Silencing the warning "Unused function parameter" _nonce; _pubkeyHash; delegateAdditional(); } /// @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.writeDepositPubdataForPriorityQueue(op); addPriorityRequest(Operations.OpType.Deposit, pubData); emit Deposit(_tokenId, _amount); } /// @dev Gets operations packed in bytes array. Unpacks it and stores onchain operations. /// @dev Priority operations must be committed in the same order as they are in the priority queue. /// @dev NOTE: does not change storage! (only emits events) /// @dev processableOperationsHash - hash of the all operations that needs to be executed (Deposit, Exits, ChangPubKey) /// @dev priorityOperationsProcessed - number of priority operations processed in this block (Deposits, FullExits) /// @dev offsetsCommitment - array where 1 is stored in chunk where onchainOperation begins and other are 0 (used in commitments) function collectOnchainOps(CommitBlockInfo calldata _newBlockData) internal view returns ( bytes32 processableOperationsHash, uint64 priorityOperationsProcessed, bytes memory offsetsCommitment ) { bytes memory pubData = _newBlockData.publicData; uint64 uncommittedPriorityRequestsOffset = firstPriorityRequestId + totalCommittedPriorityRequests; priorityOperationsProcessed = 0; processableOperationsHash = EMPTY_STRING_KECCAK; require(pubData.length % CHUNK_BYTES == 0, "A"); // pubdata length must be a multiple of CHUNK_BYTES offsetsCommitment = new bytes(pubData.length / CHUNK_BYTES); uint256 newBlockDataOnchainOperationsLength = _newBlockData.onchainOperations.length; for (uint256 i = 0; i < newBlockDataOnchainOperationsLength; ++i) { OnchainOperationData calldata onchainOpData = _newBlockData.onchainOperations[i]; uint256 pubdataOffset = onchainOpData.publicDataOffset; require(pubdataOffset < pubData.length, "A1"); require(pubdataOffset % CHUNK_BYTES == 0, "B"); // offsets should be on chunks boundaries uint256 chunkId = pubdataOffset / CHUNK_BYTES; require(offsetsCommitment[chunkId] == 0x00, "C"); // offset commitment should be empty offsetsCommitment[chunkId] = bytes1(0x01); Operations.OpType opType = Operations.OpType(uint8(pubData[pubdataOffset])); if (opType == Operations.OpType.Deposit) { bytes memory opPubData = Bytes.slice(pubData, pubdataOffset, DEPOSIT_BYTES); Operations.Deposit memory depositData = Operations.readDepositPubdata(opPubData); checkPriorityOperation(depositData, uncommittedPriorityRequestsOffset + priorityOperationsProcessed); ++priorityOperationsProcessed; } else if (opType == Operations.OpType.ChangePubKey) { bytes memory opPubData = Bytes.slice(pubData, pubdataOffset, CHANGE_PUBKEY_BYTES); Operations.ChangePubKey memory op = Operations.readChangePubKeyPubdata(opPubData); if (onchainOpData.ethWitness.length != 0) { bool valid = verifyChangePubkey(onchainOpData.ethWitness, op); require(valid, "D"); // failed to verify change pubkey hash signature } else { bool valid = authFacts[op.owner][op.nonce] == keccak256(abi.encodePacked(op.pubKeyHash)); require(valid, "E"); // new pub key hash is not authenticated properly } } else { bytes memory opPubData; if (opType == Operations.OpType.PartialExit) { opPubData = Bytes.slice(pubData, pubdataOffset, PARTIAL_EXIT_BYTES); } else if (opType == Operations.OpType.ForcedExit) { opPubData = Bytes.slice(pubData, pubdataOffset, FORCED_EXIT_BYTES); } else if (opType == Operations.OpType.WithdrawNFT) { opPubData = Bytes.slice(pubData, pubdataOffset, WITHDRAW_NFT_BYTES); } else if (opType == Operations.OpType.FullExit) { opPubData = Bytes.slice(pubData, pubdataOffset, FULL_EXIT_BYTES); Operations.FullExit memory fullExitData = Operations.readFullExitPubdata(opPubData); checkPriorityOperation( fullExitData, uncommittedPriorityRequestsOffset + priorityOperationsProcessed ); ++priorityOperationsProcessed; } else { revert("F"); // unsupported op } processableOperationsHash = Utils.concatHash(processableOperationsHash, opPubData); } } } /// @notice Checks that change operation is correct function verifyChangePubkey(bytes calldata _ethWitness, Operations.ChangePubKey memory _changePk) internal pure returns (bool) { Operations.ChangePubkeyType changePkType = Operations.ChangePubkeyType(uint8(_ethWitness[0])); if (changePkType == Operations.ChangePubkeyType.ECRECOVER) { return verifyChangePubkeyECRECOVER(_ethWitness, _changePk); } else if (changePkType == Operations.ChangePubkeyType.CREATE2) { return verifyChangePubkeyCREATE2(_ethWitness, _changePk); } else if (changePkType == Operations.ChangePubkeyType.OldECRECOVER) { return verifyChangePubkeyOldECRECOVER(_ethWitness, _changePk); } else if (changePkType == Operations.ChangePubkeyType.ECRECOVERV2) { return verifyChangePubkeyECRECOVERV2(_ethWitness, _changePk); } else if (changePkType == Operations.ChangePubkeyType.EIP712) { return verifyChangePubkeyEIP712(_ethWitness, _changePk); } else { revert("G"); // Incorrect ChangePubKey type } } /// @notice Checks that signature is valid for pubkey change message /// @param _ethWitness Signature (65 bytes) /// @param _changePk Parsed change pubkey operation function verifyChangePubkeyECRECOVER(bytes calldata _ethWitness, Operations.ChangePubKey memory _changePk) internal pure returns (bool) { (, bytes memory signature) = Bytes.read(_ethWitness, 1, 65); // offset is 1 because we skip type of ChangePubkey bytes32 messageHash = keccak256( abi.encodePacked( "\x19Ethereum Signed Message:\n60", _changePk.pubKeyHash, _changePk.nonce, _changePk.accountId, bytes32(0) ) ); address recoveredAddress = Utils.recoverAddressFromEthSignature(signature, messageHash); return recoveredAddress == _changePk.owner; } /// @notice Checks that signature is valid for pubkey change EIP712 message /// @param _ethWitness Signature (65 bytes) /// @param _changePk Parsed change pubkey operation function verifyChangePubkeyEIP712(bytes calldata _ethWitness, Operations.ChangePubKey memory _changePk) internal pure returns (bool) { (, bytes memory signature) = Bytes.read(_ethWitness, 1, 65); // offset is 1 because we skip type of ChangePubkey bytes32 eip712DomainSeparator = keccak256( abi.encode(EIP712_DOMAIN_TYPEHASH, keccak256(bytes(name)), keccak256(bytes(version)), Utils.getChainId()) ); bytes32 structHash = keccak256( abi.encode(EIP712_CHANGEPUBKEY_TYPEHASH, _changePk.pubKeyHash, _changePk.nonce, _changePk.accountId) ); bytes32 digest = keccak256(abi.encodePacked("\x19\x01", eip712DomainSeparator, structHash)); address recoveredAddress = Utils.recoverAddressFromEthSignature(signature, digest); return recoveredAddress == _changePk.owner; } /// @notice Checks that signature is valid for pubkey change message /// @param _ethWitness Signature (65 bytes) + 32 bytes of the arbitrary signed data /// @notice additional 32 bytes can be used to sign batches and ChangePubKey with one signature /// @param _changePk Parsed change pubkey operation function verifyChangePubkeyECRECOVERV2(bytes calldata _ethWitness, Operations.ChangePubKey memory _changePk) internal pure returns (bool) { (uint256 offset, bytes memory signature) = Bytes.read(_ethWitness, 1, 65); // offset is 1 because we skip type of ChangePubkey (, bytes32 additionalData) = Bytes.readBytes32(_ethWitness, offset); bytes32 messageHash = keccak256( abi.encodePacked( "\x19Ethereum Signed Message:\n60", _changePk.pubKeyHash, _changePk.nonce, _changePk.accountId, additionalData ) ); address recoveredAddress = Utils.recoverAddressFromEthSignature(signature, messageHash); return recoveredAddress == _changePk.owner; } /// @notice Checks that signature is valid for pubkey change message, old version differs by form of the signed message. /// @param _ethWitness Signature (65 bytes) /// @param _changePk Parsed change pubkey operation function verifyChangePubkeyOldECRECOVER(bytes calldata _ethWitness, Operations.ChangePubKey memory _changePk) internal pure returns (bool) { (, bytes memory signature) = Bytes.read(_ethWitness, 1, 65); // offset is 1 because we skip type of ChangePubkey bytes32 messageHash = keccak256( abi.encodePacked( "\x19Ethereum Signed Message:\n152", "Register zkSync pubkey:\n\n", Bytes.bytesToHexASCIIBytes(abi.encodePacked(_changePk.pubKeyHash)), "\n", "nonce: 0x", Bytes.bytesToHexASCIIBytes(Bytes.toBytesFromUInt32(_changePk.nonce)), "\n", "account id: 0x", Bytes.bytesToHexASCIIBytes(Bytes.toBytesFromUInt32(_changePk.accountId)), "\n\n", "Only sign this message for a trusted client!" ) ); address recoveredAddress = Utils.recoverAddressFromEthSignature(signature, messageHash); return recoveredAddress == _changePk.owner; } /// @notice Checks that signature is valid for pubkey change message /// @param _ethWitness Create2 deployer address, saltArg, codeHash /// @param _changePk Parsed change pubkey operation function verifyChangePubkeyCREATE2(bytes calldata _ethWitness, Operations.ChangePubKey memory _changePk) internal pure returns (bool) { address creatorAddress; bytes32 saltArg; // salt arg is additional bytes that are encoded in the CREATE2 salt bytes32 codeHash; uint256 offset = 1; // offset is 1 because we skip type of ChangePubkey (offset, creatorAddress) = Bytes.readAddress(_ethWitness, offset); (offset, saltArg) = Bytes.readBytes32(_ethWitness, offset); (offset, codeHash) = Bytes.readBytes32(_ethWitness, offset); // salt from CREATE2 specification bytes32 salt = keccak256(abi.encodePacked(saltArg, _changePk.pubKeyHash)); // Address computation according to CREATE2 definition: https://eips.ethereum.org/EIPS/eip-1014 address recoveredAddress = address( uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), creatorAddress, salt, codeHash)))) ); // This type of change pubkey can be done only once return recoveredAddress == _changePk.owner && _changePk.nonce == 0; } /// @dev Creates block commitment from its data /// @dev _offsetCommitment - hash of the array where 1 is stored in chunk where onchainOperation begins and 0 for other chunks function createBlockCommitment( StoredBlockInfo memory _previousBlock, CommitBlockInfo calldata _newBlockData, bytes memory _offsetCommitment ) internal view returns (bytes32 commitment) { bytes32 hash = sha256(abi.encodePacked(uint256(_newBlockData.blockNumber), uint256(_newBlockData.feeAccount))); hash = sha256(abi.encodePacked(hash, _previousBlock.stateHash)); hash = sha256(abi.encodePacked(hash, _newBlockData.newStateHash)); hash = sha256(abi.encodePacked(hash, uint256(_newBlockData.timestamp))); bytes memory pubdata = abi.encodePacked(_newBlockData.publicData, _offsetCommitment); /// 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(pubdata) mstore(pubdata, hash) // staticcall to the sha256 precompile at address 0x2 let success := staticcall(gas(), 0x2, pubdata, add(pubDataLen, 0x20), hashResult, 0x20) mstore(pubdata, pubDataLen) // Use "invalid" to make gas estimation work switch success case 0 { invalid() } commitment := mload(hashResult) } } /// @notice Checks that deposit is same as operation in priority queue /// @param _deposit Deposit data /// @param _priorityRequestId Operation's id in priority queue function checkPriorityOperation(Operations.Deposit memory _deposit, uint64 _priorityRequestId) internal view { Operations.OpType priorReqType = priorityRequests[_priorityRequestId].opType; require(priorReqType == Operations.OpType.Deposit, "H"); // incorrect priority op type bytes20 hashedPubdata = priorityRequests[_priorityRequestId].hashedPubData; require(Operations.checkDepositInPriorityQueue(_deposit, hashedPubdata), "I"); } /// @notice Checks that FullExit is same as operation in priority queue /// @param _fullExit FullExit data /// @param _priorityRequestId Operation's id in priority queue function checkPriorityOperation(Operations.FullExit memory _fullExit, uint64 _priorityRequestId) internal view { Operations.OpType priorReqType = priorityRequests[_priorityRequestId].opType; require(priorReqType == Operations.OpType.FullExit, "J"); // incorrect priority op type bytes20 hashedPubdata = priorityRequests[_priorityRequestId].hashedPubData; require(Operations.checkFullExitInPriorityQueue(_fullExit, hashedPubdata), "K"); } // 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 uint64 expirationBlock = uint64(block.number + PRIORITY_EXPIRATION); uint64 nextPriorityRequestId = firstPriorityRequestId + totalOpenPriorityRequests; bytes20 hashedPubData = Utils.hashBytesToBytes20(_pubData); priorityRequests[nextPriorityRequestId] = PriorityOperation({ hashedPubData: hashedPubData, expirationBlock: expirationBlock, opType: _opType }); emit NewPriorityRequest(msg.sender, nextPriorityRequestId, _opType, _pubData, uint256(expirationBlock)); totalOpenPriorityRequests += 1; } function increaseBalanceToWithdraw(bytes22 _packedBalanceKey, uint128 _amount) internal { uint128 balance = pendingBalances[_packedBalanceKey].balanceToWithdraw; pendingBalances[_packedBalanceKey] = PendingBalance(balance.add(_amount), FILLED_GAS_RESERVE_VALUE); } /// @notice Delegates the call to the additional part of the main contract. /// @notice Should be only use to delegate the external calls as it passes the calldata /// @notice All functions delegated to additional contract should NOT be nonReentrant function delegateAdditional() internal { address _target = address(additionalZkSync); assembly { // The pointer to the free memory slot let ptr := mload(0x40) // Copy function signature and arguments from calldata at zero position into memory at pointer position calldatacopy(ptr, 0x0, calldatasize()) // Delegatecall method of the implementation contract, returns 0 on error let result := delegatecall(gas(), _target, ptr, calldatasize(), 0x0, 0) // Get the size of the last return data let size := returndatasize() // Copy the size length of bytes from return data at zero position to pointer position returndatacopy(ptr, 0x0, size) // Depending on result value switch result case 0 { // End execution and revert state changes revert(ptr, size) } default { // Return data with length of size at pointers position return(ptr, size) } } } }
pragma solidity ^0.7.0; // SPDX-License-Identifier: MIT OR Apache-2.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 { /// @dev Address of lock flag variable. /// @dev Flag is placed at random memory location to not interfere with Storage contract. uint256 private constant LOCK_FLAG_ADDRESS = 0x8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4; // keccak256("ReentrancyGuard") - 1; // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/566a774222707e424896c0c390a84dc3c13bdcb2/contracts/security/ReentrancyGuard.sol // The values being 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 percentage 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. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; function initializeReentrancyGuard() internal { uint256 lockSlotOldValue; // Storing an initial non-zero value makes deployment a bit more // expensive, but in exchange every call to nonReentrant // will be cheaper. assembly { lockSlotOldValue := sload(LOCK_FLAG_ADDRESS) sstore(LOCK_FLAG_ADDRESS, _NOT_ENTERED) } // Check that storage slot for reentrancy guard is empty to rule out possibility of double initialization require(lockSlotOldValue == 0, "1B"); } /** * @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() { uint256 _status; assembly { _status := sload(LOCK_FLAG_ADDRESS) } // On the first call to nonReentrant, _notEntered will be true require(_status == _NOT_ENTERED); // Any calls to nonReentrant after this point will fail assembly { sstore(LOCK_FLAG_ADDRESS, _ENTERED) } _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) assembly { sstore(LOCK_FLAG_ADDRESS, _NOT_ENTERED) } } }
pragma solidity ^0.7.0; // SPDX-License-Identifier: MIT OR Apache-2.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, "14"); 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, "v"); } /** * @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, "15"); 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, "x"); } /** * @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, "y"); } /** * @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; } }
pragma solidity ^0.7.0; // SPDX-License-Identifier: MIT OR Apache-2.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, "12"); 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, "aa"); } /** * @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, "13"); 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, "ac"); } /** * @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, "ad"); } /** * @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; } }
pragma solidity ^0.7.0; // SPDX-License-Identifier: MIT OR Apache-2.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, "16"); 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, "17"); 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, "18"); 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, "19"); 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, "1a"); return uint8(value); } }
pragma solidity ^0.7.0; // SPDX-License-Identifier: MIT OR Apache-2.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 Returns lesser of two values function minU128(uint128 a, uint128 b) internal pure returns (uint128) { return a < b ? a : b; } /// @notice Recovers signer's address from ethereum signature for given message /// @param _signature 65 bytes concatenated. R (32) + S (32) + V (1) /// @param _messageHash signed message hash. /// @return address of the signer /// NOTE: will revert if signature is invalid function recoverAddressFromEthSignature(bytes memory _signature, bytes32 _messageHash) internal pure returns (address) { require(_signature.length == 65, "P"); // incorrect signature length bytes32 signR; bytes32 signS; uint8 signV; assembly { signR := mload(add(_signature, 32)) signS := mload(add(_signature, 64)) signV := byte(0, mload(add(_signature, 96))) } address recoveredAddress = ecrecover(_messageHash, signV, signR, signS); require(recoveredAddress != address(0), "p4"); // invalid signature return recoveredAddress; } /// @notice Returns new_hash = hash(old_hash + bytes) function concatHash(bytes32 _hash, bytes memory _bytes) internal pure returns (bytes32) { bytes32 result; assembly { let bytesLen := add(mload(_bytes), 32) mstore(_bytes, _hash) result := keccak256(_bytes, bytesLen) } return result; } function hashBytesToBytes20(bytes memory _bytes) internal pure returns (bytes20) { return bytes20(uint160(uint256(keccak256(_bytes)))); } function getChainId() internal pure returns (uint256) { uint256 chainId; assembly { chainId := chainid() } return chainId; } }
pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; // SPDX-License-Identifier: MIT OR Apache-2.0 // solhint-disable max-states-count import "./IERC20.sol"; import "./Governance.sol"; import "./Verifier.sol"; import "./Operations.sol"; import "./NFTFactory.sol"; import "./AdditionalZkSync.sol"; /// @title zkSync storage contract /// @author Matter Labs contract Storage { /// @dev Flag indicates that upgrade preparation status is active /// @dev Will store false in case of not active upgrade mode bool internal upgradePreparationActive; /// @dev Upgrade preparation activation timestamp (as seconds since unix epoch) /// @dev Will be equal to zero in case of not active upgrade mode uint256 internal upgradePreparationActivationTime; /// @dev Verifier contract. Used to verify block proof and exit proof Verifier internal verifier; /// @dev Governance contract. Contains the governor (the owner) of whole system, validators list, possible tokens list Governance internal governance; uint8 internal constant FILLED_GAS_RESERVE_VALUE = 0xff; // we use it to set gas revert value so slot will not be emptied with 0 balance struct PendingBalance { uint128 balanceToWithdraw; uint8 gasReserveValue; // gives user opportunity to fill storage slot with nonzero value } /// @dev Root-chain balances (per owner and token id, see packAddressAndTokenId) to withdraw mapping(bytes22 => PendingBalance) internal pendingBalances; // @dev Pending withdrawals are not used in this version struct PendingWithdrawalDEPRECATED { address to; uint16 tokenId; } mapping(uint32 => PendingWithdrawalDEPRECATED) internal pendingWithdrawalsDEPRECATED; uint32 internal firstPendingWithdrawalIndexDEPRECATED; uint32 internal numberOfPendingWithdrawalsDEPRECATED; /// @dev Total number of executed blocks i.e. blocks[totalBlocksExecuted] points at the latest executed block (block 0 is genesis) uint32 public totalBlocksExecuted; /// @notice Total number of committed blocks i.e. blocks[totalBlocksCommitted] points at the latest committed block uint32 public totalBlocksCommitted; /// @Old rollup block stored data - not used in current version /// @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 BlockDEPRECATED { 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; } mapping(uint32 => BlockDEPRECATED) internal blocksDEPRECATED; /// @dev Flag indicates that a user has exited in the exodus mode certain token balance (per account id and tokenId) mapping(uint32 => mapping(uint32 => bool)) internal performedExodus; /// @dev Flag indicates that exodus (mass exit) mode is triggered /// @dev Once it was raised, it can not be cleared again, and all users must exit bool public exodusMode; /// @dev User authenticated fact hashes for some nonce. mapping(address => mapping(uint32 => bytes32)) public authFacts; /// @notice Old 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 PriorityOperationDEPRECATED { Operations.OpType opType; bytes pubData; uint256 expirationBlock; } /// @dev 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 => PriorityOperationDEPRECATED) internal priorityRequestsDEPRECATED; /// @dev First open priority request id uint64 public firstPriorityRequestId; /// @dev Total number of requests uint64 public totalOpenPriorityRequests; /// @dev 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 internal 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))); } /// @Rollup block stored data /// @member blockNumber Rollup block number /// @member priorityOperations Number of priority operations processed /// @member pendingOnchainOperationsHash Hash of all operations that must be processed after verify /// @member timestamp Rollup block timestamp, have the same format as Ethereum block constant /// @member stateHash Root hash of the rollup state /// @member commitment Verified input for the zkSync circuit struct StoredBlockInfo { uint32 blockNumber; uint64 priorityOperations; bytes32 pendingOnchainOperationsHash; uint256 timestamp; bytes32 stateHash; bytes32 commitment; } /// @notice Returns the keccak hash of the ABI-encoded StoredBlockInfo function hashStoredBlockInfo(StoredBlockInfo memory _storedBlockInfo) internal pure returns (bytes32) { return keccak256(abi.encode(_storedBlockInfo)); } /// @dev Stored hashed StoredBlockInfo for some block number mapping(uint32 => bytes32) public storedBlockHashes; /// @dev Total blocks proven. uint32 public totalBlocksProven; /// @notice Priority Operation container /// @member hashedPubData Hashed priority operation public data /// @member expirationBlock Expiration block number (ETH block) for this request (must be satisfied before) /// @member opType Priority operation type struct PriorityOperation { bytes20 hashedPubData; uint64 expirationBlock; Operations.OpType opType; } /// @dev 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) internal priorityRequests; /// @dev Timer for authFacts entry reset (address, nonce -> timer). /// @dev Used when user wants to reset `authFacts` for some nonce. mapping(address => mapping(uint32 => uint256)) public authFactsResetTimer; mapping(uint32 => address) internal withdrawnNFTs; mapping(uint32 => Operations.WithdrawNFT) internal pendingWithdrawnNFTs; AdditionalZkSync internal additionalZkSync; /// @dev Upgrade notice period, possibly shorten by the security council uint256 internal approvedUpgradeNoticePeriod; /// @dev Upgrade start timestamp (as seconds since unix epoch) /// @dev Will be equal to zero in case of not active upgrade mode uint256 internal upgradeStartTimestamp; /// @dev Stores boolean flags which means the confirmations of the upgrade for each member of security council /// @dev Will store zeroes in case of not active upgrade mode mapping(uint256 => bool) internal securityCouncilApproves; uint256 internal numberOfApprovalsFromSecurityCouncil; /// @notice Checks that current state not is exodus mode function requireActive() internal view { require(!exodusMode, "L"); // exodus mode activated } }
pragma solidity ^0.7.0; // SPDX-License-Identifier: MIT OR Apache-2.0 /// @title zkSync configuration constants /// @author Matter Labs contract Config { /// @dev ERC20 tokens and ETH withdrawals gas limit, used only for complete withdrawals uint256 internal constant WITHDRAWAL_GAS_LIMIT = 100000; /// @dev NFT withdrawals gas limit, used only for complete withdrawals uint256 internal constant WITHDRAWAL_NFT_GAS_LIMIT = 300000; /// @dev Bytes in one chunk uint8 internal constant CHUNK_BYTES = 10; /// @dev zkSync address length uint8 internal constant ADDRESS_BYTES = 20; uint8 internal constant PUBKEY_HASH_BYTES = 20; /// @dev Public key bytes length uint8 internal constant PUBKEY_BYTES = 32; /// @dev Ethereum signature r/s bytes length uint8 internal constant ETH_SIGN_RS_BYTES = 32; /// @dev Success flag bytes length uint8 internal constant SUCCESS_FLAG_BYTES = 1; /// @dev Max amount of tokens registered in the network (excluding ETH, which is hardcoded as tokenId = 0) uint32 internal constant MAX_AMOUNT_OF_REGISTERED_TOKENS = 1023; /// @dev Max account id that could be registered in the network uint32 internal constant MAX_ACCOUNT_ID = 16777215; /// @dev Expected average period of block creation uint256 internal constant BLOCK_PERIOD = 15 seconds; /// @dev ETH blocks verification expectation /// @dev Blocks can be reverted if they are not verified for at least EXPECT_VERIFICATION_IN. /// @dev If set to 0 validator can revert blocks at any time. uint256 internal constant EXPECT_VERIFICATION_IN = 0 hours / BLOCK_PERIOD; uint256 internal constant NOOP_BYTES = 1 * CHUNK_BYTES; uint256 internal constant DEPOSIT_BYTES = 6 * CHUNK_BYTES; uint256 internal constant MINT_NFT_BYTES = 5 * CHUNK_BYTES; uint256 internal constant TRANSFER_TO_NEW_BYTES = 6 * CHUNK_BYTES; uint256 internal constant PARTIAL_EXIT_BYTES = 6 * CHUNK_BYTES; uint256 internal constant TRANSFER_BYTES = 2 * CHUNK_BYTES; uint256 internal constant FORCED_EXIT_BYTES = 6 * CHUNK_BYTES; uint256 internal constant WITHDRAW_NFT_BYTES = 10 * CHUNK_BYTES; /// @dev Full exit operation length uint256 internal constant FULL_EXIT_BYTES = 11 * CHUNK_BYTES; /// @dev ChangePubKey operation length uint256 internal constant CHANGE_PUBKEY_BYTES = 6 * CHUNK_BYTES; /// @dev Expiration delta for priority request to be satisfied (in seconds) /// @dev NOTE: Priority expiration should be > (EXPECT_VERIFICATION_IN * BLOCK_PERIOD) /// @dev otherwise incorrect block with priority op could not be reverted. uint256 internal constant PRIORITY_EXPIRATION_PERIOD = 14 days; /// @dev Expiration delta for priority request to be satisfied (in ETH blocks) uint256 internal constant PRIORITY_EXPIRATION = PRIORITY_EXPIRATION_PERIOD/BLOCK_PERIOD; /// @dev 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 internal constant MAX_PRIORITY_REQUESTS_TO_DELETE_IN_VERIFY = 6; /// @dev Reserved time for users to send full exit priority operation in case of an upgrade (in seconds) uint256 internal constant MASS_FULL_EXIT_PERIOD = 5 days; /// @dev Reserved time for users to withdraw funds from full exit priority operation in case of an upgrade (in seconds) uint256 internal constant TIME_TO_WITHDRAW_FUNDS_FROM_FULL_EXIT = 2 days; /// @dev Notice period before activation preparation status of upgrade mode (in seconds) /// @dev 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. uint256 internal constant UPGRADE_NOTICE_PERIOD = MASS_FULL_EXIT_PERIOD+PRIORITY_EXPIRATION_PERIOD+TIME_TO_WITHDRAW_FUNDS_FROM_FULL_EXIT; /// @dev Timestamp - seconds since unix epoch uint256 internal constant COMMIT_TIMESTAMP_NOT_OLDER = 24 hours; /// @dev Maximum available error between real commit block timestamp and analog used in the verifier (in seconds) /// @dev Must be used cause miner's `block.timestamp` value can differ on some small value (as we know - 15 seconds) uint256 internal constant COMMIT_TIMESTAMP_APPROXIMATION_DELTA = 15 minutes; /// @dev Bit mask to apply for verifier public input before verifying. uint256 internal constant INPUT_MASK = 14474011154664524427946373126085988481658748083205070504932198000989141204991; /// @dev Auth fact reset timelock. uint256 internal constant AUTH_FACT_RESET_TIMELOCK = 1 days; /// @dev Max deposit of ERC20 token that is possible to deposit uint128 internal constant MAX_DEPOSIT_AMOUNT = 20282409603651670423947251286015; uint32 internal constant SPECIAL_ACCOUNT_ID = 16777215; address internal constant SPECIAL_ACCOUNT_ADDRESS = address(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF); uint32 internal constant SPECIAL_NFT_TOKEN_ID = 2147483646; uint32 internal constant MAX_FUNGIBLE_TOKEN_ID = 65535; uint256 internal constant SECURITY_COUNCIL_MEMBERS_NUMBER = 15; string internal constant name = "ZkSync"; string internal constant version = "1.0"; bytes32 internal constant EIP712_DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,string version,uint256 chainId)"); bytes32 internal constant EIP712_CHANGEPUBKEY_TYPEHASH = keccak256("ChangePubKey(bytes20 pubKeyHash,uint32 nonce,uint32 accountId)"); }
pragma solidity ^0.7.0; // SPDX-License-Identifier: MIT OR Apache-2.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 funds are withdrawn from the zkSync state and contract event Withdrawal(address indexed owner, uint16 indexed tokenId, uint128 amount); /// @notice Event emitted when user funds are withdrawn from the zkSync state but not from contract event WithdrawalPending( uint16 indexed tokenId, address indexed recipient, uint128 amount, Operations.WithdrawalType withdrawalType ); /// @notice Event emitted when user NFT is withdrawn from the zkSync state and contract event WithdrawalNFT(uint32 indexed tokenId); /// @notice Event emitted when user NFT is withdrawn from the zkSync state but not from contract event WithdrawalNFTPending(uint32 indexed tokenId); /// @notice Event emitted when user funds are deposited to the zkSync contract event Deposit(uint16 indexed tokenId, uint128 amount); /// @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 Approve cut of upgrade notice period by addr event ApproveCutUpgradeNoticePeriod(address indexed addr); /// @notice Notice period changed event NoticePeriodChange(uint256 newNoticePeriod); } /// @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(uint256 indexed versionId, address indexed upgradeable); /// @notice Upgrade mode enter event event NoticePeriodStart( uint256 indexed versionId, address[] newTargets, uint256 noticePeriod // notice period (in seconds) ); /// @notice Upgrade mode cancel event event UpgradeCancel(uint256 indexed versionId); /// @notice Upgrade mode preparation status event event PreparationStart(uint256 indexed versionId); /// @notice Upgrade mode complete event event UpgradeComplete(uint256 indexed versionId, address[] newTargets); }
pragma solidity ^0.7.0; // SPDX-License-Identifier: MIT OR Apache-2.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(uint256(self), 2); } function toBytesFromUInt24(uint24 self) internal pure returns (bytes memory _bts) { return toBytesFromUIntTruncated(uint256(self), 3); } function toBytesFromUInt32(uint32 self) internal pure returns (bytes memory _bts) { return toBytesFromUIntTruncated(uint256(self), 4); } function toBytesFromUInt128(uint128 self) internal pure returns (bytes memory _bts) { return toBytesFromUIntTruncated(uint256(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(uint256 self, uint8 byteLength) private pure returns (bytes memory bts) { require(byteLength <= 32, "Q"); bts = new bytes(byteLength); // Even though the bytes will allocate a full word, we don't want // any potential garbage bytes in there. uint256 data = self << ((32 - byteLength) * 8); assembly { mstore( add(bts, 32), // BYTES_HEADER_SIZE 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(uint256(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, "R"); 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), "S"); 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, "T"); 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, "U"); 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, "V"); 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, "W"); 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, "X"); 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, "Y"); 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, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_bytes.length >= (_start + _length), "Z"); // bytes length is less then start byte + length bytes bytes memory tempBytes = new bytes(_length); if (_length != 0) { 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 newOffset - offset + amount of bytes read /// @return data - actually read data // NOTE: theoretically possible overflow of (_offset + _length) function read( bytes memory _data, uint256 _offset, uint256 _length ) internal pure returns (uint256 newOffset, bytes memory data) { data = slice(_data, _offset, _length); newOffset = _offset + _length; } // NOTE: theoretically possible overflow of (_offset + 1) function readBool(bytes memory _data, uint256 _offset) internal pure returns (uint256 newOffset, bool r) { newOffset = _offset + 1; r = uint8(_data[_offset]) != 0; } // NOTE: theoretically possible overflow of (_offset + 1) function readUint8(bytes memory _data, uint256 _offset) internal pure returns (uint256 newOffset, uint8 r) { newOffset = _offset + 1; r = uint8(_data[_offset]); } // NOTE: theoretically possible overflow of (_offset + 2) function readUInt16(bytes memory _data, uint256 _offset) internal pure returns (uint256 newOffset, uint16 r) { newOffset = _offset + 2; r = bytesToUInt16(_data, _offset); } // NOTE: theoretically possible overflow of (_offset + 3) function readUInt24(bytes memory _data, uint256 _offset) internal pure returns (uint256 newOffset, uint24 r) { newOffset = _offset + 3; r = bytesToUInt24(_data, _offset); } // NOTE: theoretically possible overflow of (_offset + 4) function readUInt32(bytes memory _data, uint256 _offset) internal pure returns (uint256 newOffset, uint32 r) { newOffset = _offset + 4; r = bytesToUInt32(_data, _offset); } // NOTE: theoretically possible overflow of (_offset + 16) function readUInt128(bytes memory _data, uint256 _offset) internal pure returns (uint256 newOffset, uint128 r) { newOffset = _offset + 16; r = bytesToUInt128(_data, _offset); } // NOTE: theoretically possible overflow of (_offset + 20) function readUInt160(bytes memory _data, uint256 _offset) internal pure returns (uint256 newOffset, uint160 r) { newOffset = _offset + 20; r = bytesToUInt160(_data, _offset); } // NOTE: theoretically possible overflow of (_offset + 20) function readAddress(bytes memory _data, uint256 _offset) internal pure returns (uint256 newOffset, address r) { newOffset = _offset + 20; r = bytesToAddress(_data, _offset); } // NOTE: theoretically possible overflow of (_offset + 20) function readBytes20(bytes memory _data, uint256 _offset) internal pure returns (uint256 newOffset, bytes20 r) { newOffset = _offset + 20; r = bytesToBytes20(_data, _offset); } // NOTE: theoretically possible overflow of (_offset + 32) function readBytes32(bytes memory _data, uint256 _offset) internal pure returns (uint256 newOffset, bytes32 r) { newOffset = _offset + 32; r = bytesToBytes32(_data, _offset); } /// Trim bytes into single word function trim(bytes memory _data, uint256 _newLength) internal pure returns (uint256 r) { require(_newLength <= 0x20, "10"); // new_length is longer than word require(_data.length >= _newLength, "11"); // data is to short uint256 a; assembly { a := mload(add(_data, 0x20)) // load bytes into uint256 } return a >> ((0x20 - _newLength) * 8); } // Helper function for hex conversion. function halfByteToHex(bytes1 _byte) internal pure returns (bytes1 _hexByte) { require(uint8(_byte) < 0x10, "hbh11"); // half byte's value is out of 0..15 range. // "FEDCBA9876543210" ASCII-encoded, shifted and automatically truncated. return bytes1(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; } }
pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; // SPDX-License-Identifier: MIT OR Apache-2.0 import "./Bytes.sol"; import "./Utils.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, ForcedExit, MintNFT, WithdrawNFT, Swap } /// @notice zkSync withdrawal types enum WithdrawalType { PartialExit, ForcedExit, FullExit } // Byte lengths uint8 internal constant OP_TYPE_BYTES = 1; uint8 internal constant TOKEN_BYTES = 4; uint8 internal constant PUBKEY_BYTES = 32; uint8 internal constant NONCE_BYTES = 4; uint8 internal constant PUBKEY_HASH_BYTES = 20; uint8 internal constant ADDRESS_BYTES = 20; uint8 internal constant CONTENT_HASH_BYTES = 32; /// @dev Packed fee bytes lengths uint8 internal constant FEE_BYTES = 2; /// @dev zkSync account id bytes lengths uint8 internal constant ACCOUNT_ID_BYTES = 4; /// @dev zkSync nft serial id bytes lengths uint8 internal constant NFT_SERIAL_ID_BYTES = 4; uint8 internal constant AMOUNT_BYTES = 16; /// @dev Signature (for example full exit signature) bytes length uint8 internal constant SIGNATURE_BYTES = 64; // Deposit pubdata struct Deposit { // uint8 opType uint32 accountId; uint32 tokenId; uint128 amount; address owner; } uint256 internal constant PACKED_DEPOSIT_PUBDATA_BYTES = OP_TYPE_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. uint256 offset = OP_TYPE_BYTES; (offset, parsed.accountId) = Bytes.readUInt32(_data, offset); // accountId (offset, parsed.tokenId) = Bytes.readUInt32(_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, "N"); // reading invalid deposit pubdata size } /// Serialize deposit pubdata function writeDepositPubdataForPriorityQueue(Deposit memory op) internal pure returns (bytes memory buf) { buf = abi.encodePacked( uint8(OpType.Deposit), bytes4(0), // accountId (ignored) (update when ACCOUNT_ID_BYTES is changed) op.tokenId, // tokenId op.amount, // amount op.owner // owner ); } /// @notice Write deposit pubdata for priority queue check. function checkDepositInPriorityQueue(Deposit memory op, bytes20 hashedPubdata) internal pure returns (bool) { return Utils.hashBytesToBytes20(writeDepositPubdataForPriorityQueue(op)) == hashedPubdata; } // FullExit pubdata struct FullExit { // uint8 opType uint32 accountId; address owner; uint32 tokenId; uint128 amount; uint32 nftCreatorAccountId; address nftCreatorAddress; uint32 nftSerialId; bytes32 nftContentHash; } uint256 public constant PACKED_FULL_EXIT_PUBDATA_BYTES = OP_TYPE_BYTES + ACCOUNT_ID_BYTES + ADDRESS_BYTES + TOKEN_BYTES + AMOUNT_BYTES + ACCOUNT_ID_BYTES + ADDRESS_BYTES + NFT_SERIAL_ID_BYTES + CONTENT_HASH_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. uint256 offset = OP_TYPE_BYTES; (offset, parsed.accountId) = Bytes.readUInt32(_data, offset); // accountId (offset, parsed.owner) = Bytes.readAddress(_data, offset); // owner (offset, parsed.tokenId) = Bytes.readUInt32(_data, offset); // tokenId (offset, parsed.amount) = Bytes.readUInt128(_data, offset); // amount (offset, parsed.nftCreatorAccountId) = Bytes.readUInt32(_data, offset); // nftCreatorAccountId (offset, parsed.nftCreatorAddress) = Bytes.readAddress(_data, offset); // nftCreatorAddress (offset, parsed.nftSerialId) = Bytes.readUInt32(_data, offset); // nftSerialId (offset, parsed.nftContentHash) = Bytes.readBytes32(_data, offset); // nftContentHash require(offset == PACKED_FULL_EXIT_PUBDATA_BYTES, "O"); // reading invalid full exit pubdata size } function writeFullExitPubdataForPriorityQueue(FullExit memory op) internal pure returns (bytes memory buf) { buf = abi.encodePacked( uint8(OpType.FullExit), op.accountId, // accountId op.owner, // owner op.tokenId, // tokenId uint128(0), // amount -- ignored uint32(0), // nftCreatorAccountId -- ignored address(0), // nftCreatorAddress -- ignored uint32(0), // nftSerialId -- ignored bytes32(0) // nftContentHash -- ignored ); } function checkFullExitInPriorityQueue(FullExit memory op, bytes20 hashedPubdata) internal pure returns (bool) { return Utils.hashBytesToBytes20(writeFullExitPubdataForPriorityQueue(op)) == hashedPubdata; } // PartialExit pubdata struct PartialExit { //uint8 opType; -- present in pubdata, ignored at serialization //uint32 accountId; -- present in pubdata, ignored at serialization uint32 tokenId; uint128 amount; //uint16 fee; -- present in pubdata, ignored at serialization address owner; } function readPartialExitPubdata(bytes memory _data) 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. uint256 offset = OP_TYPE_BYTES + ACCOUNT_ID_BYTES; // opType + accountId (ignored) (offset, parsed.tokenId) = Bytes.readUInt32(_data, offset); // tokenId (offset, parsed.amount) = Bytes.readUInt128(_data, offset); // amount offset += FEE_BYTES; // fee (ignored) (offset, parsed.owner) = Bytes.readAddress(_data, offset); // owner } // ForcedExit pubdata struct ForcedExit { //uint8 opType; -- present in pubdata, ignored at serialization //uint32 initiatorAccountId; -- present in pubdata, ignored at serialization //uint32 targetAccountId; -- present in pubdata, ignored at serialization uint32 tokenId; uint128 amount; //uint16 fee; -- present in pubdata, ignored at serialization address target; } function readForcedExitPubdata(bytes memory _data) internal pure returns (ForcedExit memory parsed) { // NOTE: there is no check that variable sizes are same as constants (i.e. TOKEN_BYTES), fix if possible. uint256 offset = OP_TYPE_BYTES + ACCOUNT_ID_BYTES * 2; // opType + initiatorAccountId + targetAccountId (ignored) (offset, parsed.tokenId) = Bytes.readUInt32(_data, offset); // tokenId (offset, parsed.amount) = Bytes.readUInt128(_data, offset); // amount offset += FEE_BYTES; // fee (ignored) (offset, parsed.target) = Bytes.readAddress(_data, offset); // target } // ChangePubKey enum ChangePubkeyType { ECRECOVER, CREATE2, OldECRECOVER, ECRECOVERV2, EIP712 } struct ChangePubKey { // uint8 opType; -- present in pubdata, ignored at serialization uint32 accountId; bytes20 pubKeyHash; address owner; uint32 nonce; //uint32 tokenId; -- present in pubdata, ignored at serialization //uint16 fee; -- present in pubdata, ignored at serialization } function readChangePubKeyPubdata(bytes memory _data) internal pure returns (ChangePubKey memory parsed) { uint256 offset = OP_TYPE_BYTES; (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 } struct WithdrawNFT { //uint8 opType; -- present in pubdata, ignored at serialization //uint32 accountId; -- present in pubdata, ignored at serialization uint32 creatorAccountId; address creatorAddress; uint32 serialId; bytes32 contentHash; address receiver; uint32 tokenId; //uint32 feeTokenId; //uint16 fee; -- present in pubdata, ignored at serialization } function readWithdrawNFTPubdata(bytes memory _data) internal pure returns (WithdrawNFT memory parsed) { uint256 offset = OP_TYPE_BYTES + ACCOUNT_ID_BYTES; // opType + accountId (ignored) (offset, parsed.creatorAccountId) = Bytes.readUInt32(_data, offset); (offset, parsed.creatorAddress) = Bytes.readAddress(_data, offset); (offset, parsed.serialId) = Bytes.readUInt32(_data, offset); (offset, parsed.contentHash) = Bytes.readBytes32(_data, offset); (offset, parsed.receiver) = Bytes.readAddress(_data, offset); (offset, parsed.tokenId) = Bytes.readUInt32(_data, offset); } }
pragma solidity ^0.7.0; // SPDX-License-Identifier: MIT OR Apache-2.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 (uint256); /// @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); }
pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; // SPDX-License-Identifier: MIT OR Apache-2.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 additional main contract /// @author Matter Labs contract AdditionalZkSync is Storage, Config, Events, ReentrancyGuard { using SafeMath for uint256; using SafeMathUInt128 for uint128; function increaseBalanceToWithdraw(bytes22 _packedBalanceKey, uint128 _amount) internal { uint128 balance = pendingBalances[_packedBalanceKey].balanceToWithdraw; pendingBalances[_packedBalanceKey] = PendingBalance(balance.add(_amount), FILLED_GAS_RESERVE_VALUE); } /// @notice Withdraws token from ZkSync to root chain in case of exodus mode. User must provide proof that he owns funds /// @param _storedBlockInfo Last verified block /// @param _owner Owner of the account /// @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 performExodus( StoredBlockInfo calldata _storedBlockInfo, address _owner, uint32 _accountId, uint32 _tokenId, uint128 _amount, uint32 _nftCreatorAccountId, address _nftCreatorAddress, uint32 _nftSerialId, bytes32 _nftContentHash, uint256[] calldata _proof ) external nonReentrant { require(_accountId <= MAX_ACCOUNT_ID, "e"); require(_accountId != SPECIAL_ACCOUNT_ID, "v"); require(_tokenId < SPECIAL_NFT_TOKEN_ID, "T"); require(exodusMode, "s"); // must be in exodus mode require(!performedExodus[_accountId][_tokenId], "t"); // already exited require(storedBlockHashes[totalBlocksExecuted] == hashStoredBlockInfo(_storedBlockInfo), "u"); // incorrect stored block info bool proofCorrect = verifier.verifyExitProof( _storedBlockInfo.stateHash, _accountId, _owner, _tokenId, _amount, _nftCreatorAccountId, _nftCreatorAddress, _nftSerialId, _nftContentHash, _proof ); require(proofCorrect, "x"); if (_tokenId <= MAX_FUNGIBLE_TOKEN_ID) { bytes22 packedBalanceKey = packAddressAndTokenId(_owner, uint16(_tokenId)); increaseBalanceToWithdraw(packedBalanceKey, _amount); emit WithdrawalPending(uint16(_tokenId), _owner, _amount, Operations.WithdrawalType.FullExit); } else { require(_amount != 0, "Z"); // Unsupported nft amount Operations.WithdrawNFT memory withdrawNftOp = Operations.WithdrawNFT( _nftCreatorAccountId, _nftCreatorAddress, _nftSerialId, _nftContentHash, _owner, _tokenId ); pendingWithdrawnNFTs[_tokenId] = withdrawNftOp; emit WithdrawalNFTPending(_tokenId); } performedExodus[_accountId][_tokenId] = true; } function cancelOutstandingDepositsForExodusMode(uint64 _n, bytes[] calldata _depositsPubdata) external nonReentrant { require(exodusMode, "8"); // exodus mode not active uint64 toProcess = Utils.minU64(totalOpenPriorityRequests, _n); require(toProcess > 0, "9"); // no deposits to process uint64 currentDepositIdx = 0; for (uint64 id = firstPriorityRequestId; id < firstPriorityRequestId + toProcess; ++id) { if (priorityRequests[id].opType == Operations.OpType.Deposit) { bytes memory depositPubdata = _depositsPubdata[currentDepositIdx]; require(Utils.hashBytesToBytes20(depositPubdata) == priorityRequests[id].hashedPubData, "a"); ++currentDepositIdx; Operations.Deposit memory op = Operations.readDepositPubdata(depositPubdata); bytes22 packedBalanceKey = packAddressAndTokenId(op.owner, uint16(op.tokenId)); pendingBalances[packedBalanceKey].balanceToWithdraw += op.amount; } delete priorityRequests[id]; } firstPriorityRequestId += toProcess; totalOpenPriorityRequests -= toProcess; } uint256 internal constant SECURITY_COUNCIL_THRESHOLD = 9; /// @notice processing new approval of decrease upgrade notice period time to zero /// @param addr address of the account that approved the reduction of the upgrade notice period to zero /// NOTE: does NOT revert if the address is not a security council member or number of approvals is already sufficient function approveCutUpgradeNoticePeriod(address addr) internal { address payable[SECURITY_COUNCIL_MEMBERS_NUMBER] memory SECURITY_COUNCIL_MEMBERS = [ 0xa2602ea835E03fb39CeD30B43d6b6EAf6aDe1769,0x9D5d6D4BaCCEDf6ECE1883456AA785dc996df607,0x002A5dc50bbB8d5808e418Aeeb9F060a2Ca17346,0x71E805aB236c945165b9Cd0bf95B9f2F0A0488c3,0x76C6cE74EAb57254E785d1DcC3f812D274bCcB11,0xFBfF3FF69D65A9103Bf4fdBf988f5271D12B3190,0xAfC2F2D803479A2AF3A72022D54cc0901a0ec0d6,0x4d1E3089042Ab3A93E03CA88B566b99Bd22438C6,0x19eD6cc20D44e5cF4Bb4894F50162F72402d8567,0x39415255619783A2E71fcF7d8f708A951d92e1b6,0x399a6a13D298CF3F41a562966C1a450136Ea52C2,0xee8AE1F1B4B1E1956C8Bda27eeBCE54Cf0bb5eaB,0xe7CCD4F3feA7df88Cf9B59B30f738ec1E049231f,0xA093284c707e207C36E3FEf9e0B6325fd9d0e33B,0x225d3822De44E58eE935440E0c0B829C4232086e ]; for (uint256 id = 0; id < SECURITY_COUNCIL_MEMBERS_NUMBER; ++id) { if (SECURITY_COUNCIL_MEMBERS[id] == addr) { // approve cut upgrade notice period if needed if (!securityCouncilApproves[id]) { securityCouncilApproves[id] = true; numberOfApprovalsFromSecurityCouncil += 1; emit ApproveCutUpgradeNoticePeriod(addr); if (numberOfApprovalsFromSecurityCouncil >= SECURITY_COUNCIL_THRESHOLD) { if (approvedUpgradeNoticePeriod > 0) { approvedUpgradeNoticePeriod = 0; emit NoticePeriodChange(approvedUpgradeNoticePeriod); } } } break; } } } /// @notice approve to decrease upgrade notice period time to zero /// NOTE: сan only be called after the start of the upgrade function cutUpgradeNoticePeriod(bytes32 targetsHash) external nonReentrant { require(upgradeStartTimestamp != 0, "p1"); require(getUpgradeTargetsHash() == targetsHash, "p3"); // given targets are not in the active upgrade approveCutUpgradeNoticePeriod(msg.sender); } /// @notice approve to decrease upgrade notice period time to zero by signatures /// NOTE: Can accept many signatures at a time, thus it is possible /// to completely cut the upgrade notice period in one transaction function cutUpgradeNoticePeriodBySignature(bytes[] calldata signatures) external nonReentrant { require(upgradeStartTimestamp != 0, "p2"); bytes32 targetsHash = getUpgradeTargetsHash(); // The Message includes a hash of the addresses of the contracts to which the upgrade will take place to prevent reuse signature. bytes32 messageHash = keccak256( abi.encodePacked( "\x19Ethereum Signed Message:\n110", "Approved new ZkSync's target contracts hash\n0x", Bytes.bytesToHexASCIIBytes(abi.encodePacked(targetsHash)) ) ); for (uint256 i = 0; i < signatures.length; ++i) { address recoveredAddress = Utils.recoverAddressFromEthSignature(signatures[i], messageHash); approveCutUpgradeNoticePeriod(recoveredAddress); } } /// @return hash of the concatenation of targets for which there is an upgrade /// NOTE: revert if upgrade is not active at this moment function getUpgradeTargetsHash() internal view returns (bytes32) { // Get the addresses of contracts that are being prepared for the upgrade. address gatekeeper = 0x38A43F4330f24fe920F943409709fc9A6084C939; (bool success0, bytes memory newTarget0) = gatekeeper.staticcall( abi.encodeWithSignature("nextTargets(uint256)", 0) ); (bool success1, bytes memory newTarget1) = gatekeeper.staticcall( abi.encodeWithSignature("nextTargets(uint256)", 1) ); (bool success2, bytes memory newTarget2) = gatekeeper.staticcall( abi.encodeWithSignature("nextTargets(uint256)", 2) ); require(success0 && success1 && success2, "p5"); // failed to get new targets address newTargetAddress0 = abi.decode(newTarget0, (address)); address newTargetAddress1 = abi.decode(newTarget1, (address)); address newTargetAddress2 = abi.decode(newTarget2, (address)); return keccak256(abi.encodePacked(newTargetAddress0, newTargetAddress1, newTargetAddress2)); } /// @notice Set data for changing pubkey hash using onchain authorization. /// Transaction author (msg.sender) should be L2 account address /// @notice New pubkey hash can be reset, to do that user should send two transactions: /// 1) First `setAuthPubkeyHash` transaction for already used `_nonce` will set timer. /// 2) After `AUTH_FACT_RESET_TIMELOCK` time is passed second `setAuthPubkeyHash` transaction will reset pubkey hash for `_nonce`. /// @param _pubkeyHash New pubkey hash /// @param _nonce Nonce of the change pubkey L2 transaction function setAuthPubkeyHash(bytes calldata _pubkeyHash, uint32 _nonce) external nonReentrant { requireActive(); require(_pubkeyHash.length == PUBKEY_HASH_BYTES, "y"); // PubKeyHash should be 20 bytes. if (authFacts[msg.sender][_nonce] == bytes32(0)) { authFacts[msg.sender][_nonce] = keccak256(_pubkeyHash); } else { uint256 currentResetTimer = authFactsResetTimer[msg.sender][_nonce]; if (currentResetTimer == 0) { authFactsResetTimer[msg.sender][_nonce] = block.timestamp; } else { require(block.timestamp.sub(currentResetTimer) >= AUTH_FACT_RESET_TIMELOCK, "z"); authFactsResetTimer[msg.sender][_nonce] = 0; authFacts[msg.sender][_nonce] = keccak256(_pubkeyHash); } } } /// @notice Reverts unverified blocks function revertBlocks(StoredBlockInfo[] calldata _blocksToRevert) external nonReentrant { requireActive(); governance.requireActiveValidator(msg.sender); uint32 blocksCommitted = totalBlocksCommitted; uint32 blocksToRevert = Utils.minU32(uint32(_blocksToRevert.length), blocksCommitted - totalBlocksExecuted); uint64 revertedPriorityRequests = 0; for (uint32 i = 0; i < blocksToRevert; ++i) { StoredBlockInfo memory storedBlockInfo = _blocksToRevert[i]; require(storedBlockHashes[blocksCommitted] == hashStoredBlockInfo(storedBlockInfo), "r"); // incorrect stored block info delete storedBlockHashes[blocksCommitted]; --blocksCommitted; revertedPriorityRequests += storedBlockInfo.priorityOperations; } totalBlocksCommitted = blocksCommitted; totalCommittedPriorityRequests -= revertedPriorityRequests; if (totalBlocksCommitted < totalBlocksProven) { totalBlocksProven = totalBlocksCommitted; } emit BlocksRevert(totalBlocksExecuted, blocksCommitted); } }
pragma solidity ^0.7.0; // SPDX-License-Identifier: UNLICENSED /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external; /** * @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. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external; /** * @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); }
pragma solidity ^0.7.0; // SPDX-License-Identifier: MIT OR Apache-2.0 import "./Config.sol"; import "./Utils.sol"; import "./NFTFactory.sol"; import "./TokenGovernance.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 Default nft factory has set event SetDefaultNFTFactory(address indexed factory); /// @notice NFT factory registered new creator account event NFTFactoryRegisteredCreator( uint32 indexed creatorAccountId, address indexed creatorAddress, address factoryAddress ); /// @notice Governor changed event NewGovernor(address newGovernor); /// @notice Token Governance changed event NewTokenGovernance(TokenGovernance newTokenGovernance); /// @notice Validator's status changed event ValidatorStatusUpdate(address indexed validatorAddress, bool isActive); event TokenPausedUpdate(address indexed token, bool paused); /// @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; /// @notice Paused tokens list, deposits are impossible to create for paused tokens mapping(uint16 => bool) public pausedTokens; /// @notice Address that is authorized to add tokens to the Governance. TokenGovernance public tokenGovernance; /// @notice NFT Creator address to factory address mapping mapping(uint32 => mapping(address => NFTFactory)) public nftFactories; /// @notice Address which will be used if NFT token has no factories NFTFactory public defaultFactory; /// @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 // solhint-disable-next-line no-empty-blocks function upgrade(bytes calldata upgradeParameters) external {} /// @notice Change current governor /// @param _newGovernor Address of the new governor function changeGovernor(address _newGovernor) external { require(_newGovernor != address(0), "1n"); requireGovernor(msg.sender); if (networkGovernor != _newGovernor) { networkGovernor = _newGovernor; emit NewGovernor(_newGovernor); } } /// @notice Change current token governance /// @param _newTokenGovernance Address of the new token governor function changeTokenGovernance(TokenGovernance _newTokenGovernance) external { requireGovernor(msg.sender); if (tokenGovernance != _newTokenGovernance) { tokenGovernance = _newTokenGovernance; emit NewTokenGovernance(_newTokenGovernance); } } /// @notice Add token to the list of networks tokens /// @param _token Token address function addToken(address _token) external { require(msg.sender == address(tokenGovernance), "1E"); require(tokenIds[_token] == 0, "1e"); // token exists require(totalTokens < MAX_AMOUNT_OF_REGISTERED_TOKENS, "1f"); // 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 Pause token deposits for the given token /// @param _tokenAddr Token address /// @param _tokenPaused Token paused status function setTokenPaused(address _tokenAddr, bool _tokenPaused) external { requireGovernor(msg.sender); uint16 tokenId = this.validateTokenAddress(_tokenAddr); if (pausedTokens[tokenId] != _tokenPaused) { pausedTokens[tokenId] = _tokenPaused; emit TokenPausedUpdate(_tokenAddr, _tokenPaused); } } /// @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, "1g"); // only by governor } /// @notice Checks if validator is active /// @param _address Validator address function requireActiveValidator(address _address) external view { require(validators[_address], "1h"); // 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, "1i"); // 0 is not a valid token return tokenId; } function packRegisterNFTFactoryMsg( uint32 _creatorAccountId, address _creatorAddress, address _factoryAddress ) internal pure returns (bytes memory) { return abi.encodePacked( "\x19Ethereum Signed Message:\n141", "\nCreator's account ID in zkSync: ", Bytes.bytesToHexASCIIBytes(abi.encodePacked((_creatorAccountId))), "\nCreator: ", Bytes.bytesToHexASCIIBytes(abi.encodePacked((_creatorAddress))), "\nFactory: ", Bytes.bytesToHexASCIIBytes(abi.encodePacked((_factoryAddress))) ); } /// @notice Register creator corresponding to the factory /// @param _creatorAccountId Creator's zkSync account ID /// @param _creatorAddress NFT creator address /// @param _signature Creator's signature function registerNFTFactoryCreator( uint32 _creatorAccountId, address _creatorAddress, bytes memory _signature ) external { require(address(nftFactories[_creatorAccountId][_creatorAddress]) == address(0), "Q"); bytes32 messageHash = keccak256(packRegisterNFTFactoryMsg(_creatorAccountId, _creatorAddress, msg.sender)); address recoveredAddress = Utils.recoverAddressFromEthSignature(_signature, messageHash); require(recoveredAddress == _creatorAddress, "ws"); nftFactories[_creatorAccountId][_creatorAddress] = NFTFactory(msg.sender); emit NFTFactoryRegisteredCreator(_creatorAccountId, _creatorAddress, msg.sender); } /// @notice Set default factory for our contract. This factory will be used to mint an NFT token that has no factory /// @param _factory Address of NFT factory function setDefaultNFTFactory(address _factory) external { requireGovernor(msg.sender); require(address(_factory) != address(0), "mb1"); // Factory should be non zero require(address(defaultFactory) == address(0), "mb2"); // NFTFactory is already set defaultFactory = NFTFactory(_factory); emit SetDefaultNFTFactory(_factory); } function getNFTFactory(uint32 _creatorAccountId, address _creatorAddress) external view returns (NFTFactory) { NFTFactory _factory = nftFactories[_creatorAccountId][_creatorAddress]; // even if the factory is undefined or has been destroyed, the user can mint NFT if (address(_factory) == address(0) || !isContract(address(_factory))) { require(address(defaultFactory) != address(0), "fs"); // NFTFactory does not set return defaultFactory; } else { return _factory; } } /// @return whether the address is a contract or not /// NOTE: for smart contracts that called `selfdestruct` will return a negative result function isContract(address _address) internal view returns (bool) { uint256 contractSize; assembly { contractSize := extcodesize(_address) } return contractSize != 0; } }
pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; // SPDX-License-Identifier: MIT OR Apache-2.0 import "./KeysWithPlonkVerifier.sol"; import "./Config.sol"; // Hardcoded constants to avoid accessing store contract Verifier is KeysWithPlonkVerifier, KeysWithPlonkVerifierOld, Config { // solhint-disable-next-line no-empty-blocks 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 // solhint-disable-next-line no-empty-blocks function upgrade(bytes calldata upgradeParameters) external {} function verifyAggregatedBlockProof( uint256[] memory _recursiveInput, uint256[] calldata _proof, uint8[] memory _vkIndexes, uint256[] memory _individualVksInputs, uint256[16] memory _subproofsLimbs ) external view returns (bool) { for (uint256 i = 0; i < _individualVksInputs.length; ++i) { uint256 commitment = _individualVksInputs[i]; _individualVksInputs[i] = commitment & INPUT_MASK; } VerificationKey memory vk = getVkAggregated(uint32(_vkIndexes.length)); return verify_serialized_proof_with_recursion( _recursiveInput, _proof, VK_TREE_ROOT, VK_MAX_INDEX, _vkIndexes, _individualVksInputs, _subproofsLimbs, vk ); } function verifyExitProof( bytes32 _rootHash, uint32 _accountId, address _owner, uint32 _tokenId, uint128 _amount, uint32 _nftCreatorAccountId, address _nftCreatorAddress, uint32 _nftSerialId, bytes32 _nftContentHash, uint256[] calldata _proof ) external view returns (bool) { bytes32 commitment = sha256( abi.encodePacked( _rootHash, _accountId, _owner, _tokenId, _amount, _nftCreatorAccountId, _nftCreatorAddress, _nftSerialId, _nftContentHash ) ); uint256[] memory inputs = new uint256[](1); inputs[0] = uint256(commitment) & INPUT_MASK; ProofOld memory proof = deserialize_proof_old(inputs, _proof); VerificationKeyOld memory vk = getVkExit(); require(vk.num_inputs == inputs.length, "n1"); return verify_old(proof, vk); } }
pragma solidity ^0.7.0; // SPDX-License-Identifier: UNLICENSED interface NFTFactory { function mintNFTFromZkSync( address creator, address recipient, uint32 creatorAccountId, uint32 serialId, bytes32 contentHash, // Even though the token id can fit into the uint32, we still use // the uint256 to preserve consistency with the ERC721 parent contract uint256 tokenId ) external; event MintNFTFromZkSync( address indexed creator, address indexed recipient, uint32 creatorAccountId, uint32 serialId, bytes32 contentHash, uint256 tokenId ); }
pragma solidity ^0.7.0; // SPDX-License-Identifier: MIT OR Apache-2.0 import "./ReentrancyGuard.sol"; import "./Governance.sol"; import "./ITrustedTransfarableERC20.sol"; import "./Utils.sol"; /// @title Token Governance Contract /// @author Matter Labs /// @notice Contract is used to allow anyone to add new ERC20 tokens to zkSync given sufficient payment contract TokenGovernance is ReentrancyGuard { /// @notice Token lister added or removed (see `tokenLister`) event TokenListerUpdate(address indexed tokenLister, bool isActive); /// @notice Listing fee token set event ListingFeeTokenUpdate(ITrustedTransfarableERC20 indexed newListingFeeToken, uint256 newListingFee); /// @notice Listing fee set event ListingFeeUpdate(uint256 newListingFee); /// @notice Maximum number of listed tokens updated event ListingCapUpdate(uint16 newListingCap); /// @notice The treasury (the account which will receive the fee) was updated event TreasuryUpdate(address newTreasury); /// @notice zkSync governance contract Governance public governance; /// @notice Token used to collect listing fee for addition of new token to zkSync network ITrustedTransfarableERC20 public listingFeeToken; /// @notice Token listing fee uint256 public listingFee; /// @notice Max number of tokens that can be listed using this contract uint16 public listingCap; /// @notice Addresses that can list tokens without fee mapping(address => bool) public tokenLister; /// @notice Address that collects listing payments address public treasury; constructor( Governance _governance, ITrustedTransfarableERC20 _listingFeeToken, uint256 _listingFee, uint16 _listingCap, address _treasury ) { initializeReentrancyGuard(); governance = _governance; listingFeeToken = _listingFeeToken; listingFee = _listingFee; listingCap = _listingCap; treasury = _treasury; address governor = governance.networkGovernor(); // We add zkSync governor as a first token lister. tokenLister[governor] = true; emit TokenListerUpdate(governor, true); } /// @notice Adds new ERC20 token to zkSync network. /// @notice If caller is not present in the `tokenLister` map payment of `listingFee` in `listingFeeToken` should be made. /// @notice NOTE: before calling this function make sure to approve `listingFeeToken` transfer for this contract. function addToken(address _token) external nonReentrant { require(_token != address(0), "z1"); // Token should have a non-zero address require(_token != 0xaBEA9132b05A70803a4E85094fD0e1800777fBEF, "z2"); // Address of the token cannot be the same as the address of the main zksync contract require(governance.totalTokens() < listingCap, "can't add more tokens"); // Impossible to add more tokens using this contract if (!tokenLister[msg.sender] && listingFee > 0) { // Collect fees bool feeTransferOk = listingFeeToken.transferFrom(msg.sender, treasury, listingFee); require(feeTransferOk, "fee transfer failed"); // Failed to receive payment for token addition. } governance.addToken(_token); } /// Governance functions (this contract is governed by zkSync governor) /// @notice Set new listing token and fee /// @notice Can be called only by zkSync governor function setListingFeeToken(ITrustedTransfarableERC20 _newListingFeeToken, uint256 _newListingFee) external { governance.requireGovernor(msg.sender); listingFeeToken = _newListingFeeToken; listingFee = _newListingFee; emit ListingFeeTokenUpdate(_newListingFeeToken, _newListingFee); } /// @notice Set new listing fee /// @notice Can be called only by zkSync governor function setListingFee(uint256 _newListingFee) external { governance.requireGovernor(msg.sender); listingFee = _newListingFee; emit ListingFeeUpdate(_newListingFee); } /// @notice Enable or disable token lister. If enabled new tokens can be added by that address without payment /// @notice Can be called only by zkSync governor function setLister(address _listerAddress, bool _active) external { governance.requireGovernor(msg.sender); if (tokenLister[_listerAddress] != _active) { tokenLister[_listerAddress] = _active; emit TokenListerUpdate(_listerAddress, _active); } } /// @notice Change maximum amount of tokens that can be listed using this method /// @notice Can be called only by zkSync governor function setListingCap(uint16 _newListingCap) external { governance.requireGovernor(msg.sender); listingCap = _newListingCap; emit ListingCapUpdate(_newListingCap); } /// @notice Change address that collects payments for listing tokens. /// @notice Can be called only by zkSync governor function setTreasury(address _newTreasury) external { governance.requireGovernor(msg.sender); treasury = _newTreasury; emit TreasuryUpdate(_newTreasury); } }
/// @dev Interface of the ERC20 standard as defined in the EIP. /// 1. Implements only `transfer` and `transferFrom` methods /// 2. These methods return a boolean value in case of a non-revert call /// NOTE: It is expected that if the function returns true, then the user's balance has /// changed exactly by `amount` according to the ERC20 standard. /// Note: Used to perform transfers for tokens that explicitly return a boolean value /// (if the token returns any other data or does not return at all, then the function call will be reverted) interface ITrustedTransfarableERC20 { /** * @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 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); }
pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; // SPDX-License-Identifier: MIT OR Apache-2.0 import "./PlonkCore.sol"; // Hardcoded constants to avoid accessing store contract KeysWithPlonkVerifier is VerifierWithDeserialize { uint256 constant VK_TREE_ROOT = 0x1ffdc7ebe04681d451ae0658a6ad27feb63835b0edf90bdfa203cd8d12282ace; uint8 constant VK_MAX_INDEX = 3; function getVkAggregated(uint32 _proofs) internal pure returns (VerificationKey memory vk) { if (_proofs == uint32(1)) { return getVkAggregated1(); } else if (_proofs == uint32(4)) { return getVkAggregated4(); } else if (_proofs == uint32(8)) { return getVkAggregated8(); } } function getVkAggregated1() internal pure returns(VerificationKey memory vk) { vk.domain_size = 4194304; vk.num_inputs = 1; vk.omega = PairingsBn254.new_fr(0x18c95f1ae6514e11a1b30fd7923947c5ffcec5347f16e91b4dd654168326bede); vk.gate_setup_commitments[0] = PairingsBn254.new_g1( 0x16782f42f191b0b1841c2b6a42b7f0564af065d04818526df6c3ad41fe35f8da, 0x125b9c68c0b931578f8a18fd23ce08e7b7c082ad76404ccece796fa9b3ec0cb0 ); vk.gate_setup_commitments[1] = PairingsBn254.new_g1( 0x2511833eee308a3936b23b27c929942a60aa780747bf32143dc183e873144bfd, 0x1b8d88d78fcc4a36ebe90fbbdc4547442411e0c8d484727d5c7c6eec27ad2df0 ); vk.gate_setup_commitments[2] = PairingsBn254.new_g1( 0x2945641d0c5556aa333ef6c8431e24379b73eccbed7ff3e9425cc64aee1e92ed, 0x25bbf079192cc83f160da9375e7aec3d3d2caac8d831a29b50f5497071fc14c6 ); vk.gate_setup_commitments[3] = PairingsBn254.new_g1( 0x09b3c361e5895a8e074eb9b9a9e57af59966f0464068460adc3f64e58544afa4, 0x0412a017f775dd05af16cf387a1e822c2a7e0f8b7cfabd0eb4eb0f67b20e4ada ); vk.gate_setup_commitments[4] = PairingsBn254.new_g1( 0x244b30447ab3e56bb5a5a7f0ef8463a4047476ea269735a887b3de568b3401a3, 0x2ba860198d5e6e0fd93355cb5f309e7e4c1113a57222830961999b79b83d700f ); vk.gate_setup_commitments[5] = PairingsBn254.new_g1( 0x0e13af99775bf5555c366e9c8d4af25a2e195807b766b422856525c01a38b12d, 0x1787389894222dba5371ab55d512460c5205c1baa0421fc877b183025079a472 ); vk.gate_setup_commitments[6] = PairingsBn254.new_g1( 0x233a03f89c094cf39c89020772d9b912bd0c303d211002ee5afc5c59e241f02b, 0x04fa51fca1b17399bbbf2b99f17bbce6af1f50b085add4c41ac4ea64f65f4674 ); vk.gate_selector_commitments[0] = PairingsBn254.new_g1( 0x1ca088ed531e65b722c8b48568359bbe11051b86f1a8e8951eacc615d9faed3b, 0x074b06c09de93dd79e070a9ded635e21a34d7178e9a670766e8208149c28e339 ); vk.gate_selector_commitments[1] = PairingsBn254.new_g1( 0x2b4c77c0d47676559061b47968a044aec625cb907181457428e5d08df9b27ef8, 0x1c1be561bdc3eba16162886a2943882157f98ed8246f2063028497f1c108fa93 ); vk.copy_permutation_commitments[0] = PairingsBn254.new_g1( 0x238fd7f2cbc3c3e5899483633c78f051e6d6d25f31aaa6b32b863d55b20d641a, 0x1f9877b625eaae7a084582a2ffce326a6a5558f3efdb3367037098c4ca25a647 ); vk.copy_permutation_commitments[1] = PairingsBn254.new_g1( 0x0b126f60653e371f3f2a85301f16e9cf4af04922a2725fc131b17e90e13d0d84, 0x13bc3f0c7475b74591827463943b35cfd05adb7094a79eeeee2067e8e28a8e84 ); vk.copy_permutation_commitments[2] = PairingsBn254.new_g1( 0x06cae3c1e5b43afb4dda3243c99da693a27eba065fd61a873e99e2c85fd22719, 0x14343c6bdcc85b01b053f26aa3c473cb2f24747ba6d6b90b2323b24f3dfd127e ); vk.copy_permutation_commitments[3] = PairingsBn254.new_g1( 0x217564e2c710d050161b57ef2700e1676251a6d457c4b0d94c41a4492d6dcea3, 0x2365779642d63803d0265a7cc666b3af6ad92b7e9ef38d9113db1208b83f0732 ); vk.copy_permutation_non_residues[0] = PairingsBn254.new_fr( 0x0000000000000000000000000000000000000000000000000000000000000005 ); vk.copy_permutation_non_residues[1] = PairingsBn254.new_fr( 0x0000000000000000000000000000000000000000000000000000000000000007 ); vk.copy_permutation_non_residues[2] = PairingsBn254.new_fr( 0x000000000000000000000000000000000000000000000000000000000000000a ); vk.g2_x = PairingsBn254.new_g2( [0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1, 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0], [0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4, 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55] ); } function getVkAggregated4() internal pure returns(VerificationKey memory vk) { vk.domain_size = 8388608; vk.num_inputs = 1; vk.omega = PairingsBn254.new_fr(0x1283ba6f4b7b1a76ba2008fe823128bea4adb9269cbfd7c41c223be65bc60863); vk.gate_setup_commitments[0] = PairingsBn254.new_g1( 0x1878d6c837a0f16cb055d3a4e79fba0d85de670dacd708dadd55407b0619796d, 0x0b3282e52a38ecec63ba42710e8d1ad5c8715c7ed07ce217a3eec747a3f37d76 ); vk.gate_setup_commitments[1] = PairingsBn254.new_g1( 0x07425bcaf480e377886678d5b5432f0945e3fc952126503a7b672dc4b03f2c26, 0x155b8003ea27945bf43fb5f43291f76e2aa361e0ec81550c0af66dcd1dc8077e ); vk.gate_setup_commitments[2] = PairingsBn254.new_g1( 0x1292b8795f05fc50782ea7303e2b65a7b2f0e1cc3dead51dfa0b9d2183e5d907, 0x220d344a384ac53f682e1be6c69407a1fadd0a589de36b95ddc4da05693ba679 ); vk.gate_setup_commitments[3] = PairingsBn254.new_g1( 0x283412c1942c0cb3fffc935aab313a37510888bd5ae5972d8d67edc2312af895, 0x1040e655967354e7ae9227c6200c2256cdcbb707e7158b66462aba23d96b8de2 ); vk.gate_setup_commitments[4] = PairingsBn254.new_g1( 0x2abe282377038904420434202c11a4f849e64babd436b93192d8d9c34d28ce44, 0x19f0ed010326da1cf8ac93a0f73617ab7c9acb30a0c23a26db9ec19ab6a52fcb ); vk.gate_setup_commitments[5] = PairingsBn254.new_g1( 0x236f01e67b19be0e7487100a14fd04a05a83a5660966ace987c5248f8c883459, 0x0ebe824fb1e778491bcb8091d2adbc18dceda4fa9ee191b71c5834a71c533c41 ); vk.gate_setup_commitments[6] = PairingsBn254.new_g1( 0x2ad3c37aa0b1335f6c70d0e10f0a123a28ea012e857df30e3ced524ef6562c71, 0x1b52d7ac4ee6082438deab8ab0f2944c9fd53258de305065f8323a3767dd8234 ); vk.gate_selector_commitments[0] = PairingsBn254.new_g1( 0x173c39587688a8967e915959df613aecf44ad0c7d2019ec32311bccdf542c78e, 0x2421a36a67559ed89afbff081cd45b318835e2b0233c047d030abc48b5011c22 ); vk.gate_selector_commitments[1] = PairingsBn254.new_g1( 0x177d8ef11cac24105d4b38e035b891986d163d9df717fce12d18af324f86d2dc, 0x02cd01ba1c82c85b4f0f8c7304254de64516857ac4f7bb60f052bb2af98132c5 ); vk.copy_permutation_commitments[0] = PairingsBn254.new_g1( 0x21da2c0f2b7849d4c44dbc487d370cccbae78fbd979e79575e04b7a983f2f68a, 0x14ffb806769ccf0d2c692cd93653491966525554d79efc37cfba5a5c08b15039 ); vk.copy_permutation_commitments[1] = PairingsBn254.new_g1( 0x184cc2f37e687a9be2404cd367536f14a505f086fd597cb966c5b753f325adb4, 0x20aaed49755efed4814025ac679570f62b8c98a1b8d977969242c3ffa67884d6 ); vk.copy_permutation_commitments[2] = PairingsBn254.new_g1( 0x0a2dee920031d9cd5ed499dc3cb901657079f6a2dfb0ba389b0181803bb91e24, 0x272ac2a214f46be0ed7d2b4cf125504ef82d929b1c1ec0a81655c66f39403cd1 ); vk.copy_permutation_commitments[3] = PairingsBn254.new_g1( 0x07e360365c7a5363389b2d2449b9471754591f01a623fd5553c5cfe6bad19aaf, 0x1b814914958835ef86de3c26c6c4bdc27e947f38cb0d2bfaa421d66cabfb7d55 ); vk.copy_permutation_non_residues[0] = PairingsBn254.new_fr( 0x0000000000000000000000000000000000000000000000000000000000000005 ); vk.copy_permutation_non_residues[1] = PairingsBn254.new_fr( 0x0000000000000000000000000000000000000000000000000000000000000007 ); vk.copy_permutation_non_residues[2] = PairingsBn254.new_fr( 0x000000000000000000000000000000000000000000000000000000000000000a ); vk.g2_x = PairingsBn254.new_g2( [0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1, 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0], [0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4, 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55] ); } function getVkAggregated8() internal pure returns(VerificationKey memory vk) { vk.domain_size = 16777216; vk.num_inputs = 1; vk.omega = PairingsBn254.new_fr(0x1951441010b2b95a6e47a6075066a50a036f5ba978c050f2821df86636c0facb); vk.gate_setup_commitments[0] = PairingsBn254.new_g1( 0x1aab46b9aa3adcac623c360e4d075572e3f56f4c75ac3b8663a7b059bd9b1857, 0x166ac39283efa3d6cb36423e83e2360f006e5fa374b454dea5fe92cc50d4193f ); vk.gate_setup_commitments[1] = PairingsBn254.new_g1( 0x13bce0a7bfbf2e7a81f18e84966c32422446b01f54cc7dc2ad3f64e92fe94cad, 0x0247234b0cdfd8c95a767f84303c3dd65ce7b15856c2840635d9d4754ba99479 ); vk.gate_setup_commitments[2] = PairingsBn254.new_g1( 0x08742bad9a7cbcc9dbb49a25bebce179295d1cf70fd8f9c8e82b8a658ee0b67c, 0x2a467983257850c5fa27f2f52f0c5c5fc98e7d2e0d440a8fd954ad981ff0ce9f ); vk.gate_setup_commitments[3] = PairingsBn254.new_g1( 0x16ebdd4b95b872cd09c13b6b54a8b8bf81a01529a71234db26e3b22c6d632723, 0x034219d7ad9ef204cfb3e32c4a47af82eea40504c2b1bac785104731722ed617 ); vk.gate_setup_commitments[4] = PairingsBn254.new_g1( 0x2e3a7c4458a8dc1535e68bac5dd5c1c9ff3886df4156bad4a08fcd08ebf1db26, 0x173859705317db06e5b7d260898ab08e72fae987c272b82345105d72bfd00ab8 ); vk.gate_setup_commitments[5] = PairingsBn254.new_g1( 0x0b830132e3325eaaea73c1095e615358db38dfb39248c90f8ff4afde169e7657, 0x0bfedf8cfce7260c16bb1f76ad9a39f73a68087e5c68e841020aeaa5ba301a9f ); vk.gate_setup_commitments[6] = PairingsBn254.new_g1( 0x1660c850da793add523f7990b983896e50d5549eec7990ec26aabc220ca58d52, 0x0ba698e78dee0d41cf8aefde82c5bfda38be071e11025b56db779ddb40a4fe92 ); vk.gate_selector_commitments[0] = PairingsBn254.new_g1( 0x024fe4ce02dd48937e4642b66308ae15d731e0ea82fc5430a0470d9a5dab3694, 0x177cac2d79a8bfa6aba134e24bded06d06219979c18b2fa4fe71baea9885985d ); vk.gate_selector_commitments[1] = PairingsBn254.new_g1( 0x00a848bc76c52faf7d4e7cc4086b50e3ccc9b1cebef130ac1bbf1816502df59d, 0x02f42f326f82b33cb9e4e7cfb332889eec95c2813f7968b3a50d838b3cbfa676 ); vk.copy_permutation_commitments[0] = PairingsBn254.new_g1( 0x20c176738979e0d1ea9541bf26e6209d3091b618ae94f3c72e13e954a1614f60, 0x2a7019c81009c00a7412b6a303b2eb118a362a558837e9ecdb912589bc11ff83 ); vk.copy_permutation_commitments[1] = PairingsBn254.new_g1( 0x10a92b3fa2b8280030c9de5cbcab4da3cf9b5b3f63f3ad60284ecded63cc54ea, 0x1bde2a83db435b8c74e4239b4f8416da88008331a758d8c68a9104f2dfc3e237 ); vk.copy_permutation_commitments[2] = PairingsBn254.new_g1( 0x08e2e513d1e548a627e2d4f74d28dea916d8598415b70543bb3e92429f0111cb, 0x2fb46898f77e32d7fd646fe31b60320423aa4698501e329e206b6acfcfb01337 ); vk.copy_permutation_commitments[3] = PairingsBn254.new_g1( 0x145b88d324270872b13784fbb7ccdee6e5593d2d5cbc81f4aaa9b4268cfc5094, 0x197d826aaf2a9853ca98ec9c0e55376eec1a6a0f5dbbbe02afeb1b567d8eafa0 ); vk.copy_permutation_non_residues[0] = PairingsBn254.new_fr( 0x0000000000000000000000000000000000000000000000000000000000000005 ); vk.copy_permutation_non_residues[1] = PairingsBn254.new_fr( 0x0000000000000000000000000000000000000000000000000000000000000007 ); vk.copy_permutation_non_residues[2] = PairingsBn254.new_fr( 0x000000000000000000000000000000000000000000000000000000000000000a ); vk.g2_x = PairingsBn254.new_g2( [0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1, 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0], [0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4, 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55] ); } } // Hardcoded constants to avoid accessing store contract KeysWithPlonkVerifierOld is VerifierWithDeserializeOld { function getVkExit() internal pure returns(VerificationKeyOld memory vk) { vk.domain_size = 524288; vk.num_inputs = 1; vk.omega = PairingsBn254.new_fr(0x0cf1526aaafac6bacbb67d11a4077806b123f767e4b0883d14cc0193568fc082); vk.selector_commitments[0] = PairingsBn254.new_g1( 0x114dd473f77a15b602201577dd4b64a32a783cb32fbc02911e512df6a219695d, 0x04c68f82a5dd7d0cc90318bdff493b3d552d148ad859c373ffe55275e043c43b ); vk.selector_commitments[1] = PairingsBn254.new_g1( 0x245e8c882af503cb5421f5135b4295a920ccf68b42ae7fb967f044f54e2aaa29, 0x071322ee387a9ce49fe7ef2edb6e9237203dee49ec47483af85e356b79fb06fd ); vk.selector_commitments[2] = PairingsBn254.new_g1( 0x0187754ab593b07a420b3b4d215c20ed49acf90fc4c97e4b06e8f5bc0a2eb3f4, 0x0170f9286ce950286a16ea25136c163c0b32019f31b89c256a612d40b863d0b6 ); vk.selector_commitments[3] = PairingsBn254.new_g1( 0x0defecfae1d2b9ec9b2ee4d4798c625fa50f6a4ddb7747a7293df0c17fcb90c2, 0x0f91d08fceebf85fb80f12cda78cefa1ee9dbf5cfe7c4f0704b3c6620fa50c55 ); vk.selector_commitments[4] = PairingsBn254.new_g1( 0x2f7fef3b3fb64af6640f93803a18b3e5ce4e0e60aecd4f924c833fa6fa6da961, 0x03908fc737113ac7f3529fe3b36efca200c66d1d85d2fc081973214c586de732 ); vk.selector_commitments[5] = PairingsBn254.new_g1( 0x14ce3c0e9b78fc331327249e707f58fa4bb0ed746bdc9c2262ad0cf905609627, 0x09e64fdac452b424e98fc4a92f7222693d0d84ab48aadd9c46151dbe5f1a34a9 ); // 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( 0x1d10bfd923c17d9623ec02db00099355b373021432ae1edef69b0f5f461f78d6, 0x24e370a93f65f42888781d0158bb6ef9136c8bbd047d7993b8276bc8df8b640a ); vk.permutation_commitments[0] = PairingsBn254.new_g1( 0x1fd1755ed4d06d91d50db4771d332cfa2bc2ca0e10ac8b77e0d6b73b993e788e, 0x0bdbf3b7f0d3cffdcf818f1fba18b90914eda59b454bd1858c6c0916b817f883 ); vk.permutation_commitments[1] = PairingsBn254.new_g1( 0x1f3b8d12ffa2ceb2bb42d232ad2cf11bce3183472b622e11cc841d26f42ad507, 0x0ce815e32b3bd14311cde210cda1bd351617d539ed3e9d96a8605f364f3a29b0 ); vk.permutation_commitments[2] = PairingsBn254.new_g1( 0x123afa8c1cec1956d7330db062498a2a3e3a9862926c02e1228d9cfb63d3c301, 0x0f5af15ff0a3e35486c541f72956b53ff6d0740384ef6463c866146c1bd2afc8 ); vk.permutation_commitments[3] = PairingsBn254.new_g1( 0x01069e38ea6396af1623921101d3d3d14ee46942fb23bf1d110efb994c3ee573, 0x232a8ce7151e69601a7867f9dcac8e2de4dd8352d119c90bbb0fb84720c02513 ); 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] ); } }
pragma solidity >=0.5.0 <0.8.0; pragma experimental ABIEncoderV2; // SPDX-License-Identifier: MIT OR Apache-2.0 // solhint-disable 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 { uint256[2] X; uint256[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 { uint256[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); uint256 elements = p1.length; uint256 inputSize = elements * 6; uint256[] memory input = new uint256[](inputSize); for (uint256 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]; } uint256[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 { uint256 constant r_mod = 21888242871839275222246405745257275088548364400416034343698204186575808495617; using PairingsBn254 for PairingsBn254.G1Point; using PairingsBn254 for PairingsBn254.G2Point; using PairingsBn254 for PairingsBn254.Fr; using TranscriptLibrary for TranscriptLibrary.Transcript; uint256 constant ZERO = 0; uint256 constant ONE = 1; uint256 constant TWO = 2; uint256 constant THREE = 3; uint256 constant FOUR = 4; uint256 constant STATE_WIDTH = 4; uint256 constant NUM_DIFFERENT_GATES = 2; uint256 constant NUM_SETUP_POLYS_FOR_MAIN_GATE = 7; uint256 constant NUM_SETUP_POLYS_RANGE_CHECK_GATE = 0; uint256 constant ACCESSIBLE_STATE_POLYS_ON_NEXT_STEP = 1; uint256 constant NUM_GATE_SELECTORS_OPENED_EXPLICITLY = 1; uint256 constant RECURSIVE_CIRCUIT_INPUT_COMMITMENT_MASK = 0x00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; uint256 constant LIMB_WIDTH = 68; struct VerificationKey { uint256 domain_size; uint256 num_inputs; PairingsBn254.Fr omega; PairingsBn254.G1Point[NUM_SETUP_POLYS_FOR_MAIN_GATE + NUM_SETUP_POLYS_RANGE_CHECK_GATE] gate_setup_commitments; PairingsBn254.G1Point[NUM_DIFFERENT_GATES] gate_selector_commitments; PairingsBn254.G1Point[STATE_WIDTH] copy_permutation_commitments; PairingsBn254.Fr[STATE_WIDTH - 1] copy_permutation_non_residues; PairingsBn254.G2Point g2_x; } struct Proof { uint256[] input_values; PairingsBn254.G1Point[STATE_WIDTH] wire_commitments; PairingsBn254.G1Point copy_permutation_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[NUM_GATE_SELECTORS_OPENED_EXPLICITLY] gate_selector_values_at_z; PairingsBn254.Fr copy_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 (uint256 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 (uint256 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 (uint256 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 (uint256 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); PairingsBn254.Fr memory inputs_term = 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])); inputs_term.add_assign(tmp); } inputs_term.mul_assign(proof.gate_selector_values_at_z[0]); rhs.add_assign(inputs_term); // now we need 5th power quotient_challenge.mul_assign(state.alpha); quotient_challenge.mul_assign(state.alpha); quotient_challenge.mul_assign(state.alpha); quotient_challenge.mul_assign(state.alpha); quotient_challenge.mul_assign(state.alpha); PairingsBn254.Fr memory z_part = PairingsBn254.copy(proof.copy_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 add_contribution_from_range_constraint_gates( PartialVerifierState memory state, Proof memory proof, PairingsBn254.Fr memory current_alpha ) internal pure returns (PairingsBn254.Fr memory res) { // now add contribution from range constraint gate // we multiply selector commitment by all the factors (alpha*(c - 4d)(c - 4d - 1)(..-2)(..-3) + alpha^2 * (4b - c)()()() + {} + {}) PairingsBn254.Fr memory one_fr = PairingsBn254.new_fr(ONE); PairingsBn254.Fr memory two_fr = PairingsBn254.new_fr(TWO); PairingsBn254.Fr memory three_fr = PairingsBn254.new_fr(THREE); PairingsBn254.Fr memory four_fr = PairingsBn254.new_fr(FOUR); res = PairingsBn254.new_fr(0); PairingsBn254.Fr memory t0 = PairingsBn254.new_fr(0); PairingsBn254.Fr memory t1 = PairingsBn254.new_fr(0); PairingsBn254.Fr memory t2 = PairingsBn254.new_fr(0); for (uint256 i = 0; i < 3; i++) { current_alpha.mul_assign(state.alpha); // high - 4*low // this is 4*low t0 = PairingsBn254.copy(proof.wire_values_at_z[3 - i]); t0.mul_assign(four_fr); // high t1 = PairingsBn254.copy(proof.wire_values_at_z[2 - i]); t1.sub_assign(t0); // t0 is now t1 - {0,1,2,3} // first unroll manually for -0; t2 = PairingsBn254.copy(t1); // -1 t0 = PairingsBn254.copy(t1); t0.sub_assign(one_fr); t2.mul_assign(t0); // -2 t0 = PairingsBn254.copy(t1); t0.sub_assign(two_fr); t2.mul_assign(t0); // -3 t0 = PairingsBn254.copy(t1); t0.sub_assign(three_fr); t2.mul_assign(t0); t2.mul_assign(current_alpha); res.add_assign(t2); } // now also d_next - 4a current_alpha.mul_assign(state.alpha); // high - 4*low // this is 4*low t0 = PairingsBn254.copy(proof.wire_values_at_z[0]); t0.mul_assign(four_fr); // high t1 = PairingsBn254.copy(proof.wire_values_at_z_omega[0]); t1.sub_assign(t0); // t0 is now t1 - {0,1,2,3} // first unroll manually for -0; t2 = PairingsBn254.copy(t1); // -1 t0 = PairingsBn254.copy(t1); t0.sub_assign(one_fr); t2.mul_assign(t0); // -2 t0 = PairingsBn254.copy(t1); t0.sub_assign(two_fr); t2.mul_assign(t0); // -3 t0 = PairingsBn254.copy(t1); t0.sub_assign(three_fr); t2.mul_assign(t0); t2.mul_assign(current_alpha); res.add_assign(t2); return res; } function reconstruct_linearization_commitment( 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} * (selector(x) - selector(z)) // + v^{7..9} * (permutation(x) - permutation(z)) // ] // W'(x) = 1 / (x - z*omega) * // [ // + v^10 (z(x) - z(z*omega)) <- we need this power // + v^11 * (d(x) - d(z*omega)) // ] // // we reconstruct linearization polynomial virtual selector // for that purpose we first linearize over main gate (over all it's selectors) // and multiply them by value(!) of the corresponding main gate selector res = PairingsBn254.copy_g1(vk.gate_setup_commitments[STATE_WIDTH + 1]); // index of q_const(x) 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.gate_setup_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.gate_setup_commitments[STATE_WIDTH].point_mul(tmp_fr); res.point_add_assign(tmp_g1); // d_next tmp_g1 = vk.gate_setup_commitments[STATE_WIDTH + 2].point_mul(proof.wire_values_at_z_omega[0]); // index of q_d_next(x) res.point_add_assign(tmp_g1); // multiply by main gate selector(z) res.point_mul_assign(proof.gate_selector_values_at_z[0]); // these is only one explicitly opened selector PairingsBn254.Fr memory current_alpha = PairingsBn254.new_fr(ONE); // calculate scalar contribution from the range check gate tmp_fr = add_contribution_from_range_constraint_gates(state, proof, current_alpha); tmp_g1 = vk.gate_selector_commitments[1].point_mul(tmp_fr); // selector commitment for range constraint gate * scalar res.point_add_assign(tmp_g1); // proceed as normal to copy permutation current_alpha.mul_assign(state.alpha); // alpha^5 PairingsBn254.Fr memory alpha_for_grand_product = PairingsBn254.copy(current_alpha); // 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.copy_permutation_non_residues.length; i++) { tmp_fr.assign(state.z); tmp_fr.mul_assign(vk.copy_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(alpha_for_grand_product); // alpha^n & L_{0}(z), and we bump current_alpha current_alpha.mul_assign(state.alpha); tmp_fr.assign(state.cached_lagrange_evals[0]); tmp_fr.mul_assign(current_alpha); grand_product_part_at_z.add_assign(tmp_fr); // prefactor for grand_product(x) is complete // add to the linearization a part from the term // - (a(z) + beta*perm_a + gamma)*()*()*z(z*omega) * beta * perm_d(X) 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.copy_grand_product_at_z_omega); last_permutation_part_at_z.mul_assign(alpha_for_grand_product); // we multiply by the power of alpha from the argument // actually multiply prefactors by z(x) and perm_d(x) and combine them tmp_g1 = proof.copy_permutation_grand_product_commitment.point_mul(grand_product_part_at_z); tmp_g1.point_sub_assign(vk.copy_permutation_commitments[STATE_WIDTH - 1].point_mul(last_permutation_part_at_z)); res.point_add_assign(tmp_g1); // multiply them by v immedately as linearization has a factor of v^1 res.point_mul_assign(state.v); // res now contains contribution from the gates linearization and // copy permutation part // now we need to add a part that is the rest // for z(x*omega): // - (a(z) + beta*perm_a + gamma)*()*()*(d(z) + gamma) * z(x*omega) } function aggregate_commitments( PartialVerifierState memory state, Proof memory proof, VerificationKey memory vk ) internal view returns (PairingsBn254.G1Point[2] memory res) { PairingsBn254.G1Point memory d = reconstruct_linearization_commitment(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 (uint256 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 (uint256 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 (uint256 i = 0; i < NUM_GATE_SELECTORS_OPENED_EXPLICITLY; i++) { aggregation_challenge.mul_assign(state.v); tmp_g1 = vk.gate_selector_commitments[0].point_mul(aggregation_challenge); commitment_aggregation.point_add_assign(tmp_g1); } for (uint256 i = 0; i < vk.copy_permutation_commitments.length - 1; i++) { aggregation_challenge.mul_assign(state.v); tmp_g1 = vk.copy_permutation_commitments[i].point_mul(aggregation_challenge); commitment_aggregation.point_add_assign(tmp_g1); } aggregation_challenge.mul_assign(state.v); // now do prefactor for grand_product(x*omega) tmp_fr.assign(aggregation_challenge); tmp_fr.mul_assign(state.u); commitment_aggregation.point_add_assign(proof.copy_permutation_grand_product_commitment.point_mul(tmp_fr)); 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 (uint256 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 (uint256 i = 0; i < proof.gate_selector_values_at_z.length; i++) { aggregation_challenge.mul_assign(state.v); tmp_fr.assign(proof.gate_selector_values_at_z[i]); tmp_fr.mul_assign(aggregation_challenge); aggregated_value.add_assign(tmp_fr); } for (uint256 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.copy_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(); res[0] = pair_with_generator; res[1] = pair_with_x; return res; } 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.copy_permutation_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; } transcript.update_with_fr(proof.quotient_polynomial_at_z); 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]); } transcript.update_with_fr(proof.gate_selector_values_at_z[0]); 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.copy_grand_product_at_z_omega); 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 aggregate_for_verification(Proof memory proof, VerificationKey memory vk) internal view returns (bool valid, PairingsBn254.G1Point[2] memory part) { PartialVerifierState memory state; valid = verify_initial(state, proof, vk); if (valid == false) { return (valid, part); } part = aggregate_commitments(state, proof, vk); (valid, part); } function verify(Proof memory proof, VerificationKey memory vk) internal view returns (bool) { (bool valid, PairingsBn254.G1Point[2] memory recursive_proof_part) = aggregate_for_verification(proof, vk); if (valid == false) { return false; } valid = PairingsBn254.pairingProd2( recursive_proof_part[0], PairingsBn254.P2(), recursive_proof_part[1], vk.g2_x ); return valid; } function verify_recursive( Proof memory proof, VerificationKey memory vk, uint256 recursive_vks_root, uint8 max_valid_index, uint8[] memory recursive_vks_indexes, uint256[] memory individual_vks_inputs, uint256[16] memory subproofs_limbs ) internal view returns (bool) { (uint256 recursive_input, PairingsBn254.G1Point[2] memory aggregated_g1s) = reconstruct_recursive_public_input( recursive_vks_root, max_valid_index, recursive_vks_indexes, individual_vks_inputs, subproofs_limbs ); assert(recursive_input == proof.input_values[0]); (bool valid, PairingsBn254.G1Point[2] memory recursive_proof_part) = aggregate_for_verification(proof, vk); if (valid == false) { return false; } // aggregated_g1s = inner // recursive_proof_part = outer PairingsBn254.G1Point[2] memory combined = combine_inner_and_outer(aggregated_g1s, recursive_proof_part); valid = PairingsBn254.pairingProd2(combined[0], PairingsBn254.P2(), combined[1], vk.g2_x); return valid; } function combine_inner_and_outer(PairingsBn254.G1Point[2] memory inner, PairingsBn254.G1Point[2] memory outer) internal view returns (PairingsBn254.G1Point[2] memory result) { // reuse the transcript primitive TranscriptLibrary.Transcript memory transcript = TranscriptLibrary.new_transcript(); transcript.update_with_g1(inner[0]); transcript.update_with_g1(inner[1]); transcript.update_with_g1(outer[0]); transcript.update_with_g1(outer[1]); PairingsBn254.Fr memory challenge = transcript.get_challenge(); // 1 * inner + challenge * outer result[0] = PairingsBn254.copy_g1(inner[0]); result[1] = PairingsBn254.copy_g1(inner[1]); PairingsBn254.G1Point memory tmp = outer[0].point_mul(challenge); result[0].point_add_assign(tmp); tmp = outer[1].point_mul(challenge); result[1].point_add_assign(tmp); return result; } function reconstruct_recursive_public_input( uint256 recursive_vks_root, uint8 max_valid_index, uint8[] memory recursive_vks_indexes, uint256[] memory individual_vks_inputs, uint256[16] memory subproofs_aggregated ) internal pure returns (uint256 recursive_input, PairingsBn254.G1Point[2] memory reconstructed_g1s) { assert(recursive_vks_indexes.length == individual_vks_inputs.length); bytes memory concatenated = abi.encodePacked(recursive_vks_root); uint8 index; for (uint256 i = 0; i < recursive_vks_indexes.length; i++) { index = recursive_vks_indexes[i]; assert(index <= max_valid_index); concatenated = abi.encodePacked(concatenated, index); } uint256 input; for (uint256 i = 0; i < recursive_vks_indexes.length; i++) { input = individual_vks_inputs[i]; assert(input < r_mod); concatenated = abi.encodePacked(concatenated, input); } concatenated = abi.encodePacked(concatenated, subproofs_aggregated); bytes32 commitment = sha256(concatenated); recursive_input = uint256(commitment) & RECURSIVE_CIRCUIT_INPUT_COMMITMENT_MASK; reconstructed_g1s[0] = PairingsBn254.new_g1_checked( subproofs_aggregated[0] + (subproofs_aggregated[1] << LIMB_WIDTH) + (subproofs_aggregated[2] << (2 * LIMB_WIDTH)) + (subproofs_aggregated[3] << (3 * LIMB_WIDTH)), subproofs_aggregated[4] + (subproofs_aggregated[5] << LIMB_WIDTH) + (subproofs_aggregated[6] << (2 * LIMB_WIDTH)) + (subproofs_aggregated[7] << (3 * LIMB_WIDTH)) ); reconstructed_g1s[1] = PairingsBn254.new_g1_checked( subproofs_aggregated[8] + (subproofs_aggregated[9] << LIMB_WIDTH) + (subproofs_aggregated[10] << (2 * LIMB_WIDTH)) + (subproofs_aggregated[11] << (3 * LIMB_WIDTH)), subproofs_aggregated[12] + (subproofs_aggregated[13] << LIMB_WIDTH) + (subproofs_aggregated[14] << (2 * LIMB_WIDTH)) + (subproofs_aggregated[15] << (3 * LIMB_WIDTH)) ); return (recursive_input, reconstructed_g1s); } } contract VerifierWithDeserialize is Plonk4VerifierWithAccessToDNext { uint256 constant SERIALIZED_PROOF_LENGTH = 34; 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.copy_permutation_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; } for (uint256 i = 0; i < proof.gate_selector_values_at_z.length; i++) { proof.gate_selector_values_at_z[i] = 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.copy_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; 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]); } function verify_serialized_proof( uint256[] memory public_inputs, uint256[] memory serialized_proof, VerificationKey memory vk ) public view returns (bool) { require(vk.num_inputs == public_inputs.length); Proof memory proof = deserialize_proof(public_inputs, serialized_proof); bool valid = verify(proof, vk); return valid; } function verify_serialized_proof_with_recursion( uint256[] memory public_inputs, uint256[] memory serialized_proof, uint256 recursive_vks_root, uint8 max_valid_index, uint8[] memory recursive_vks_indexes, uint256[] memory individual_vks_inputs, uint256[16] memory subproofs_limbs, VerificationKey memory vk ) public view returns (bool) { require(vk.num_inputs == public_inputs.length); Proof memory proof = deserialize_proof(public_inputs, serialized_proof); bool valid = verify_recursive( proof, vk, recursive_vks_root, max_valid_index, recursive_vks_indexes, individual_vks_inputs, subproofs_limbs ); return valid; } } contract Plonk4VerifierWithAccessToDNextOld { using PairingsBn254 for PairingsBn254.G1Point; using PairingsBn254 for PairingsBn254.G2Point; using PairingsBn254 for PairingsBn254.Fr; using TranscriptLibrary for TranscriptLibrary.Transcript; uint256 constant STATE_WIDTH_OLD = 4; uint256 constant ACCESSIBLE_STATE_POLYS_ON_NEXT_STEP_OLD = 1; struct VerificationKeyOld { uint256 domain_size; uint256 num_inputs; PairingsBn254.Fr omega; PairingsBn254.G1Point[STATE_WIDTH_OLD + 2] selector_commitments; // STATE_WIDTH for witness + multiplication + constant PairingsBn254.G1Point[ACCESSIBLE_STATE_POLYS_ON_NEXT_STEP_OLD] next_step_selector_commitments; PairingsBn254.G1Point[STATE_WIDTH_OLD] permutation_commitments; PairingsBn254.Fr[STATE_WIDTH_OLD - 1] permutation_non_residues; PairingsBn254.G2Point g2_x; } struct ProofOld { uint256[] input_values; PairingsBn254.G1Point[STATE_WIDTH_OLD] wire_commitments; PairingsBn254.G1Point grand_product_commitment; PairingsBn254.G1Point[STATE_WIDTH_OLD] quotient_poly_commitments; PairingsBn254.Fr[STATE_WIDTH_OLD] wire_values_at_z; PairingsBn254.Fr[ACCESSIBLE_STATE_POLYS_ON_NEXT_STEP_OLD] 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_OLD - 1] permutation_polynomials_at_z; PairingsBn254.G1Point opening_at_z_proof; PairingsBn254.G1Point opening_at_z_omega_proof; } struct PartialVerifierStateOld { 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_old( 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_old( 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 (uint256 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 (uint256 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 (uint256 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 (uint256 i = 0; i < nums.length; i++) { nums[i].mul_assign(dens[i]); } return nums; } function evaluate_vanishing_old(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( PartialVerifierStateOld memory state, ProofOld memory proof, VerificationKeyOld memory vk ) internal view returns (bool) { PairingsBn254.Fr memory lhs = evaluate_vanishing_old(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_OLD - 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( PartialVerifierStateOld memory state, ProofOld memory proof, VerificationKeyOld 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_OLD + STATE_WIDTH_OLD - 1; res = PairingsBn254.copy_g1(vk.selector_commitments[STATE_WIDTH_OLD + 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_OLD; 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_OLD].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_OLD - 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( PartialVerifierStateOld memory state, ProofOld memory proof, VerificationKeyOld 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 (uint256 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 (uint256 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 (uint256 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_OLD - 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 (uint256 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 (uint256 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( PartialVerifierStateOld memory state, ProofOld memory proof, VerificationKeyOld 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_old( 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); transcript.update_with_fr(proof.grand_product_at_z_omega); 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_old(ProofOld memory proof, VerificationKeyOld memory vk) internal view returns (bool) { PartialVerifierStateOld memory state; bool valid = verify_initial(state, proof, vk); if (valid == false) { return false; } valid = verify_commitments(state, proof, vk); return valid; } } contract VerifierWithDeserializeOld is Plonk4VerifierWithAccessToDNextOld { uint256 constant SERIALIZED_PROOF_LENGTH_OLD = 33; function deserialize_proof_old(uint256[] memory public_inputs, uint256[] memory serialized_proof) internal pure returns (ProofOld memory proof) { require(serialized_proof.length == SERIALIZED_PROOF_LENGTH_OLD); 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_OLD; 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_OLD; 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_OLD; 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]); } }
pragma solidity ^0.7.0; // SPDX-License-Identifier: MIT OR Apache-2.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; }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"}],"name":"ApproveCutUpgradeNoticePeriod","type":"event"},{"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":"uint16","name":"tokenId","type":"uint16"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"Deposit","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":false,"internalType":"uint256","name":"newNoticePeriod","type":"uint256"}],"name":"NoticePeriodChange","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":"Withdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"tokenId","type":"uint32"}],"name":"WithdrawalNFT","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"tokenId","type":"uint32"}],"name":"WithdrawalNFTPending","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"tokenId","type":"uint16"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"},{"indexed":false,"internalType":"enum Operations.WithdrawalType","name":"withdrawalType","type":"uint8"}],"name":"WithdrawalPending","type":"event"},{"inputs":[],"name":"activateExodusMode","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint32","name":"","type":"uint32"}],"name":"authFacts","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint32","name":"","type":"uint32"}],"name":"authFactsResetTimer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"_n","type":"uint64"},{"internalType":"bytes[]","name":"_depositsPubdata","type":"bytes[]"}],"name":"cancelOutstandingDepositsForExodusMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"uint64","name":"priorityOperations","type":"uint64"},{"internalType":"bytes32","name":"pendingOnchainOperationsHash","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes32","name":"stateHash","type":"bytes32"},{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"internalType":"struct Storage.StoredBlockInfo","name":"_lastCommittedBlockData","type":"tuple"},{"components":[{"internalType":"bytes32","name":"newStateHash","type":"bytes32"},{"internalType":"bytes","name":"publicData","type":"bytes"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"components":[{"internalType":"bytes","name":"ethWitness","type":"bytes"},{"internalType":"uint32","name":"publicDataOffset","type":"uint32"}],"internalType":"struct ZkSync.OnchainOperationData[]","name":"onchainOperations","type":"tuple[]"},{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"uint32","name":"feeAccount","type":"uint32"}],"internalType":"struct ZkSync.CommitBlockInfo[]","name":"_newBlocksData","type":"tuple[]"}],"name":"commitBlocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"targetsHash","type":"bytes32"}],"name":"cutUpgradeNoticePeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"signatures","type":"bytes[]"}],"name":"cutUpgradeNoticePeriodBySignature","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"uint104","name":"_amount","type":"uint104"},{"internalType":"address","name":"_zkSyncAddress","type":"address"}],"name":"depositERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_zkSyncAddress","type":"address"}],"name":"depositETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"uint64","name":"priorityOperations","type":"uint64"},{"internalType":"bytes32","name":"pendingOnchainOperationsHash","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes32","name":"stateHash","type":"bytes32"},{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"internalType":"struct Storage.StoredBlockInfo","name":"storedBlock","type":"tuple"},{"internalType":"bytes[]","name":"pendingOnchainOpsPubdata","type":"bytes[]"}],"internalType":"struct ZkSync.ExecuteBlockInfo[]","name":"_blocksData","type":"tuple[]"}],"name":"executeBlocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exodusMode","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"firstPriorityRequestId","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNoticePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getPendingBalance","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"initializationParameters","type":"bytes"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isReadyForUpgrade","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"uint64","name":"priorityOperations","type":"uint64"},{"internalType":"bytes32","name":"pendingOnchainOperationsHash","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes32","name":"stateHash","type":"bytes32"},{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"internalType":"struct Storage.StoredBlockInfo","name":"_storedBlockInfo","type":"tuple"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint32","name":"_accountId","type":"uint32"},{"internalType":"uint32","name":"_tokenId","type":"uint32"},{"internalType":"uint128","name":"_amount","type":"uint128"},{"internalType":"uint32","name":"_nftCreatorAccountId","type":"uint32"},{"internalType":"address","name":"_nftCreatorAddress","type":"address"},{"internalType":"uint32","name":"_nftSerialId","type":"uint32"},{"internalType":"bytes32","name":"_nftContentHash","type":"bytes32"},{"internalType":"uint256[]","name":"_proof","type":"uint256[]"}],"name":"performExodus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"uint64","name":"priorityOperations","type":"uint64"},{"internalType":"bytes32","name":"pendingOnchainOperationsHash","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes32","name":"stateHash","type":"bytes32"},{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"internalType":"struct Storage.StoredBlockInfo[]","name":"_committedBlocks","type":"tuple[]"},{"components":[{"internalType":"uint256[]","name":"recursiveInput","type":"uint256[]"},{"internalType":"uint256[]","name":"proof","type":"uint256[]"},{"internalType":"uint256[]","name":"commitments","type":"uint256[]"},{"internalType":"uint8[]","name":"vkIndexes","type":"uint8[]"},{"internalType":"uint256[16]","name":"subproofsLimbs","type":"uint256[16]"}],"internalType":"struct ZkSync.ProofInput","name":"_proof","type":"tuple"}],"name":"proveBlocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_accountId","type":"uint32"},{"internalType":"address","name":"_token","type":"address"}],"name":"requestFullExit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_accountId","type":"uint32"},{"internalType":"uint32","name":"_tokenId","type":"uint32"}],"name":"requestFullExitNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"uint64","name":"priorityOperations","type":"uint64"},{"internalType":"bytes32","name":"pendingOnchainOperationsHash","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes32","name":"stateHash","type":"bytes32"},{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"internalType":"struct Storage.StoredBlockInfo[]","name":"_blocksToRevert","type":"tuple[]"}],"name":"revertBlocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_pubkeyHash","type":"bytes"},{"internalType":"uint32","name":"_nonce","type":"uint32"}],"name":"setAuthPubkeyHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"storedBlockHashes","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBlocksCommitted","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBlocksExecuted","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBlocksProven","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalOpenPriorityRequests","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"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":"transferERC20","outputs":[{"internalType":"uint128","name":"withdrawnAmount","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"upgradeParameters","type":"bytes"}],"name":"upgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upgradeCanceled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upgradeFinishes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upgradeNoticePeriodStarted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upgradePreparationStarted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_owner","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint128","name":"_amount","type":"uint128"}],"name":"withdrawPendingBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_tokenId","type":"uint32"}],"name":"withdrawPendingNFTBalance","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b506200001c62000022565b62000086565b7f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf480546001909155801562000083576040805162461bcd60e51b815260206004820152600260248201526118a160f11b604482015290519081900360640190fd5b50565b615aa380620000966000396000f3fe6080604052600436106102045760003560e01c80637efcfe8511610118578063b0705b42116100a0578063c57b22be1161006f578063c57b22be1461057b578063d514da5014610590578063e17376b5146105b0578063f2235487146105d0578063faf4d8cb146105e557610204565b8063b0705b4214610520578063b269b9ae14610461578063b4a8498c14610540578063b65975ec1461055b57610204565b80638ae20dc9116100e75780638ae20dc91461048b5780639ba0d146146104ab5780639beb4650146104cb578063a7e7aacd146104eb578063ab9b2adf1461050057610204565b80637efcfe85146104265780638398180814610441578063871b8ff1146104615780638773334c1461047657610204565b8063452692981161019b5780635aca41f61161016a5780635aca41f614610380578063647b5923146103ad57806367708dae146103cf57806368809a23146103f157806378b91e701461041157610204565b80634526929814610300578063505a757314610320578063595a5ebc1461034057806359acda851461036057610204565b80632a3174f4116101d75780632a3174f4146102965780632d2da806146102b85780633b154b73146102cb578063439fab91146102e057610204565b806313d9787b146102095780631d1796431461022b578063253946451461024b578063264c09121461026b575b600080fd5b34801561021557600080fd5b50610229610224366004614d0d565b6105fa565b005b34801561023757600080fd5b50610229610246366004614b49565b610740565b34801561025757600080fd5b50610229610266366004614a04565b610755565b34801561027757600080fd5b506102806107b6565b60405161028d91906152ca565b60405180910390f35b3480156102a257600080fd5b506102ab6107bf565b60405161028d91906152d5565b6102296102c6366004614718565b6107c4565b3480156102d757600080fd5b5061022961082c565b3480156102ec57600080fd5b506102296102fb366004614a04565b610832565b34801561030c57600080fd5b5061022961031b366004614c49565b610962565b34801561032c57600080fd5b5061022961033b366004614cd8565b610b89565b34801561034c57600080fd5b5061022961035b366004614a37565b610df6565b34801561036c57600080fd5b5061022961037b3660046149d4565b610e03565b34801561038c57600080fd5b506103a061039b3660046147ce565b610e0b565b60405161028d9190615860565b3480156103b957600080fd5b506103c2610eda565b60405161028d91906158aa565b3480156103db57600080fd5b506103e4610ee6565b60405161028d91906158da565b3480156103fd57600080fd5b506103a061040c366004614a88565b610ef5565b34801561041d57600080fd5b506102296110db565b34801561043257600080fd5b5061022961035b366004614d42565b34801561044d57600080fd5b5061022961045c3660046148a3565b61110b565b34801561046d57600080fd5b506102296113a4565b34801561048257600080fd5b506102806113ae565b34801561049757600080fd5b506102ab6104a6366004614806565b6113b3565b3480156104b757600080fd5b506102ab6104c6366004614cd8565b6113d0565b3480156104d757600080fd5b506102296104e6366004614831565b6113e2565b3480156104f757600080fd5b506102806113ee565b34801561050c57600080fd5b5061022961051b366004614cf2565b6114e6565b34801561052c57600080fd5b5061022961053b366004614831565b6116bb565b34801561054c57600080fd5b506102296104e6366004614870565b34801561056757600080fd5b506102ab610576366004614806565b6118ed565b34801561058757600080fd5b506103e461190a565b34801561059c57600080fd5b506102296105ab366004614784565b611920565b3480156105bc57600080fd5b506102296105cb366004614ae3565b611bf8565b3480156105dc57600080fd5b506103c2611f5e565b3480156105f157600080fd5b506103c2611f71565b600080516020615a4e833981519152546001811461061757600080fd5b6002600080516020615a4e83398151915255610631611f84565b62ffffff63ffffffff841611156106635760405162461bcd60e51b815260040161065a90615690565b60405180910390fd5b63ffffffff831662ffffff141561068c5760405162461bcd60e51b815260040161065a9061565a565b63ffffffff821661ffff1080156106ac5750637ffffffe63ffffffff8316105b6106c85760405162461bcd60e51b815260040161065a9061559a565b604080516101008101825263ffffffff80861682523360208301528416918101919091526000606082018190526080820181905260a0820181905260c0820181905260e0820181905261071a82611fa7565b9050610727600682611fe8565b50506001600080516020615a4e83398151915255505050565b610748612150565b5050505050505050505050565b600080516020615a4e833981519152546001811461077257600080fd5b5050621baf8060145550601380546001600160a01b031916732eaa1377e0fc95de998b9fa7611e9d67eba534fd1790556001600080516020615a4e83398151915255565b60095460ff1681565b600090565b6001600160a01b0381811614156107ed5760405162461bcd60e51b815260040161065a9061552d565b6000341161080d5760405162461bcd60e51b815260040161065a9061557f565b610815611f84565b610829600061082334612184565b836121cb565b50565b42601555565b61083a61225e565b600080808061084b85870187614734565b600280546001600160a01b038086166001600160a01b0319928316179092556003805483881690831617905560138054928516929091169190911790556040805160c0810182526000808252602082018190527fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47092820192909252606081018290526080810183905260a0810191909152939750919550935091506108ef816122ac565b60008052600d6020527f81955a0a11e65eac625c29e8882660bae4e165a75d72780094acae8ece9a29ee55621baf8060148190556040517ff2b18f8abbd8a0d0c1fb8245146eedf5304887b12f6395b548ca238e054a148391610951916152d5565b60405180910390a150505050505050565b600080516020615a4e833981519152546001811461097f57600080fd5b6002600080516020615a4e83398151915255610999611f84565b600354604051634b18bd0f60e01b81526001600160a01b0390911690634b18bd0f906109c9903390600401615112565b60006040518083038186803b1580156109e157600080fd5b505afa1580156109f5573d6000803e3d6000fd5b50505050610a02846122ac565b600654600160601b900463ffffffff166000908152600d602052604090205414610a3e5760405162461bcd60e51b815260040161065a906157a0565b8160005b8163ffffffff16811015610b0c57610a7786868684818110610a6057fe5b9050602002810190610a729190615978565b6122dc565b6020810151600c80546001600160401b03600160801b80830482169094011690920267ffffffffffffffff60801b199092169190911790559550610aba866122ac565b865163ffffffff9081166000908152600d6020526040808220939093558851925192909116917f81a92942d0f9c33b897a438384c9c3d88be397776138efa3ba1a4fc8b62684249190a2600101610a42565b506006805463ffffffff600160601b808304821685019091160263ffffffff60601b19909116179055600c546001600160401b03600160401b82048116600160801b909204161115610b705760405162461bcd60e51b815260040161065a906156ab565b506001600080516020615a4e8339815191525550505050565b600080516020615a4e8339815191525460018114610ba657600080fd5b6002600080516020615a4e83398151915281905563ffffffff808416600090815260126020908152604091829020825160c081018452815480861682526001600160a01b0364010000000082048116948301859052600160c01b909104861694820194909452600182015460608201529401549182166080850152600160a01b90910490911660a0830152610c4d5760405162461bcd60e51b815260040161065a906156e1565b6003548151602083015160405163b79eb8c760e01b81526000936001600160a01b03169263b79eb8c792610c83926004016158bb565b60206040518083038186803b158015610c9b57600080fd5b505afa158015610caf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd39190614b2d565b63ffffffff8516600090815260116020908152604080832080546001600160a01b0319166001600160a01b0386169081179091556012835281842080546001600160e01b03191681556001810194909455600290930180546001600160c01b0319169055908501516080860151865187840151606089015160a08a01519551630234ce5960e41b8152979850959663234ce59096610d759690916004016151be565b600060405180830381600087803b158015610d8f57600080fd5b505af1158015610da3573d6000803e3d6000fd5b505050508160a0015163ffffffff167f0b9f3586023bf754b8d962232407f7ac4d90fd19a1c4756c6619927abf06756060405160405180910390a250506001600080516020615a4e833981519152555050565b610dfe612150565b505050565b610829612150565b6000806001600160a01b03831615610ea0576003546040516375698bb160e11b81526001600160a01b039091169063ead3176290610e4d908690600401615112565b60206040518083038186803b158015610e6557600080fd5b505afa158015610e79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e9d9190614cb6565b90505b60046000610eae8684612421565b6001600160501b03191681526020810191909152604001600020546001600160801b0316949350505050565b600e5463ffffffff1681565b600c546001600160401b031681565b6000333014610f165760405162461bcd60e51b815260040161065a90615718565b6040516370a0823160e01b81526000906001600160a01b038716906370a0823190610f45903090600401615112565b60206040518083038186803b158015610f5d57600080fd5b505afa158015610f71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9591906149ec565b60405163a9059cbb60e01b81529091506001600160a01b0387169063a9059cbb90610fc690889088906004016151fc565b600060405180830381600087803b158015610fe057600080fd5b505af1158015610ff4573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03891691506370a0823190611027903090600401615112565b60206040518083038186803b15801561103f57600080fd5b505afa158015611053573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061107791906149ec565b90506000611085838361243e565b9050600081116110a75760405162461bcd60e51b815260040161065a90615548565b846001600160801b03168111156110d05760405162461bcd60e51b815260040161065a90615485565b979650505050505050565b6014546015546110ea9161246b565b4210156110f657600080fd5b6000805460ff19166001908117909155429055565b600080516020615a4e833981519152546001811461112857600080fd5b6002600080516020615a4e83398151915255611142611f84565b600e5463ffffffff908116600181019091166000908152600d60205260408120549091905b8061119288888681811061117757fe5b905060c0020180360381019061118d9190614c2e565b6122ac565b146111c1576001909201918583106111bc5760405162461bcd60e51b815260040161065a906157f1565b611167565b50845b808310156112825763ffffffff60018301166000908152600d60205260409020546111f488888681811061117757fe5b146112115760405162461bcd60e51b815260040161065a906155b5565b8160010191506001600160fd1b0387878581811061122b57fe5b905060c0020160a0013560001c166001600160fd1b038660400151858151811061125157fe5b602002602001015116146112775760405162461bcd60e51b815260040161065a906154a0565b8260010192506111c4565b6002548551602087015160608801516040808a015160808b0151915163054185eb60e51b81526000966001600160a01b03169563a830bd60956112cd9591949093919260040161521e565b60206040518083038186803b1580156112e557600080fd5b505afa1580156112f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061131d91906149b4565b90508061133c5760405162461bcd60e51b815260040161065a906153e2565b60065463ffffffff600160601b9091048116908416111561136f5760405162461bcd60e51b815260040161065a90615434565b5050600e805463ffffffff191663ffffffff9290921691909117905550506001600080516020615a4e83398151915255505050565b6113ac6124aa565b565b600190565b600a60209081526000928352604080842090915290825290205481565b600d6020526000908152604090205481565b6113ea612150565b5050565b600080516020615a4e833981519152546000906001811461140e57600080fd5b6002600080516020615a4e8339815191525560095460ff161561143457600091506114d0565b600c546001600160401b039081166000908152600f60205260408120549091600160a01b90910416431080159061148e5750600c546001600160401b039081166000908152600f6020526040902054600160a01b90041615155b905080156114cd576009805460ff191660011790556040517fc71028c67eb0ef128ea270a59a674629e767d51c1af44ed6753fd2fad2c7b67790600090a15b91505b6001600080516020615a4e833981519152555090565b600080516020615a4e833981519152546001811461150357600080fd5b6002600080516020615a4e8339815191525561151d611f84565b62ffffff63ffffffff841611156115465760405162461bcd60e51b815260040161065a90615690565b63ffffffff831662ffffff141561156f5760405162461bcd60e51b815260040161065a9061565a565b60006001600160a01b0383166115875750600061160a565b6003546040516375698bb160e11b81526001600160a01b039091169063ead31762906115b7908690600401615112565b60206040518083038186803b1580156115cf57600080fd5b505afa1580156115e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116079190614cb6565b90505b604080516101008101825263ffffffff8616815233602082015261ffff8316918101919091526000606082018190526080820181905260a0820181905260c0820181905260e0820181905261165e82611fa7565b905061166b600682611fe8565b60006116773385612421565b6001600160501b0319166000908152600460205260409020805460ff60801b191660ff60801b17905550506001600080516020615a4e833981519152555050505050565b600080516020615a4e83398151915254600181146116d857600080fd5b6002600080516020615a4e833981519152556116f2611f84565b600354604051634b18bd0f60e01b81526001600160a01b0390911690634b18bd0f90611722903390600401615112565b60006040518083038186803b15801561173a57600080fd5b505afa15801561174e573d6000803e3d6000fd5b50600092508491508290505b8163ffffffff168110156118285761178f86868381811061177757fe5b9050602002810190611789919061598d565b8261252d565b85858281811061179b57fe5b90506020028101906117ad919061598d565b6117be906040810190602001614d28565b830192508585828181106117ce57fe5b90506020028101906117e0919061598d565b6117ee906020810190614cd8565b63ffffffff167f0cdbd8bd7813095001c5fe7917bd69d834dc01db7c1dfcf52ca135bd2038441360405160405180910390a260010161175a565b50600c805467ffffffffffffffff60401b1967ffffffffffffffff60801b1967ffffffffffffffff1983166001600160401b039384168701841617908116600160801b918290048416879003841690910217908116600160401b918290048316869003909216810291909117909155600680546bffffffff00000000000000001981169083900463ffffffff9081168501811684029190911791829055600e548116929091041611156107275760405162461bcd60e51b815260040161065a9061546a565b601060209081526000928352604080842090915290825290205481565b600c54600160401b90046001600160401b031681565b600080516020615a4e833981519152546001811461193d57600080fd5b6002600080516020615a4e8339815191525560006001600160a01b038416156119e3576003546040516375698bb160e11b81526001600160a01b039091169063ead3176290611990908790600401615112565b60206040518083038186803b1580156119a857600080fd5b505afa1580156119bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e09190614cb6565b90505b60006119ef8683612421565b6001600160501b031981166000908152600460205260408120549192506001600160801b0390911690611a2282876129bb565b90506000816001600160801b031611611a4d5760405162461bcd60e51b815260040161065a9061574e565b61ffff8416611ae1576000886001600160a01b0316826001600160801b0316604051611a789061501c565b60006040518083038185875af1925050503d8060008114611ab5576040519150601f19603f3d011682016040523d82523d6000602084013e611aba565b606091505b5050905080611adb5760405162461bcd60e51b815260040161065a906157bb565b50611b5f565b6040516368809a2360e01b815230906368809a2390611b0a908a908c9086908890600401615327565b602060405180830381600087803b158015611b2457600080fd5b505af1158015611b38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b5c9190614c9a565b90505b6001600160501b031983166000908152600460205260409081902080546001600160801b0319168385036001600160801b03161790555161ffff8516906001600160a01b038a16907fefef619ae4a542a2b8810b4efeccd8478bd683e985354ee31dd2d644aff6d0ca90611bd4908590615860565b60405180910390a3505050506001600080516020615a4e8339815191525550505050565b600080516020615a4e8339815191525460018114611c1557600080fd5b6002600080516020615a4e833981519152556001600160a01b038281161415611c505760405162461bcd60e51b815260040161065a9061552d565b611c58611f84565b6003546040516375698bb160e11b81526000916001600160a01b03169063ead3176290611c89908890600401615112565b60206040518083038186803b158015611ca157600080fd5b505afa158015611cb5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cd99190614cb6565b60035460405163f3a65bf960e01b81529192506001600160a01b03169063f3a65bf990611d0a90849060040161589b565b60206040518083038186803b158015611d2257600080fd5b505afa158015611d36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d5a91906149b4565b15611d775760405162461bcd60e51b815260040161065a906156c6565b6040516370a0823160e01b81526000906001600160a01b038716906370a0823190611da6903090600401615112565b60206040518083038186803b158015611dbe57600080fd5b505afa158015611dd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df691906149ec565b6040516323b872dd60e01b81529091506001600160a01b038716906323b872dd90611e2990339030908a90600401615126565b600060405180830381600087803b158015611e4357600080fd5b505af1158015611e57573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03891691506370a0823190611e8a903090600401615112565b60206040518083038186803b158015611ea257600080fd5b505afa158015611eb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eda91906149ec565b90506000611ef0611eeb838561243e565b612184565b90506000816001600160801b0316118015611f1b57506001600160681b036001600160801b03821611155b611f375760405162461bcd60e51b815260040161065a9061535b565b611f428482886121cb565b505050506001600080516020615a4e8339815191525550505050565b600654600160401b900463ffffffff1681565b600654600160601b900463ffffffff1681565b60095460ff16156113ac5760405162461bcd60e51b815260040161065a906155d1565b6060600682516020808501516040808701519051611fd295949360009182918291829182910161507d565b6040516020818303038152906040529050919050565b600c544362013b0001906001600160401b03808216600160401b90920416016000612012846129e3565b90506040518060600160405280826bffffffffffffffffffffffff19168152602001846001600160401b0316815260200186600b81111561204f57fe5b90526001600160401b038084166000908152600f60209081526040918290208451815492860151909416600160a01b0267ffffffffffffffff60a01b1960609590951c6001600160a01b03199093169290921793909316178083559083015190829060ff60e01b1916600160e01b83600b8111156120c957fe5b02179055509050507fd0943372c08b438a88d4b39d77216901079eda9ca59d45349841c099083b683033838787876001600160401b0316604051612111959493929190615152565b60405180910390a15050600c80546001600160401b03600160401b80830482166001019091160267ffffffffffffffff60401b19909116179055505050565b6013546040516001600160a01b039091169036600082376000803683855af43d806000843e818015612180578184f35b8184fd5b6000600160801b82106121c3576040805162461bcd60e51b8152602060048201526002602482015261189b60f11b604482015290519081900360640190fd5b50805b919050565b60408051608081018252600080825261ffff861660208301526001600160801b038516928201929092526001600160a01b03831660608201529061220e826129f1565b905061221b600182611fe8565b8461ffff167f8f5f51448394699ad6a3b80cdadf4ec68c5d724c8c3fea09bea55b3c2d0e2dd08560405161224f9190615860565b60405180910390a25050505050565b600080516020615a4e833981519152805460019091558015610829576040805162461bcd60e51b815260206004820152600260248201526118a160f11b604482015290519081900360640190fd5b6000816040516020016122bf919061580d565b604051602081830303815290604052805190602001209050919050565b6122e4614397565b825160010163ffffffff166122ff60a0840160808501614cd8565b63ffffffff16146123225760405162461bcd60e51b815260040161065a90615733565b82606001518260400135101561234a5760405162461bcd60e51b815260040161065a906153ac565b6000604083013561235e426201518061243e565b1115905060006123704261038461246b565b8460400135111590508180156123835750805b61239f5760405162461bcd60e51b815260040161065a90615675565b505060008060006123af85612a18565b92509250925060006123c2878784612e80565b90506040518060c001604052808760800160208101906123e29190614cd8565b63ffffffff1681526001600160401b039094166020850152604080850195909552938601356060840152943560808301525060a0019290925250919050565b60a01b61ffff60a01b166001600160a01b03919091161760501b90565b60006124648383604051806040016040528060018152602001603b60f91b8152506130e4565b9392505050565b600082820183811015612464576040805162461bcd60e51b81526020600482015260026024820152610c4d60f21b604482015290519081900360640190fd5b6000805460ff19168155600155621baf8060148190556040517ff2b18f8abbd8a0d0c1fb8245146eedf5304887b12f6395b548ca238e054a1483916124ee916152d5565b60405180910390a1600060158190555b600f811015612525576000818152601660205260409020805460ff191690556001016124fe565b506000601755565b600d600061253e6020850185614cd8565b63ffffffff16815260208101919091526040016000205461256761118d36859003850185614c2e565b146125845760405162461bcd60e51b815260040161065a906154bb565b600654600160401b900463ffffffff1681016001016125a66020840184614cd8565b63ffffffff16146125c95760405162461bcd60e51b815260040161065a906157d6565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060006125f960c08501856158ee565b9050905060005b818110156129915736600061261860c08801886158ee565b8481811061262257fe5b90506020028101906126349190615934565b9150915060008282600081811061264757fe5b919091013560f81c9050600b81111561265c57fe5b9050600381600b81111561266c57fe5b14156127065760006126b384848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061317b92505050565b905061ffff63ffffffff16816000015163ffffffff1611156126e75760405162461bcd60e51b815260040161065a906155ec565b61270081600001518260400151836020015160006131d6565b50612941565b600881600b81111561271457fe5b14156127a857600061275b84848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061323d92505050565b905061ffff63ffffffff16816000015163ffffffff16111561278f5760405162461bcd60e51b815260040161065a90615510565b61270081600001518260400151836020015160016131d6565b600681600b8111156127b657fe5b14156128c95760006127fd84848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061325192505050565b905061ffff63ffffffff16816040015163ffffffff16116128365761283181604001518260200151836060015160026131d6565b612700565b80606001516001600160801b0316600114156127005760006040518060c00160405280836080015163ffffffff1681526020018360a001516001600160a01b031681526020018360c0015163ffffffff1681526020018360e00151815260200183602001516001600160a01b03168152602001836040015163ffffffff1681525090506128c281613339565b5050612941565b600a81600b8111156128d757fe5b141561292957600061291e84848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061341f92505050565b905061270081613339565b60405162461bcd60e51b815260040161065a906154da565b6129818684848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506134b692505050565b9550505050806001019050612600565b50604084013582146129b55760405162461bcd60e51b815260040161065a9061576a565b50505050565b6000816001600160801b0316836001600160801b0316106129dc5781612464565b5090919050565b805160209091012060601b90565b6060600160208084015160408086015160608701519151611fd2959460009493910161501f565b600080606081612a2b6020860186615934565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250600c5485517fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4709a509198509495506001600160401b03808616600160801b909604169490940193600a93509150612aaf9050565b0615612acd5760405162461bcd60e51b815260040161065a90615376565b8151600a90046001600160401b0381118015612ae857600080fd5b506040519080825280601f01601f191660200182016040528015612b13576020820181803683370190505b5092506000612b2560608801886158ee565b9050905060005b81811015612e755736612b4260608a018a6158ee565b83818110612b4c57fe5b9050602002810190612b5e91906159a2565b90506000612b726040830160208401614cd8565b63ffffffff16905085518110612b9a5760405162461bcd60e51b815260040161065a90615418565b600a810615612bbb5760405162461bcd60e51b815260040161065a906153c7565b6000600a82049050878181518110612bcf57fe5b01602001516001600160f81b03191615612bfb5760405162461bcd60e51b815260040161065a9061535b565b600160f81b888281518110612c0c57fe5b60200101906001600160f81b031916908160001a9053506000878381518110612c3157fe5b016020015160f81c600b811115612c4457fe5b9050600181600b811115612c5457fe5b1415612c90576000612c688985603c6134c5565b90506000612c7582613581565b9050612c83818d8b0161360a565b8b6001019b505050612e66565b600781600b811115612c9e57fe5b1415612d90576000612cb28985603c6134c5565b90506000612cbf8261369a565b9050612ccb8680615934565b159050612d0c576000612ce7612ce18880615934565b8461370a565b905080612d065760405162461bcd60e51b815260040161065a906154f5565b50612d89565b60008160200151604051602001612d239190614e09565b60408051601f198184030181529181528151602092830120848201516001600160a01b03166000908152600a8452828120606087015163ffffffff16825290935291205414905080612d875760405162461bcd60e51b815260040161065a9061544f565b505b5050612e66565b6060600382600b811115612da057fe5b1415612db957612db28985603c6134c5565b9050612e58565b600882600b811115612dc757fe5b1415612dd957612db28985603c6134c5565b600a82600b811115612de757fe5b1415612df957612db2898560646134c5565b600682600b811115612e0757fe5b1415612e4057612e198985606e6134c5565b90506000612e2682613251565b9050612e34818d8b016137ec565b8b6001019b5050612e58565b60405162461bcd60e51b815260040161065a90615785565b612e628c826134b6565b9b50505b50505050806001019050612b2c565b505050509193909250565b6000806002612e9560a0860160808701614cd8565b63ffffffff16612eab60c0870160a08801614cd8565b63ffffffff16604051602001612ec2929190614e36565b60408051601f1981840301815290829052612edc91614e6a565b602060405180830381855afa158015612ef9573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190612f1c91906149ec565b90506002818660800151604051602001612f37929190614e36565b60408051601f1981840301815290829052612f5191614e6a565b602060405180830381855afa158015612f6e573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190612f9191906149ec565b90506002818560000135604051602001612fac929190614e36565b60408051601f1981840301815290829052612fc691614e6a565b602060405180830381855afa158015612fe3573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061300691906149ec565b90506002818560400135604051602001613021929190614e36565b60408051601f198184030181529082905261303b91614e6a565b602060405180830381855afa158015613058573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061307b91906149ec565b9050600061308c6020860186615934565b8560405160200161309f93929190614e44565b60405160208183030381529060405290506040518151838352602082602083018560025afa8184528080156130d3576130d5565bfe5b50509051979650505050505050565b600081848411156131735760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613138578181015183820152602001613120565b50505050905090810190601f1680156131655780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6131836143cc565b600561318f838261387c565b63ffffffff16835290506131a38382613895565b6001600160801b0316602084015260020190506131c083826138a5565b6001600160a01b03166040840152509092915050565b60006131e28486612421565b90506131ee81846138b5565b836001600160a01b03168561ffff167f08262c50127efaa884a8609d16fe2ed98c5fd8e4f1c393f2d7d8f9f52f602ff6858560405161322e929190615874565b60405180910390a35050505050565b6132456143cc565b600961318f838261387c565b6132596143ec565b6001613265838261387c565b63ffffffff168352905061327983826138a5565b6001600160a01b031660208401529050613293838261387c565b63ffffffff16604084015290506132aa8382613895565b6001600160801b0316606084015290506132c4838261387c565b63ffffffff16608084015290506132db83826138a5565b6001600160a01b031660a084015290506132f5838261387c565b63ffffffff1660c0840152905061330c8382613953565b60e08401529050606981146133335760405162461bcd60e51b815260040161065a906156fd565b50919050565b60a08101805163ffffffff908116600090815260126020908152604080832086518154938801518389015163ffffffff1990951691871691909117640100000000600160c01b0319166401000000006001600160a01b03928316021763ffffffff60c01b1916600160c01b948716949094029390931781556060870151600182015560808701516002909101805496516001600160a01b0319909716919093161763ffffffff60a01b1916600160a01b9590941694850293909317905590517f1d19de6753fc463923c3d90b6fb45aca536732ed7c5ca377d4b3f63dfbe4d8199190a250565b613427614397565b6005613433838261387c565b63ffffffff168352905061344783826138a5565b6001600160a01b031660208401529050613461838261387c565b63ffffffff16604084015290506134788382613953565b6060840152905061348983826138a5565b6001600160a01b0316608084015290506134a3838261387c565b63ffffffff1660a0840152509092915050565b80519181526020909101902090565b606081830184511015613503576040805162461bcd60e51b81526020600482015260016024820152602d60f91b604482015290519081900360640190fd5b6000826001600160401b038111801561351b57600080fd5b506040519080825280601f01601f191660200182016040528015613546576020820181803683370190505b509050821561357957602081018381016020860187015b8183101561357557805183526020928301920161355d565b5050505b949350505050565b613589614430565b6001613595838261387c565b63ffffffff16835290506135a9838261387c565b63ffffffff16602084015290506135c08382613895565b6001600160801b0316604084015290506135da83826138a5565b6001600160a01b031660608401529050602d81146133335760405162461bcd60e51b815260040161065a90615564565b6001600160401b0381166000908152600f6020526040902054600160e01b900460ff16600181600b81111561363b57fe5b146136585760405162461bcd60e51b815260040161065a906153fd565b6001600160401b0382166000908152600f602052604090205460601b61367e8482613963565b6129b55760405162461bcd60e51b815260040161065a90615609565b6136a2614430565b60016136ae838261387c565b63ffffffff16835290506136c28382613993565b6001600160601b031916602084015290506136dd83826138a5565b6001600160a01b0316604084015290506136f7838261387c565b63ffffffff166060840152509092915050565b6000808484600081811061371a57fe5b919091013560f81c9050600481111561372f57fe5b9050600081600481111561373f57fe5b1415613758576137508585856139a3565b915050612464565b600181600481111561376657fe5b141561377757613750858585613a59565b600281600481111561378557fe5b141561379657613750858585613bdc565b60038160048111156137a457fe5b14156137b557613750858585613c8c565b60048160048111156137c357fe5b14156137d457613750858585613d8a565b60405162461bcd60e51b815260040161065a90615391565b6001600160401b0381166000908152600f6020526040902054600160e01b900460ff16600681600b81111561381d57fe5b1461383a5760405162461bcd60e51b815260040161065a90615624565b6001600160401b0382166000908152600f602052604090205460601b6138608482613f31565b6129b55760405162461bcd60e51b815260040161065a9061563f565b60048101600061388c8484613f4a565b90509250929050565b60108101600061388c8484613f98565b60148101600061388c8484613fdb565b6001600160501b03198216600090815260046020526040908190205481518083019092526001600160801b031690806138ee838561401e565b6001600160801b03908116825260ff60209283018190526001600160501b031990961660009081526004835260409020835181549490930151909616600160801b0260ff60801b19929091166001600160801b03199093169290921716179092555050565b60208101600061388c8484614069565b60006001600160601b0319821661398161397c856129f1565b6129e3565b6001600160601b031916149392505050565b60148101600061388c84846140ac565b6000806139eb85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250604191506140f49050565b91505060008360200151846060015185600001516000801b604051602001613a169493929190614fbd565b6040516020818303038152906040528051906020012090506000613a3a838361410f565b60408601516001600160a01b0391821691161493505050509392505050565b600080600080600060019050613aa688888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508592506138a5915050565b604080516020601f8c018190048102820181019092528a8152919650919250613aeb918a908a9081908401838280828437600092019190915250859250613953915050565b604080516020601f8c018190048102820181019092528a8152919550919250613b30918a908a9081908401838280828437600092019190915250859250613953915050565b602080890151604051929550929350600092613b4e92879201614e1e565b60408051601f198184030181529082905280516020918201209250600091613b86916001600160f81b03199189918691899101614dd5565b6040516020818303038152906040528051906020012060001c905087604001516001600160a01b0316816001600160a01b0316148015613bce5750606088015163ffffffff16155b9a9950505050505050505050565b600080613c2485858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250604191506140f49050565b9150506000613c558460200151604051602001613c419190614e09565b60405160208183030381529060405261421b565b613c6a613c6586606001516142dc565b61421b565b613c7a613c6587600001516142dc565b604051602001613a1693929190614e86565b6000806000613cd686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250604191506140f49050565b915091506000613d1d87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250879250613953915050565b915050600085602001518660600151876000015184604051602001613d459493929190614fbd565b6040516020818303038152906040528051906020012090506000613d69848361410f565b60408801516001600160a01b03918216911614955050505050509392505050565b600080613dd285858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250604191506140f49050565b60408051808201825260068152655a6b53796e6360d01b602091820152815180830190925260038252620312e360ec1b9101529150600090507fc2f8787176b8ac6bf7215b4adcc1e069bf4ab82d9ab1df05a57a91d425935b6e7f2e760812e6696b561a918e71ad2845639638959ed846b188488dd0d8c0b953ef7fe6bbd6277e1bf288eed5e8d1780f9a50b239e86b153736bceebccf4ea79d90b3613e766142f5565b604051602001613e89949392919061530c565b60408051601f198184030181529082905280516020918201208682015160608801518851929550600094613ee0947f8012078cc90c4c82e493f1a538159fd8621f39392101b34fba2ecd141432580b9491016152de565b60405160208183030381529060405280519060200120905060008282604051602001613f0d929190614fa2565b6040516020818303038152906040528051906020012090506000613d69858361410f565b60006001600160601b0319821661398161397c85611fa7565b6000808260040190508084511015613f8d576040805162461bcd60e51b81526020600482015260016024820152602b60f91b604482015290519081900360640190fd5b929092015192915050565b6000808260100190508084511015613f8d576040805162461bcd60e51b81526020600482015260016024820152605760f81b604482015290519081900360640190fd5b6000808260140190508084511015613f8d576040805162461bcd60e51b81526020600482015260016024820152602960f91b604482015290519081900360640190fd5b60008282016001600160801b038085169082161015612464576040805162461bcd60e51b8152602060048201526002602482015261189960f11b604482015290519081900360640190fd5b6000808260200190508084511015613f8d576040805162461bcd60e51b81526020600482015260016024820152605960f81b604482015290519081900360640190fd5b600081601401835110156140eb576040805162461bcd60e51b81526020600482015260016024820152605360f81b604482015290519081900360640190fd5b50016020015190565b600060606141038585856134c5565b93909201949293505050565b6000825160411461414b576040805162461bcd60e51b81526020600482015260016024820152600560fc1b604482015290519081900360640190fd5b60008060006020860151925060408601519150606086015160001a9050600060018683868660405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156141c4573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614211576040805162461bcd60e51b81526020600482015260026024820152611c0d60f21b604482015290519081900360640190fd5b9695505050505050565b6060600082516002026001600160401b038111801561423957600080fd5b506040519080825280601f01601f191660200182016040528015614264576020820181803683370190505b5090506020830183518101602083015b818310156142d257825160f81c6f6665646362613938373635343332313060088260041c021c60f81b82526f66656463626139383736353433323130600882600f16021c60f81b600183015250600183019250600281019050614274565b5091949350505050565b60606142ef8263ffffffff1660046142f9565b92915050565b4690565b606060208260ff161115614338576040805162461bcd60e51b81526020600482015260016024820152605160f81b604482015290519081900360640190fd5b8160ff166001600160401b038111801561435157600080fd5b506040519080825280601f01601f19166020018201604052801561437c576020820181803683370190505b5060ff6008602094850302169390931b918301919091525090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b604080516060810182526000808252602082018190529181019190915290565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b60408051608081018252600080825260208201819052918101829052606081019190915290565b80356121c681615a23565b60008083601f840112614473578182fd5b5081356001600160401b03811115614489578182fd5b60208301915083602080830285010111156144a357600080fd5b9250929050565b60008083601f8401126144bb578182fd5b5081356001600160401b038111156144d1578182fd5b60208301915083602060c0830285010111156144a357600080fd5b600082601f8301126144fc578081fd5b6040516102008082018281106001600160401b038211171561451a57fe5b604052818482810187101561452d578485fd5b8492505b601083101561455157803582526001929092019160209182019101614531565b509195945050505050565b600082601f83011261456c578081fd5b8135602061458161457c836159da565b6159b7565b828152818101908583018385028701840188101561459d578586fd5b855b858110156145bb5781358452928401929084019060010161459f565b5090979650505050505050565b600082601f8301126145d8578081fd5b813560206145e861457c836159da565b8281528181019085830183850287018401881015614604578586fd5b855b858110156145bb57813560ff8116811461461e578788fd5b84529284019290840190600101614606565b60008083601f840112614641578182fd5b5081356001600160401b03811115614657578182fd5b6020830191508360208285010111156144a357600080fd5b600060c08284031215614680578081fd5b60405160c081018181106001600160401b038211171561469c57fe5b6040529050806146ab836146ed565b81526146b960208401614701565b602082015260408301356040820152606083013560608201526080830135608082015260a083013560a08201525092915050565b803563ffffffff811681146121c657600080fd5b80356001600160401b03811681146121c657600080fd5b600060208284031215614729578081fd5b813561246481615a23565b60008060008060808587031215614749578283fd5b843561475481615a23565b9350602085013561476481615a23565b9250604085013561477481615a23565b9396929550929360600135925050565b600080600060608486031215614798578081fd5b83356147a381615a23565b925060208401356147b381615a23565b915060408401356147c381615a38565b809150509250925092565b600080604083850312156147e0578182fd5b82356147eb81615a23565b915060208301356147fb81615a23565b809150509250929050565b60008060408385031215614818578182fd5b823561482381615a23565b915061388c602084016146ed565b60008060208385031215614843578182fd5b82356001600160401b03811115614858578283fd5b61486485828601614462565b90969095509350505050565b60008060208385031215614882578182fd5b82356001600160401b03811115614897578283fd5b614864858286016144aa565b6000806000604084860312156148b7578081fd5b83356001600160401b03808211156148cd578283fd5b6148d9878388016144aa565b909550935060208601359150808211156148f1578283fd5b908501906102808288031215614905578283fd5b61490f60a06159b7565b82358281111561491d578485fd5b6149298982860161455c565b82525060208301358281111561493d578485fd5b6149498982860161455c565b602083015250604083013582811115614960578485fd5b61496c8982860161455c565b604083015250606083013582811115614983578485fd5b61498f898286016145c8565b6060830152506149a288608085016144ec565b60808201528093505050509250925092565b6000602082840312156149c5578081fd5b81518015158114612464578182fd5b6000602082840312156149e5578081fd5b5035919050565b6000602082840312156149fd578081fd5b5051919050565b60008060208385031215614a16578182fd5b82356001600160401b03811115614a2b578283fd5b61486485828601614630565b600080600060408486031215614a4b578081fd5b83356001600160401b03811115614a60578182fd5b614a6c86828701614630565b9094509250614a7f9050602085016146ed565b90509250925092565b60008060008060808587031215614a9d578182fd5b8435614aa881615a23565b93506020850135614ab881615a23565b92506040850135614ac881615a38565b91506060850135614ad881615a38565b939692955090935050565b600080600060608486031215614af7578081fd5b8335614b0281615a23565b925060208401356001600160681b0381168114614b1d578182fd5b915060408401356147c381615a23565b600060208284031215614b3e578081fd5b815161246481615a23565b60008060008060008060008060008060008b8d036101e0811215614b6b57898afd5b60c0811215614b7857898afd5b508b9a5060c08c0135614b8a81615a23565b9950614b9860e08d016146ed565b9850614ba76101008d016146ed565b97506101208c0135614bb881615a38565b9650614bc76101408d016146ed565b9550614bd66101608d01614457565b9450614be56101808d016146ed565b93506101a08c013592506101c08c01356001600160401b03811115614c08578283fd5b614c148e828f01614462565b915080935050809150509295989b509295989b9093969950565b600060c08284031215614c3f578081fd5b612464838361466f565b600080600060e08486031215614c5d578081fd5b614c67858561466f565b925060c08401356001600160401b03811115614c81578182fd5b614c8d86828701614462565b9497909650939450505050565b600060208284031215614cab578081fd5b815161246481615a38565b600060208284031215614cc7578081fd5b815161ffff81168114612464578182fd5b600060208284031215614ce9578081fd5b612464826146ed565b60008060408385031215614d04578182fd5b6147eb836146ed565b60008060408385031215614d1f578182fd5b614823836146ed565b600060208284031215614d39578081fd5b61246482614701565b600080600060408486031215614d56578081fd5b614d5f84614701565b925060208401356001600160401b03811115614c81578182fd5b60601b6001600160601b0319169052565b6000815180845260208085019450808401835b83811015614db957815187529582019590820190600101614d9d565b509495945050505050565b60e01b6001600160e01b0319169052565b6001600160f81b031994909416845260609290921b6001600160601b03191660018401526015830152603582015260550190565b6001600160601b031991909116815260140190565b9182526001600160601b031916602082015260340190565b918252602082015260400190565b6000838583378382018181528351614e608183602088016159f7565b0195945050505050565b60008251614e7c8184602087016159f7565b9190910192915050565b60007f19457468657265756d205369676e6564204d6573736167653a0a31353200000082527f5265676973746572207a6b53796e63207075626b65793a0a0a00000000000000601d8301528451614ee48160368501602089016159f7565b600560f91b6036918401918201819052680dcdedcc6ca744060f60bb1b60378301528551614f19816040850160208a016159f7565b60409201918201526d0c2c6c6deeadce840d2c8744060f60931b60418201528351614f4b81604f8401602088016159f7565b61050560f11b604f92909101918201527f4f6e6c79207369676e2074686973206d65737361676520666f7220612074727560518201526b7374656420636c69656e742160a01b6071820152607d0195945050505050565b61190160f01b81526002810192909252602282015260420190565b7f19457468657265756d205369676e6564204d6573736167653a0a36300000000081526001600160601b031994909416601c8501526001600160e01b031960e093841b811660308601529190921b166034830152603882015260580190565b90565b60f89590951b6001600160f81b03191685526001600160e01b0319938416600186015260e09290921b909216600584015260809190911b6001600160801b031916600983015260601b6001600160601b0319166019820152602d0190565b6001600160f81b031960f88b901b1681526001600160e01b031960e08a811b821660018401526001600160601b031960608b901b16600584015288811b821660198401526001600160801b0319608089901b16601d84015286901b16602d82015260006150ed6031830186614d79565b6150fa6045830185614dc4565b50604981019190915260690198975050505050505050565b6001600160a01b0391909116815260200190565b6001600160a01b0393841681529190921660208201526001600160681b03909116604082015260600190565b6001600160a01b03861681526001600160401b03851660208201526000600c851061517957fe5b84604083015260a0606083015283518060a084015261519f8160c08501602088016159f7565b608083019390935250601f91909101601f19160160c001949350505050565b6001600160a01b03968716815294909516602085015263ffffffff92831660408501529082166060840152608083015290911660a082015260c00190565b6001600160a01b039290921682526001600160801b0316602082015260400190565b600061028080835261523281840189614d8a565b90506020838203818501526152478289614d8a565b84810360408601528751808252828901935090820190845b8181101561527e57845160ff168352938301939183019160010161525f565b505084810360608601526152928188614d8a565b9350506080840191508460005b60108110156152bc5781518452928201929082019060010161529f565b505050509695505050505050565b901515815260200190565b90815260200190565b9384526001600160601b031992909216602084015263ffffffff908116604084015216606082015260800190565b93845260208401929092526040830152606082015260800190565b6001600160a01b0394851681529290931660208301526001600160801b039081166040830152909116606082015260800190565b6020808252600190820152604360f81b604082015260600190565b6020808252600190820152604160f81b604082015260600190565b6020808252600190820152604760f81b604082015260600190565b6020808252600190820152606760f81b604082015260600190565b6020808252600190820152602160f91b604082015260600190565b6020808252600190820152600760fc1b604082015260600190565b6020808252600190820152600960fb1b604082015260600190565b602080825260029082015261413160f01b604082015260600190565b6020808252600190820152607160f81b604082015260600190565b6020808252600190820152604560f81b604082015260600190565b6020808252600190820152603760f91b604082015260600190565b6020808252600190820152603760f81b604082015260600190565b6020808252600190820152606f60f81b604082015260600190565b602080825260059082015264065786531360dc1b604082015260600190565b6020808252600190820152601b60fa1b604082015260600190565b6020808252600190820152601160fa1b604082015260600190565b60208082526003908201526236b31960e91b604082015260600190565b6020808252600190820152600560fc1b604082015260600190565b602080825260029082015261633160f01b604082015260600190565b6020808252600190820152602760f91b604082015260600190565b6020808252600190820152604d60f81b604082015260600190565b6020808252600190820152601560fa1b604082015260600190565b6020808252600290820152616f3160f01b604082015260600190565b6020808252600190820152601360fa1b604082015260600190565b6020808252600390820152626d663160e81b604082015260600190565b6020808252600190820152604960f81b604082015260600190565b6020808252600190820152602560f91b604082015260600190565b6020808252600190820152604b60f81b604082015260600190565b6020808252600190820152603b60f91b604082015260600190565b6020808252600190820152600d60fb1b604082015260600190565b6020808252600190820152606560f81b604082015260600190565b6020808252600190820152603560f91b604082015260600190565b6020808252600190820152603160f91b604082015260600190565b60208082526002908201526106f760f41b604082015260600190565b6020808252600190820152604f60f81b604082015260600190565b6020808252600190820152603560f81b604082015260600190565b6020808252600190820152603360f91b604082015260600190565b602080825260029082015261663160f01b604082015260600190565b6020808252600190820152606d60f81b604082015260600190565b6020808252600190820152602360f91b604082015260600190565b6020808252600190820152606960f81b604082015260600190565b6020808252600190820152601960fa1b604082015260600190565b6020808252600190820152606b60f81b604082015260600190565b602080825260029082015261379960f11b604082015260600190565b600060c08201905063ffffffff83511682526001600160401b03602084015116602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b6001600160801b0391909116815260200190565b6001600160801b0383168152604081016003831061588e57fe5b8260208301529392505050565b61ffff91909116815260200190565b63ffffffff91909116815260200190565b63ffffffff9290921682526001600160a01b0316602082015260400190565b6001600160401b0391909116815260200190565b6000808335601e19843603018112615904578283fd5b8301803591506001600160401b0382111561591d578283fd5b60209081019250810236038213156144a357600080fd5b6000808335601e1984360301811261594a578283fd5b8301803591506001600160401b03821115615963578283fd5b6020019150368190038213156144a357600080fd5b6000823560be19833603018112614e7c578182fd5b6000823560de19833603018112614e7c578182fd5b60008235603e19833603018112614e7c578182fd5b6040518181016001600160401b03811182821017156159d257fe5b604052919050565b60006001600160401b038211156159ed57fe5b5060209081020190565b60005b83811015615a125781810151838201526020016159fa565b838111156129b55750506000910152565b6001600160a01b038116811461082957600080fd5b6001600160801b038116811461082957600080fdfe8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4a2646970667358221220aa1e173e9b0205e9c8c2d0c2712fc68b94e648b3fdbe9d7f916646ee2221e80664736f6c63430007060033
Deployed Bytecode
0x6080604052600436106102045760003560e01c80637efcfe8511610118578063b0705b42116100a0578063c57b22be1161006f578063c57b22be1461057b578063d514da5014610590578063e17376b5146105b0578063f2235487146105d0578063faf4d8cb146105e557610204565b8063b0705b4214610520578063b269b9ae14610461578063b4a8498c14610540578063b65975ec1461055b57610204565b80638ae20dc9116100e75780638ae20dc91461048b5780639ba0d146146104ab5780639beb4650146104cb578063a7e7aacd146104eb578063ab9b2adf1461050057610204565b80637efcfe85146104265780638398180814610441578063871b8ff1146104615780638773334c1461047657610204565b8063452692981161019b5780635aca41f61161016a5780635aca41f614610380578063647b5923146103ad57806367708dae146103cf57806368809a23146103f157806378b91e701461041157610204565b80634526929814610300578063505a757314610320578063595a5ebc1461034057806359acda851461036057610204565b80632a3174f4116101d75780632a3174f4146102965780632d2da806146102b85780633b154b73146102cb578063439fab91146102e057610204565b806313d9787b146102095780631d1796431461022b578063253946451461024b578063264c09121461026b575b600080fd5b34801561021557600080fd5b50610229610224366004614d0d565b6105fa565b005b34801561023757600080fd5b50610229610246366004614b49565b610740565b34801561025757600080fd5b50610229610266366004614a04565b610755565b34801561027757600080fd5b506102806107b6565b60405161028d91906152ca565b60405180910390f35b3480156102a257600080fd5b506102ab6107bf565b60405161028d91906152d5565b6102296102c6366004614718565b6107c4565b3480156102d757600080fd5b5061022961082c565b3480156102ec57600080fd5b506102296102fb366004614a04565b610832565b34801561030c57600080fd5b5061022961031b366004614c49565b610962565b34801561032c57600080fd5b5061022961033b366004614cd8565b610b89565b34801561034c57600080fd5b5061022961035b366004614a37565b610df6565b34801561036c57600080fd5b5061022961037b3660046149d4565b610e03565b34801561038c57600080fd5b506103a061039b3660046147ce565b610e0b565b60405161028d9190615860565b3480156103b957600080fd5b506103c2610eda565b60405161028d91906158aa565b3480156103db57600080fd5b506103e4610ee6565b60405161028d91906158da565b3480156103fd57600080fd5b506103a061040c366004614a88565b610ef5565b34801561041d57600080fd5b506102296110db565b34801561043257600080fd5b5061022961035b366004614d42565b34801561044d57600080fd5b5061022961045c3660046148a3565b61110b565b34801561046d57600080fd5b506102296113a4565b34801561048257600080fd5b506102806113ae565b34801561049757600080fd5b506102ab6104a6366004614806565b6113b3565b3480156104b757600080fd5b506102ab6104c6366004614cd8565b6113d0565b3480156104d757600080fd5b506102296104e6366004614831565b6113e2565b3480156104f757600080fd5b506102806113ee565b34801561050c57600080fd5b5061022961051b366004614cf2565b6114e6565b34801561052c57600080fd5b5061022961053b366004614831565b6116bb565b34801561054c57600080fd5b506102296104e6366004614870565b34801561056757600080fd5b506102ab610576366004614806565b6118ed565b34801561058757600080fd5b506103e461190a565b34801561059c57600080fd5b506102296105ab366004614784565b611920565b3480156105bc57600080fd5b506102296105cb366004614ae3565b611bf8565b3480156105dc57600080fd5b506103c2611f5e565b3480156105f157600080fd5b506103c2611f71565b600080516020615a4e833981519152546001811461061757600080fd5b6002600080516020615a4e83398151915255610631611f84565b62ffffff63ffffffff841611156106635760405162461bcd60e51b815260040161065a90615690565b60405180910390fd5b63ffffffff831662ffffff141561068c5760405162461bcd60e51b815260040161065a9061565a565b63ffffffff821661ffff1080156106ac5750637ffffffe63ffffffff8316105b6106c85760405162461bcd60e51b815260040161065a9061559a565b604080516101008101825263ffffffff80861682523360208301528416918101919091526000606082018190526080820181905260a0820181905260c0820181905260e0820181905261071a82611fa7565b9050610727600682611fe8565b50506001600080516020615a4e83398151915255505050565b610748612150565b5050505050505050505050565b600080516020615a4e833981519152546001811461077257600080fd5b5050621baf8060145550601380546001600160a01b031916732eaa1377e0fc95de998b9fa7611e9d67eba534fd1790556001600080516020615a4e83398151915255565b60095460ff1681565b600090565b6001600160a01b0381811614156107ed5760405162461bcd60e51b815260040161065a9061552d565b6000341161080d5760405162461bcd60e51b815260040161065a9061557f565b610815611f84565b610829600061082334612184565b836121cb565b50565b42601555565b61083a61225e565b600080808061084b85870187614734565b600280546001600160a01b038086166001600160a01b0319928316179092556003805483881690831617905560138054928516929091169190911790556040805160c0810182526000808252602082018190527fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47092820192909252606081018290526080810183905260a0810191909152939750919550935091506108ef816122ac565b60008052600d6020527f81955a0a11e65eac625c29e8882660bae4e165a75d72780094acae8ece9a29ee55621baf8060148190556040517ff2b18f8abbd8a0d0c1fb8245146eedf5304887b12f6395b548ca238e054a148391610951916152d5565b60405180910390a150505050505050565b600080516020615a4e833981519152546001811461097f57600080fd5b6002600080516020615a4e83398151915255610999611f84565b600354604051634b18bd0f60e01b81526001600160a01b0390911690634b18bd0f906109c9903390600401615112565b60006040518083038186803b1580156109e157600080fd5b505afa1580156109f5573d6000803e3d6000fd5b50505050610a02846122ac565b600654600160601b900463ffffffff166000908152600d602052604090205414610a3e5760405162461bcd60e51b815260040161065a906157a0565b8160005b8163ffffffff16811015610b0c57610a7786868684818110610a6057fe5b9050602002810190610a729190615978565b6122dc565b6020810151600c80546001600160401b03600160801b80830482169094011690920267ffffffffffffffff60801b199092169190911790559550610aba866122ac565b865163ffffffff9081166000908152600d6020526040808220939093558851925192909116917f81a92942d0f9c33b897a438384c9c3d88be397776138efa3ba1a4fc8b62684249190a2600101610a42565b506006805463ffffffff600160601b808304821685019091160263ffffffff60601b19909116179055600c546001600160401b03600160401b82048116600160801b909204161115610b705760405162461bcd60e51b815260040161065a906156ab565b506001600080516020615a4e8339815191525550505050565b600080516020615a4e8339815191525460018114610ba657600080fd5b6002600080516020615a4e83398151915281905563ffffffff808416600090815260126020908152604091829020825160c081018452815480861682526001600160a01b0364010000000082048116948301859052600160c01b909104861694820194909452600182015460608201529401549182166080850152600160a01b90910490911660a0830152610c4d5760405162461bcd60e51b815260040161065a906156e1565b6003548151602083015160405163b79eb8c760e01b81526000936001600160a01b03169263b79eb8c792610c83926004016158bb565b60206040518083038186803b158015610c9b57600080fd5b505afa158015610caf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd39190614b2d565b63ffffffff8516600090815260116020908152604080832080546001600160a01b0319166001600160a01b0386169081179091556012835281842080546001600160e01b03191681556001810194909455600290930180546001600160c01b0319169055908501516080860151865187840151606089015160a08a01519551630234ce5960e41b8152979850959663234ce59096610d759690916004016151be565b600060405180830381600087803b158015610d8f57600080fd5b505af1158015610da3573d6000803e3d6000fd5b505050508160a0015163ffffffff167f0b9f3586023bf754b8d962232407f7ac4d90fd19a1c4756c6619927abf06756060405160405180910390a250506001600080516020615a4e833981519152555050565b610dfe612150565b505050565b610829612150565b6000806001600160a01b03831615610ea0576003546040516375698bb160e11b81526001600160a01b039091169063ead3176290610e4d908690600401615112565b60206040518083038186803b158015610e6557600080fd5b505afa158015610e79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e9d9190614cb6565b90505b60046000610eae8684612421565b6001600160501b03191681526020810191909152604001600020546001600160801b0316949350505050565b600e5463ffffffff1681565b600c546001600160401b031681565b6000333014610f165760405162461bcd60e51b815260040161065a90615718565b6040516370a0823160e01b81526000906001600160a01b038716906370a0823190610f45903090600401615112565b60206040518083038186803b158015610f5d57600080fd5b505afa158015610f71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9591906149ec565b60405163a9059cbb60e01b81529091506001600160a01b0387169063a9059cbb90610fc690889088906004016151fc565b600060405180830381600087803b158015610fe057600080fd5b505af1158015610ff4573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03891691506370a0823190611027903090600401615112565b60206040518083038186803b15801561103f57600080fd5b505afa158015611053573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061107791906149ec565b90506000611085838361243e565b9050600081116110a75760405162461bcd60e51b815260040161065a90615548565b846001600160801b03168111156110d05760405162461bcd60e51b815260040161065a90615485565b979650505050505050565b6014546015546110ea9161246b565b4210156110f657600080fd5b6000805460ff19166001908117909155429055565b600080516020615a4e833981519152546001811461112857600080fd5b6002600080516020615a4e83398151915255611142611f84565b600e5463ffffffff908116600181019091166000908152600d60205260408120549091905b8061119288888681811061117757fe5b905060c0020180360381019061118d9190614c2e565b6122ac565b146111c1576001909201918583106111bc5760405162461bcd60e51b815260040161065a906157f1565b611167565b50845b808310156112825763ffffffff60018301166000908152600d60205260409020546111f488888681811061117757fe5b146112115760405162461bcd60e51b815260040161065a906155b5565b8160010191506001600160fd1b0387878581811061122b57fe5b905060c0020160a0013560001c166001600160fd1b038660400151858151811061125157fe5b602002602001015116146112775760405162461bcd60e51b815260040161065a906154a0565b8260010192506111c4565b6002548551602087015160608801516040808a015160808b0151915163054185eb60e51b81526000966001600160a01b03169563a830bd60956112cd9591949093919260040161521e565b60206040518083038186803b1580156112e557600080fd5b505afa1580156112f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061131d91906149b4565b90508061133c5760405162461bcd60e51b815260040161065a906153e2565b60065463ffffffff600160601b9091048116908416111561136f5760405162461bcd60e51b815260040161065a90615434565b5050600e805463ffffffff191663ffffffff9290921691909117905550506001600080516020615a4e83398151915255505050565b6113ac6124aa565b565b600190565b600a60209081526000928352604080842090915290825290205481565b600d6020526000908152604090205481565b6113ea612150565b5050565b600080516020615a4e833981519152546000906001811461140e57600080fd5b6002600080516020615a4e8339815191525560095460ff161561143457600091506114d0565b600c546001600160401b039081166000908152600f60205260408120549091600160a01b90910416431080159061148e5750600c546001600160401b039081166000908152600f6020526040902054600160a01b90041615155b905080156114cd576009805460ff191660011790556040517fc71028c67eb0ef128ea270a59a674629e767d51c1af44ed6753fd2fad2c7b67790600090a15b91505b6001600080516020615a4e833981519152555090565b600080516020615a4e833981519152546001811461150357600080fd5b6002600080516020615a4e8339815191525561151d611f84565b62ffffff63ffffffff841611156115465760405162461bcd60e51b815260040161065a90615690565b63ffffffff831662ffffff141561156f5760405162461bcd60e51b815260040161065a9061565a565b60006001600160a01b0383166115875750600061160a565b6003546040516375698bb160e11b81526001600160a01b039091169063ead31762906115b7908690600401615112565b60206040518083038186803b1580156115cf57600080fd5b505afa1580156115e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116079190614cb6565b90505b604080516101008101825263ffffffff8616815233602082015261ffff8316918101919091526000606082018190526080820181905260a0820181905260c0820181905260e0820181905261165e82611fa7565b905061166b600682611fe8565b60006116773385612421565b6001600160501b0319166000908152600460205260409020805460ff60801b191660ff60801b17905550506001600080516020615a4e833981519152555050505050565b600080516020615a4e83398151915254600181146116d857600080fd5b6002600080516020615a4e833981519152556116f2611f84565b600354604051634b18bd0f60e01b81526001600160a01b0390911690634b18bd0f90611722903390600401615112565b60006040518083038186803b15801561173a57600080fd5b505afa15801561174e573d6000803e3d6000fd5b50600092508491508290505b8163ffffffff168110156118285761178f86868381811061177757fe5b9050602002810190611789919061598d565b8261252d565b85858281811061179b57fe5b90506020028101906117ad919061598d565b6117be906040810190602001614d28565b830192508585828181106117ce57fe5b90506020028101906117e0919061598d565b6117ee906020810190614cd8565b63ffffffff167f0cdbd8bd7813095001c5fe7917bd69d834dc01db7c1dfcf52ca135bd2038441360405160405180910390a260010161175a565b50600c805467ffffffffffffffff60401b1967ffffffffffffffff60801b1967ffffffffffffffff1983166001600160401b039384168701841617908116600160801b918290048416879003841690910217908116600160401b918290048316869003909216810291909117909155600680546bffffffff00000000000000001981169083900463ffffffff9081168501811684029190911791829055600e548116929091041611156107275760405162461bcd60e51b815260040161065a9061546a565b601060209081526000928352604080842090915290825290205481565b600c54600160401b90046001600160401b031681565b600080516020615a4e833981519152546001811461193d57600080fd5b6002600080516020615a4e8339815191525560006001600160a01b038416156119e3576003546040516375698bb160e11b81526001600160a01b039091169063ead3176290611990908790600401615112565b60206040518083038186803b1580156119a857600080fd5b505afa1580156119bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e09190614cb6565b90505b60006119ef8683612421565b6001600160501b031981166000908152600460205260408120549192506001600160801b0390911690611a2282876129bb565b90506000816001600160801b031611611a4d5760405162461bcd60e51b815260040161065a9061574e565b61ffff8416611ae1576000886001600160a01b0316826001600160801b0316604051611a789061501c565b60006040518083038185875af1925050503d8060008114611ab5576040519150601f19603f3d011682016040523d82523d6000602084013e611aba565b606091505b5050905080611adb5760405162461bcd60e51b815260040161065a906157bb565b50611b5f565b6040516368809a2360e01b815230906368809a2390611b0a908a908c9086908890600401615327565b602060405180830381600087803b158015611b2457600080fd5b505af1158015611b38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b5c9190614c9a565b90505b6001600160501b031983166000908152600460205260409081902080546001600160801b0319168385036001600160801b03161790555161ffff8516906001600160a01b038a16907fefef619ae4a542a2b8810b4efeccd8478bd683e985354ee31dd2d644aff6d0ca90611bd4908590615860565b60405180910390a3505050506001600080516020615a4e8339815191525550505050565b600080516020615a4e8339815191525460018114611c1557600080fd5b6002600080516020615a4e833981519152556001600160a01b038281161415611c505760405162461bcd60e51b815260040161065a9061552d565b611c58611f84565b6003546040516375698bb160e11b81526000916001600160a01b03169063ead3176290611c89908890600401615112565b60206040518083038186803b158015611ca157600080fd5b505afa158015611cb5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cd99190614cb6565b60035460405163f3a65bf960e01b81529192506001600160a01b03169063f3a65bf990611d0a90849060040161589b565b60206040518083038186803b158015611d2257600080fd5b505afa158015611d36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d5a91906149b4565b15611d775760405162461bcd60e51b815260040161065a906156c6565b6040516370a0823160e01b81526000906001600160a01b038716906370a0823190611da6903090600401615112565b60206040518083038186803b158015611dbe57600080fd5b505afa158015611dd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df691906149ec565b6040516323b872dd60e01b81529091506001600160a01b038716906323b872dd90611e2990339030908a90600401615126565b600060405180830381600087803b158015611e4357600080fd5b505af1158015611e57573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03891691506370a0823190611e8a903090600401615112565b60206040518083038186803b158015611ea257600080fd5b505afa158015611eb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eda91906149ec565b90506000611ef0611eeb838561243e565b612184565b90506000816001600160801b0316118015611f1b57506001600160681b036001600160801b03821611155b611f375760405162461bcd60e51b815260040161065a9061535b565b611f428482886121cb565b505050506001600080516020615a4e8339815191525550505050565b600654600160401b900463ffffffff1681565b600654600160601b900463ffffffff1681565b60095460ff16156113ac5760405162461bcd60e51b815260040161065a906155d1565b6060600682516020808501516040808701519051611fd295949360009182918291829182910161507d565b6040516020818303038152906040529050919050565b600c544362013b0001906001600160401b03808216600160401b90920416016000612012846129e3565b90506040518060600160405280826bffffffffffffffffffffffff19168152602001846001600160401b0316815260200186600b81111561204f57fe5b90526001600160401b038084166000908152600f60209081526040918290208451815492860151909416600160a01b0267ffffffffffffffff60a01b1960609590951c6001600160a01b03199093169290921793909316178083559083015190829060ff60e01b1916600160e01b83600b8111156120c957fe5b02179055509050507fd0943372c08b438a88d4b39d77216901079eda9ca59d45349841c099083b683033838787876001600160401b0316604051612111959493929190615152565b60405180910390a15050600c80546001600160401b03600160401b80830482166001019091160267ffffffffffffffff60401b19909116179055505050565b6013546040516001600160a01b039091169036600082376000803683855af43d806000843e818015612180578184f35b8184fd5b6000600160801b82106121c3576040805162461bcd60e51b8152602060048201526002602482015261189b60f11b604482015290519081900360640190fd5b50805b919050565b60408051608081018252600080825261ffff861660208301526001600160801b038516928201929092526001600160a01b03831660608201529061220e826129f1565b905061221b600182611fe8565b8461ffff167f8f5f51448394699ad6a3b80cdadf4ec68c5d724c8c3fea09bea55b3c2d0e2dd08560405161224f9190615860565b60405180910390a25050505050565b600080516020615a4e833981519152805460019091558015610829576040805162461bcd60e51b815260206004820152600260248201526118a160f11b604482015290519081900360640190fd5b6000816040516020016122bf919061580d565b604051602081830303815290604052805190602001209050919050565b6122e4614397565b825160010163ffffffff166122ff60a0840160808501614cd8565b63ffffffff16146123225760405162461bcd60e51b815260040161065a90615733565b82606001518260400135101561234a5760405162461bcd60e51b815260040161065a906153ac565b6000604083013561235e426201518061243e565b1115905060006123704261038461246b565b8460400135111590508180156123835750805b61239f5760405162461bcd60e51b815260040161065a90615675565b505060008060006123af85612a18565b92509250925060006123c2878784612e80565b90506040518060c001604052808760800160208101906123e29190614cd8565b63ffffffff1681526001600160401b039094166020850152604080850195909552938601356060840152943560808301525060a0019290925250919050565b60a01b61ffff60a01b166001600160a01b03919091161760501b90565b60006124648383604051806040016040528060018152602001603b60f91b8152506130e4565b9392505050565b600082820183811015612464576040805162461bcd60e51b81526020600482015260026024820152610c4d60f21b604482015290519081900360640190fd5b6000805460ff19168155600155621baf8060148190556040517ff2b18f8abbd8a0d0c1fb8245146eedf5304887b12f6395b548ca238e054a1483916124ee916152d5565b60405180910390a1600060158190555b600f811015612525576000818152601660205260409020805460ff191690556001016124fe565b506000601755565b600d600061253e6020850185614cd8565b63ffffffff16815260208101919091526040016000205461256761118d36859003850185614c2e565b146125845760405162461bcd60e51b815260040161065a906154bb565b600654600160401b900463ffffffff1681016001016125a66020840184614cd8565b63ffffffff16146125c95760405162461bcd60e51b815260040161065a906157d6565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060006125f960c08501856158ee565b9050905060005b818110156129915736600061261860c08801886158ee565b8481811061262257fe5b90506020028101906126349190615934565b9150915060008282600081811061264757fe5b919091013560f81c9050600b81111561265c57fe5b9050600381600b81111561266c57fe5b14156127065760006126b384848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061317b92505050565b905061ffff63ffffffff16816000015163ffffffff1611156126e75760405162461bcd60e51b815260040161065a906155ec565b61270081600001518260400151836020015160006131d6565b50612941565b600881600b81111561271457fe5b14156127a857600061275b84848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061323d92505050565b905061ffff63ffffffff16816000015163ffffffff16111561278f5760405162461bcd60e51b815260040161065a90615510565b61270081600001518260400151836020015160016131d6565b600681600b8111156127b657fe5b14156128c95760006127fd84848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061325192505050565b905061ffff63ffffffff16816040015163ffffffff16116128365761283181604001518260200151836060015160026131d6565b612700565b80606001516001600160801b0316600114156127005760006040518060c00160405280836080015163ffffffff1681526020018360a001516001600160a01b031681526020018360c0015163ffffffff1681526020018360e00151815260200183602001516001600160a01b03168152602001836040015163ffffffff1681525090506128c281613339565b5050612941565b600a81600b8111156128d757fe5b141561292957600061291e84848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061341f92505050565b905061270081613339565b60405162461bcd60e51b815260040161065a906154da565b6129818684848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506134b692505050565b9550505050806001019050612600565b50604084013582146129b55760405162461bcd60e51b815260040161065a9061576a565b50505050565b6000816001600160801b0316836001600160801b0316106129dc5781612464565b5090919050565b805160209091012060601b90565b6060600160208084015160408086015160608701519151611fd2959460009493910161501f565b600080606081612a2b6020860186615934565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250600c5485517fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4709a509198509495506001600160401b03808616600160801b909604169490940193600a93509150612aaf9050565b0615612acd5760405162461bcd60e51b815260040161065a90615376565b8151600a90046001600160401b0381118015612ae857600080fd5b506040519080825280601f01601f191660200182016040528015612b13576020820181803683370190505b5092506000612b2560608801886158ee565b9050905060005b81811015612e755736612b4260608a018a6158ee565b83818110612b4c57fe5b9050602002810190612b5e91906159a2565b90506000612b726040830160208401614cd8565b63ffffffff16905085518110612b9a5760405162461bcd60e51b815260040161065a90615418565b600a810615612bbb5760405162461bcd60e51b815260040161065a906153c7565b6000600a82049050878181518110612bcf57fe5b01602001516001600160f81b03191615612bfb5760405162461bcd60e51b815260040161065a9061535b565b600160f81b888281518110612c0c57fe5b60200101906001600160f81b031916908160001a9053506000878381518110612c3157fe5b016020015160f81c600b811115612c4457fe5b9050600181600b811115612c5457fe5b1415612c90576000612c688985603c6134c5565b90506000612c7582613581565b9050612c83818d8b0161360a565b8b6001019b505050612e66565b600781600b811115612c9e57fe5b1415612d90576000612cb28985603c6134c5565b90506000612cbf8261369a565b9050612ccb8680615934565b159050612d0c576000612ce7612ce18880615934565b8461370a565b905080612d065760405162461bcd60e51b815260040161065a906154f5565b50612d89565b60008160200151604051602001612d239190614e09565b60408051601f198184030181529181528151602092830120848201516001600160a01b03166000908152600a8452828120606087015163ffffffff16825290935291205414905080612d875760405162461bcd60e51b815260040161065a9061544f565b505b5050612e66565b6060600382600b811115612da057fe5b1415612db957612db28985603c6134c5565b9050612e58565b600882600b811115612dc757fe5b1415612dd957612db28985603c6134c5565b600a82600b811115612de757fe5b1415612df957612db2898560646134c5565b600682600b811115612e0757fe5b1415612e4057612e198985606e6134c5565b90506000612e2682613251565b9050612e34818d8b016137ec565b8b6001019b5050612e58565b60405162461bcd60e51b815260040161065a90615785565b612e628c826134b6565b9b50505b50505050806001019050612b2c565b505050509193909250565b6000806002612e9560a0860160808701614cd8565b63ffffffff16612eab60c0870160a08801614cd8565b63ffffffff16604051602001612ec2929190614e36565b60408051601f1981840301815290829052612edc91614e6a565b602060405180830381855afa158015612ef9573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190612f1c91906149ec565b90506002818660800151604051602001612f37929190614e36565b60408051601f1981840301815290829052612f5191614e6a565b602060405180830381855afa158015612f6e573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190612f9191906149ec565b90506002818560000135604051602001612fac929190614e36565b60408051601f1981840301815290829052612fc691614e6a565b602060405180830381855afa158015612fe3573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061300691906149ec565b90506002818560400135604051602001613021929190614e36565b60408051601f198184030181529082905261303b91614e6a565b602060405180830381855afa158015613058573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061307b91906149ec565b9050600061308c6020860186615934565b8560405160200161309f93929190614e44565b60405160208183030381529060405290506040518151838352602082602083018560025afa8184528080156130d3576130d5565bfe5b50509051979650505050505050565b600081848411156131735760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613138578181015183820152602001613120565b50505050905090810190601f1680156131655780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6131836143cc565b600561318f838261387c565b63ffffffff16835290506131a38382613895565b6001600160801b0316602084015260020190506131c083826138a5565b6001600160a01b03166040840152509092915050565b60006131e28486612421565b90506131ee81846138b5565b836001600160a01b03168561ffff167f08262c50127efaa884a8609d16fe2ed98c5fd8e4f1c393f2d7d8f9f52f602ff6858560405161322e929190615874565b60405180910390a35050505050565b6132456143cc565b600961318f838261387c565b6132596143ec565b6001613265838261387c565b63ffffffff168352905061327983826138a5565b6001600160a01b031660208401529050613293838261387c565b63ffffffff16604084015290506132aa8382613895565b6001600160801b0316606084015290506132c4838261387c565b63ffffffff16608084015290506132db83826138a5565b6001600160a01b031660a084015290506132f5838261387c565b63ffffffff1660c0840152905061330c8382613953565b60e08401529050606981146133335760405162461bcd60e51b815260040161065a906156fd565b50919050565b60a08101805163ffffffff908116600090815260126020908152604080832086518154938801518389015163ffffffff1990951691871691909117640100000000600160c01b0319166401000000006001600160a01b03928316021763ffffffff60c01b1916600160c01b948716949094029390931781556060870151600182015560808701516002909101805496516001600160a01b0319909716919093161763ffffffff60a01b1916600160a01b9590941694850293909317905590517f1d19de6753fc463923c3d90b6fb45aca536732ed7c5ca377d4b3f63dfbe4d8199190a250565b613427614397565b6005613433838261387c565b63ffffffff168352905061344783826138a5565b6001600160a01b031660208401529050613461838261387c565b63ffffffff16604084015290506134788382613953565b6060840152905061348983826138a5565b6001600160a01b0316608084015290506134a3838261387c565b63ffffffff1660a0840152509092915050565b80519181526020909101902090565b606081830184511015613503576040805162461bcd60e51b81526020600482015260016024820152602d60f91b604482015290519081900360640190fd5b6000826001600160401b038111801561351b57600080fd5b506040519080825280601f01601f191660200182016040528015613546576020820181803683370190505b509050821561357957602081018381016020860187015b8183101561357557805183526020928301920161355d565b5050505b949350505050565b613589614430565b6001613595838261387c565b63ffffffff16835290506135a9838261387c565b63ffffffff16602084015290506135c08382613895565b6001600160801b0316604084015290506135da83826138a5565b6001600160a01b031660608401529050602d81146133335760405162461bcd60e51b815260040161065a90615564565b6001600160401b0381166000908152600f6020526040902054600160e01b900460ff16600181600b81111561363b57fe5b146136585760405162461bcd60e51b815260040161065a906153fd565b6001600160401b0382166000908152600f602052604090205460601b61367e8482613963565b6129b55760405162461bcd60e51b815260040161065a90615609565b6136a2614430565b60016136ae838261387c565b63ffffffff16835290506136c28382613993565b6001600160601b031916602084015290506136dd83826138a5565b6001600160a01b0316604084015290506136f7838261387c565b63ffffffff166060840152509092915050565b6000808484600081811061371a57fe5b919091013560f81c9050600481111561372f57fe5b9050600081600481111561373f57fe5b1415613758576137508585856139a3565b915050612464565b600181600481111561376657fe5b141561377757613750858585613a59565b600281600481111561378557fe5b141561379657613750858585613bdc565b60038160048111156137a457fe5b14156137b557613750858585613c8c565b60048160048111156137c357fe5b14156137d457613750858585613d8a565b60405162461bcd60e51b815260040161065a90615391565b6001600160401b0381166000908152600f6020526040902054600160e01b900460ff16600681600b81111561381d57fe5b1461383a5760405162461bcd60e51b815260040161065a90615624565b6001600160401b0382166000908152600f602052604090205460601b6138608482613f31565b6129b55760405162461bcd60e51b815260040161065a9061563f565b60048101600061388c8484613f4a565b90509250929050565b60108101600061388c8484613f98565b60148101600061388c8484613fdb565b6001600160501b03198216600090815260046020526040908190205481518083019092526001600160801b031690806138ee838561401e565b6001600160801b03908116825260ff60209283018190526001600160501b031990961660009081526004835260409020835181549490930151909616600160801b0260ff60801b19929091166001600160801b03199093169290921716179092555050565b60208101600061388c8484614069565b60006001600160601b0319821661398161397c856129f1565b6129e3565b6001600160601b031916149392505050565b60148101600061388c84846140ac565b6000806139eb85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250604191506140f49050565b91505060008360200151846060015185600001516000801b604051602001613a169493929190614fbd565b6040516020818303038152906040528051906020012090506000613a3a838361410f565b60408601516001600160a01b0391821691161493505050509392505050565b600080600080600060019050613aa688888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508592506138a5915050565b604080516020601f8c018190048102820181019092528a8152919650919250613aeb918a908a9081908401838280828437600092019190915250859250613953915050565b604080516020601f8c018190048102820181019092528a8152919550919250613b30918a908a9081908401838280828437600092019190915250859250613953915050565b602080890151604051929550929350600092613b4e92879201614e1e565b60408051601f198184030181529082905280516020918201209250600091613b86916001600160f81b03199189918691899101614dd5565b6040516020818303038152906040528051906020012060001c905087604001516001600160a01b0316816001600160a01b0316148015613bce5750606088015163ffffffff16155b9a9950505050505050505050565b600080613c2485858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250604191506140f49050565b9150506000613c558460200151604051602001613c419190614e09565b60405160208183030381529060405261421b565b613c6a613c6586606001516142dc565b61421b565b613c7a613c6587600001516142dc565b604051602001613a1693929190614e86565b6000806000613cd686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250604191506140f49050565b915091506000613d1d87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250879250613953915050565b915050600085602001518660600151876000015184604051602001613d459493929190614fbd565b6040516020818303038152906040528051906020012090506000613d69848361410f565b60408801516001600160a01b03918216911614955050505050509392505050565b600080613dd285858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250604191506140f49050565b60408051808201825260068152655a6b53796e6360d01b602091820152815180830190925260038252620312e360ec1b9101529150600090507fc2f8787176b8ac6bf7215b4adcc1e069bf4ab82d9ab1df05a57a91d425935b6e7f2e760812e6696b561a918e71ad2845639638959ed846b188488dd0d8c0b953ef7fe6bbd6277e1bf288eed5e8d1780f9a50b239e86b153736bceebccf4ea79d90b3613e766142f5565b604051602001613e89949392919061530c565b60408051601f198184030181529082905280516020918201208682015160608801518851929550600094613ee0947f8012078cc90c4c82e493f1a538159fd8621f39392101b34fba2ecd141432580b9491016152de565b60405160208183030381529060405280519060200120905060008282604051602001613f0d929190614fa2565b6040516020818303038152906040528051906020012090506000613d69858361410f565b60006001600160601b0319821661398161397c85611fa7565b6000808260040190508084511015613f8d576040805162461bcd60e51b81526020600482015260016024820152602b60f91b604482015290519081900360640190fd5b929092015192915050565b6000808260100190508084511015613f8d576040805162461bcd60e51b81526020600482015260016024820152605760f81b604482015290519081900360640190fd5b6000808260140190508084511015613f8d576040805162461bcd60e51b81526020600482015260016024820152602960f91b604482015290519081900360640190fd5b60008282016001600160801b038085169082161015612464576040805162461bcd60e51b8152602060048201526002602482015261189960f11b604482015290519081900360640190fd5b6000808260200190508084511015613f8d576040805162461bcd60e51b81526020600482015260016024820152605960f81b604482015290519081900360640190fd5b600081601401835110156140eb576040805162461bcd60e51b81526020600482015260016024820152605360f81b604482015290519081900360640190fd5b50016020015190565b600060606141038585856134c5565b93909201949293505050565b6000825160411461414b576040805162461bcd60e51b81526020600482015260016024820152600560fc1b604482015290519081900360640190fd5b60008060006020860151925060408601519150606086015160001a9050600060018683868660405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156141c4573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614211576040805162461bcd60e51b81526020600482015260026024820152611c0d60f21b604482015290519081900360640190fd5b9695505050505050565b6060600082516002026001600160401b038111801561423957600080fd5b506040519080825280601f01601f191660200182016040528015614264576020820181803683370190505b5090506020830183518101602083015b818310156142d257825160f81c6f6665646362613938373635343332313060088260041c021c60f81b82526f66656463626139383736353433323130600882600f16021c60f81b600183015250600183019250600281019050614274565b5091949350505050565b60606142ef8263ffffffff1660046142f9565b92915050565b4690565b606060208260ff161115614338576040805162461bcd60e51b81526020600482015260016024820152605160f81b604482015290519081900360640190fd5b8160ff166001600160401b038111801561435157600080fd5b506040519080825280601f01601f19166020018201604052801561437c576020820181803683370190505b5060ff6008602094850302169390931b918301919091525090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b604080516060810182526000808252602082018190529181019190915290565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b60408051608081018252600080825260208201819052918101829052606081019190915290565b80356121c681615a23565b60008083601f840112614473578182fd5b5081356001600160401b03811115614489578182fd5b60208301915083602080830285010111156144a357600080fd5b9250929050565b60008083601f8401126144bb578182fd5b5081356001600160401b038111156144d1578182fd5b60208301915083602060c0830285010111156144a357600080fd5b600082601f8301126144fc578081fd5b6040516102008082018281106001600160401b038211171561451a57fe5b604052818482810187101561452d578485fd5b8492505b601083101561455157803582526001929092019160209182019101614531565b509195945050505050565b600082601f83011261456c578081fd5b8135602061458161457c836159da565b6159b7565b828152818101908583018385028701840188101561459d578586fd5b855b858110156145bb5781358452928401929084019060010161459f565b5090979650505050505050565b600082601f8301126145d8578081fd5b813560206145e861457c836159da565b8281528181019085830183850287018401881015614604578586fd5b855b858110156145bb57813560ff8116811461461e578788fd5b84529284019290840190600101614606565b60008083601f840112614641578182fd5b5081356001600160401b03811115614657578182fd5b6020830191508360208285010111156144a357600080fd5b600060c08284031215614680578081fd5b60405160c081018181106001600160401b038211171561469c57fe5b6040529050806146ab836146ed565b81526146b960208401614701565b602082015260408301356040820152606083013560608201526080830135608082015260a083013560a08201525092915050565b803563ffffffff811681146121c657600080fd5b80356001600160401b03811681146121c657600080fd5b600060208284031215614729578081fd5b813561246481615a23565b60008060008060808587031215614749578283fd5b843561475481615a23565b9350602085013561476481615a23565b9250604085013561477481615a23565b9396929550929360600135925050565b600080600060608486031215614798578081fd5b83356147a381615a23565b925060208401356147b381615a23565b915060408401356147c381615a38565b809150509250925092565b600080604083850312156147e0578182fd5b82356147eb81615a23565b915060208301356147fb81615a23565b809150509250929050565b60008060408385031215614818578182fd5b823561482381615a23565b915061388c602084016146ed565b60008060208385031215614843578182fd5b82356001600160401b03811115614858578283fd5b61486485828601614462565b90969095509350505050565b60008060208385031215614882578182fd5b82356001600160401b03811115614897578283fd5b614864858286016144aa565b6000806000604084860312156148b7578081fd5b83356001600160401b03808211156148cd578283fd5b6148d9878388016144aa565b909550935060208601359150808211156148f1578283fd5b908501906102808288031215614905578283fd5b61490f60a06159b7565b82358281111561491d578485fd5b6149298982860161455c565b82525060208301358281111561493d578485fd5b6149498982860161455c565b602083015250604083013582811115614960578485fd5b61496c8982860161455c565b604083015250606083013582811115614983578485fd5b61498f898286016145c8565b6060830152506149a288608085016144ec565b60808201528093505050509250925092565b6000602082840312156149c5578081fd5b81518015158114612464578182fd5b6000602082840312156149e5578081fd5b5035919050565b6000602082840312156149fd578081fd5b5051919050565b60008060208385031215614a16578182fd5b82356001600160401b03811115614a2b578283fd5b61486485828601614630565b600080600060408486031215614a4b578081fd5b83356001600160401b03811115614a60578182fd5b614a6c86828701614630565b9094509250614a7f9050602085016146ed565b90509250925092565b60008060008060808587031215614a9d578182fd5b8435614aa881615a23565b93506020850135614ab881615a23565b92506040850135614ac881615a38565b91506060850135614ad881615a38565b939692955090935050565b600080600060608486031215614af7578081fd5b8335614b0281615a23565b925060208401356001600160681b0381168114614b1d578182fd5b915060408401356147c381615a23565b600060208284031215614b3e578081fd5b815161246481615a23565b60008060008060008060008060008060008b8d036101e0811215614b6b57898afd5b60c0811215614b7857898afd5b508b9a5060c08c0135614b8a81615a23565b9950614b9860e08d016146ed565b9850614ba76101008d016146ed565b97506101208c0135614bb881615a38565b9650614bc76101408d016146ed565b9550614bd66101608d01614457565b9450614be56101808d016146ed565b93506101a08c013592506101c08c01356001600160401b03811115614c08578283fd5b614c148e828f01614462565b915080935050809150509295989b509295989b9093969950565b600060c08284031215614c3f578081fd5b612464838361466f565b600080600060e08486031215614c5d578081fd5b614c67858561466f565b925060c08401356001600160401b03811115614c81578182fd5b614c8d86828701614462565b9497909650939450505050565b600060208284031215614cab578081fd5b815161246481615a38565b600060208284031215614cc7578081fd5b815161ffff81168114612464578182fd5b600060208284031215614ce9578081fd5b612464826146ed565b60008060408385031215614d04578182fd5b6147eb836146ed565b60008060408385031215614d1f578182fd5b614823836146ed565b600060208284031215614d39578081fd5b61246482614701565b600080600060408486031215614d56578081fd5b614d5f84614701565b925060208401356001600160401b03811115614c81578182fd5b60601b6001600160601b0319169052565b6000815180845260208085019450808401835b83811015614db957815187529582019590820190600101614d9d565b509495945050505050565b60e01b6001600160e01b0319169052565b6001600160f81b031994909416845260609290921b6001600160601b03191660018401526015830152603582015260550190565b6001600160601b031991909116815260140190565b9182526001600160601b031916602082015260340190565b918252602082015260400190565b6000838583378382018181528351614e608183602088016159f7565b0195945050505050565b60008251614e7c8184602087016159f7565b9190910192915050565b60007f19457468657265756d205369676e6564204d6573736167653a0a31353200000082527f5265676973746572207a6b53796e63207075626b65793a0a0a00000000000000601d8301528451614ee48160368501602089016159f7565b600560f91b6036918401918201819052680dcdedcc6ca744060f60bb1b60378301528551614f19816040850160208a016159f7565b60409201918201526d0c2c6c6deeadce840d2c8744060f60931b60418201528351614f4b81604f8401602088016159f7565b61050560f11b604f92909101918201527f4f6e6c79207369676e2074686973206d65737361676520666f7220612074727560518201526b7374656420636c69656e742160a01b6071820152607d0195945050505050565b61190160f01b81526002810192909252602282015260420190565b7f19457468657265756d205369676e6564204d6573736167653a0a36300000000081526001600160601b031994909416601c8501526001600160e01b031960e093841b811660308601529190921b166034830152603882015260580190565b90565b60f89590951b6001600160f81b03191685526001600160e01b0319938416600186015260e09290921b909216600584015260809190911b6001600160801b031916600983015260601b6001600160601b0319166019820152602d0190565b6001600160f81b031960f88b901b1681526001600160e01b031960e08a811b821660018401526001600160601b031960608b901b16600584015288811b821660198401526001600160801b0319608089901b16601d84015286901b16602d82015260006150ed6031830186614d79565b6150fa6045830185614dc4565b50604981019190915260690198975050505050505050565b6001600160a01b0391909116815260200190565b6001600160a01b0393841681529190921660208201526001600160681b03909116604082015260600190565b6001600160a01b03861681526001600160401b03851660208201526000600c851061517957fe5b84604083015260a0606083015283518060a084015261519f8160c08501602088016159f7565b608083019390935250601f91909101601f19160160c001949350505050565b6001600160a01b03968716815294909516602085015263ffffffff92831660408501529082166060840152608083015290911660a082015260c00190565b6001600160a01b039290921682526001600160801b0316602082015260400190565b600061028080835261523281840189614d8a565b90506020838203818501526152478289614d8a565b84810360408601528751808252828901935090820190845b8181101561527e57845160ff168352938301939183019160010161525f565b505084810360608601526152928188614d8a565b9350506080840191508460005b60108110156152bc5781518452928201929082019060010161529f565b505050509695505050505050565b901515815260200190565b90815260200190565b9384526001600160601b031992909216602084015263ffffffff908116604084015216606082015260800190565b93845260208401929092526040830152606082015260800190565b6001600160a01b0394851681529290931660208301526001600160801b039081166040830152909116606082015260800190565b6020808252600190820152604360f81b604082015260600190565b6020808252600190820152604160f81b604082015260600190565b6020808252600190820152604760f81b604082015260600190565b6020808252600190820152606760f81b604082015260600190565b6020808252600190820152602160f91b604082015260600190565b6020808252600190820152600760fc1b604082015260600190565b6020808252600190820152600960fb1b604082015260600190565b602080825260029082015261413160f01b604082015260600190565b6020808252600190820152607160f81b604082015260600190565b6020808252600190820152604560f81b604082015260600190565b6020808252600190820152603760f91b604082015260600190565b6020808252600190820152603760f81b604082015260600190565b6020808252600190820152606f60f81b604082015260600190565b602080825260059082015264065786531360dc1b604082015260600190565b6020808252600190820152601b60fa1b604082015260600190565b6020808252600190820152601160fa1b604082015260600190565b60208082526003908201526236b31960e91b604082015260600190565b6020808252600190820152600560fc1b604082015260600190565b602080825260029082015261633160f01b604082015260600190565b6020808252600190820152602760f91b604082015260600190565b6020808252600190820152604d60f81b604082015260600190565b6020808252600190820152601560fa1b604082015260600190565b6020808252600290820152616f3160f01b604082015260600190565b6020808252600190820152601360fa1b604082015260600190565b6020808252600390820152626d663160e81b604082015260600190565b6020808252600190820152604960f81b604082015260600190565b6020808252600190820152602560f91b604082015260600190565b6020808252600190820152604b60f81b604082015260600190565b6020808252600190820152603b60f91b604082015260600190565b6020808252600190820152600d60fb1b604082015260600190565b6020808252600190820152606560f81b604082015260600190565b6020808252600190820152603560f91b604082015260600190565b6020808252600190820152603160f91b604082015260600190565b60208082526002908201526106f760f41b604082015260600190565b6020808252600190820152604f60f81b604082015260600190565b6020808252600190820152603560f81b604082015260600190565b6020808252600190820152603360f91b604082015260600190565b602080825260029082015261663160f01b604082015260600190565b6020808252600190820152606d60f81b604082015260600190565b6020808252600190820152602360f91b604082015260600190565b6020808252600190820152606960f81b604082015260600190565b6020808252600190820152601960fa1b604082015260600190565b6020808252600190820152606b60f81b604082015260600190565b602080825260029082015261379960f11b604082015260600190565b600060c08201905063ffffffff83511682526001600160401b03602084015116602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b6001600160801b0391909116815260200190565b6001600160801b0383168152604081016003831061588e57fe5b8260208301529392505050565b61ffff91909116815260200190565b63ffffffff91909116815260200190565b63ffffffff9290921682526001600160a01b0316602082015260400190565b6001600160401b0391909116815260200190565b6000808335601e19843603018112615904578283fd5b8301803591506001600160401b0382111561591d578283fd5b60209081019250810236038213156144a357600080fd5b6000808335601e1984360301811261594a578283fd5b8301803591506001600160401b03821115615963578283fd5b6020019150368190038213156144a357600080fd5b6000823560be19833603018112614e7c578182fd5b6000823560de19833603018112614e7c578182fd5b60008235603e19833603018112614e7c578182fd5b6040518181016001600160401b03811182821017156159d257fe5b604052919050565b60006001600160401b038211156159ed57fe5b5060209081020190565b60005b83811015615a125781810151838201526020016159fa565b838111156129b55750506000910152565b6001600160a01b038116811461082957600080fd5b6001600160801b038116811461082957600080fdfe8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4a2646970667358221220aa1e173e9b0205e9c8c2d0c2712fc68b94e648b3fdbe9d7f916646ee2221e80664736f6c63430007060033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | Ether (ETH) | 100.00% | $3,404.65 | 1.4723 | $5,012.58 |
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.