Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
21104293 | 72 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
LibProposing
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "src/shared/common/LibAddress.sol"; import "src/shared/common/LibNetwork.sol"; import "./LibBonds.sol"; import "./LibData.sol"; import "./LibUtils.sol"; import "./LibVerifying.sol"; /// @title LibProposing /// @notice A library for handling block proposals in the Taiko protocol. /// @custom:security-contact [email protected] library LibProposing { using LibAddress for address; uint256 internal constant SECONDS_PER_BLOCK = 12; struct Local { TaikoData.SlotB b; TaikoData.BlockParamsV2 params; ITierProvider tierProvider; bytes32 parentMetaHash; bool postFork; bool allowCustomProposer; bytes32 extraData; } /// @notice Emitted when a block is proposed. /// @param blockId The ID of the proposed block. /// @param assignedProver The address of the assigned prover. /// @param livenessBond The liveness bond of the proposed block. /// @param meta The metadata of the proposed block. /// @param depositsProcessed The EthDeposit array about processed deposits in this proposed /// block. event BlockProposed( uint256 indexed blockId, address indexed assignedProver, uint96 livenessBond, TaikoData.BlockMetadata meta, TaikoData.EthDeposit[] depositsProcessed ); /// @notice Emitted when a block is proposed. /// @param blockId The ID of the proposed block. /// @param meta The metadata of the proposed block. event BlockProposedV2(uint256 indexed blockId, TaikoData.BlockMetadataV2 meta); /// @notice Emitted when a block's txList is in the calldata. /// @param blockId The ID of the proposed block. /// @param txList The txList. event CalldataTxList(uint256 indexed blockId, bytes txList); error L1_BLOB_NOT_AVAILABLE(); error L1_BLOB_NOT_FOUND(); error L1_INVALID_ANCHOR_BLOCK(); error L1_INVALID_CUSTOM_PROPOSER(); error L1_INVALID_PARAMS(); error L1_INVALID_PROPOSER(); error L1_INVALID_TIMESTAMP(); error L1_LIVENESS_BOND_NOT_RECEIVED(); error L1_TOO_MANY_BLOCKS(); error L1_UNEXPECTED_PARENT(); /// @notice Proposes multiple Taiko L2 blocks. /// @param _state The current state of the Taiko protocol. /// @param _config The configuration parameters for the Taiko protocol. /// @param _resolver The address resolver interface. /// @param _paramsArr An array of encoded data bytes containing the block parameters. /// @param _txListArr An array of transaction list bytes (if not blob). /// @return metaV1s_ An array of metadata objects for the proposed L2 blocks (version 1). /// @return metas_ An array of metadata objects for the proposed L2 blocks (version 2). function proposeBlocks( TaikoData.State storage _state, TaikoData.Config memory _config, IAddressResolver _resolver, bytes[] calldata _paramsArr, bytes[] calldata _txListArr ) public returns ( TaikoData.BlockMetadata[] memory metaV1s_, TaikoData.BlockMetadataV2[] memory metas_ ) { if (_paramsArr.length == 0 || _paramsArr.length != _txListArr.length) { revert L1_INVALID_PARAMS(); } metaV1s_ = new TaikoData.BlockMetadata[](_paramsArr.length); metas_ = new TaikoData.BlockMetadataV2[](_paramsArr.length); for (uint256 i; i < _paramsArr.length; ++i) { (metaV1s_[i], metas_[i]) = _proposeBlock(_state, _config, _resolver, _paramsArr[i], _txListArr[i]); } if (!_state.slotB.provingPaused) { for (uint256 i; i < _paramsArr.length; ++i) { if (LibUtils.shouldVerifyBlocks(_config, metas_[i].id, false)) { LibVerifying.verifyBlocks(_state, _config, _resolver, _config.maxBlocksToVerify); } } } } /// @notice Proposes a single Taiko L2 block. /// @param _state The current state of the Taiko protocol. /// @param _config The configuration parameters for the Taiko protocol. /// @param _resolver The address resolver interface. /// @param _params Encoded data bytes containing the block parameters. /// @param _txList Transaction list bytes (if not blob). /// @return metaV1_ The metadata of the proposed block (version 1). /// @return meta_ The metadata of the proposed block (version 2). function proposeBlock( TaikoData.State storage _state, TaikoData.Config memory _config, IAddressResolver _resolver, bytes calldata _params, bytes calldata _txList ) public returns (TaikoData.BlockMetadata memory metaV1_, TaikoData.BlockMetadataV2 memory meta_) { (metaV1_, meta_) = _proposeBlock(_state, _config, _resolver, _params, _txList); if (!_state.slotB.provingPaused) { if (LibUtils.shouldVerifyBlocks(_config, meta_.id, false)) { LibVerifying.verifyBlocks(_state, _config, _resolver, _config.maxBlocksToVerify); } } } function _proposeBlock( TaikoData.State storage _state, TaikoData.Config memory _config, IAddressResolver _resolver, bytes calldata _params, bytes calldata _txList ) private returns (TaikoData.BlockMetadata memory metaV1_, TaikoData.BlockMetadataV2 memory meta_) { // Checks proposer access. Local memory local; local.b = _state.slotB; local.postFork = local.b.numBlocks >= _config.ontakeForkHeight; // It's essential to ensure that the ring buffer for proposed blocks // still has space for at least one more block. if (local.b.numBlocks >= local.b.lastVerifiedBlockId + _config.blockMaxProposals + 1) { revert L1_TOO_MANY_BLOCKS(); } address preconfRegistry = _resolver.resolve(LibStrings.B_PRECONF_REGISTRY, true); if (preconfRegistry != address(0)) { if (preconfRegistry != msg.sender) revert L1_INVALID_PROPOSER(); local.allowCustomProposer = true; } if (local.postFork) { if (_params.length != 0) { local.params = abi.decode(_params, (TaikoData.BlockParamsV2)); } } else { TaikoData.BlockParams memory paramsV1 = abi.decode(_params, (TaikoData.BlockParams)); local.params = LibData.blockParamsV1ToV2(paramsV1); local.extraData = paramsV1.extraData; } if (local.params.proposer == address(0)) { local.params.proposer = msg.sender; } else { if (local.params.proposer != msg.sender && !local.allowCustomProposer) { revert L1_INVALID_CUSTOM_PROPOSER(); } } if (local.params.coinbase == address(0)) { local.params.coinbase = local.params.proposer; } if (local.params.anchorBlockId == 0) { unchecked { local.params.anchorBlockId = uint64(block.number - 1); } } if (local.params.timestamp == 0) { local.params.timestamp = uint64(block.timestamp); } // Verify params against the parent block. TaikoData.BlockV2 storage parentBlk; unchecked { parentBlk = _state.blocks[(local.b.numBlocks - 1) % _config.blockRingBufferSize]; } if (local.postFork) { // Verify the passed in L1 state block number. // We only allow the L1 block to be 2 epochs old. // The other constraint is that the L1 block number needs to be larger than or equal // the one in the previous L2 block. if ( local.params.anchorBlockId + _config.maxAnchorHeightOffset < block.number // || local.params.anchorBlockId >= block.number || local.params.anchorBlockId < parentBlk.proposedIn ) { revert L1_INVALID_ANCHOR_BLOCK(); } // Verify the passed in timestamp. // We only allow the timestamp to be 2 epochs old. // The other constraint is that the timestamp needs to be larger than or equal the // one in the previous L2 block. if ( local.params.timestamp + _config.maxAnchorHeightOffset * SECONDS_PER_BLOCK < block.timestamp || local.params.timestamp > block.timestamp || local.params.timestamp < parentBlk.proposedAt ) { revert L1_INVALID_TIMESTAMP(); } } // Check if parent block has the right meta hash. This is to allow the proposer to make // sure the block builds on the expected latest chain state. if (local.params.parentMetaHash == 0) { local.params.parentMetaHash = parentBlk.metaHash; } else if (local.params.parentMetaHash != parentBlk.metaHash) { revert L1_UNEXPECTED_PARENT(); } // Initialize metadata to compute a metaHash, which forms a part of // the block data to be stored on-chain for future integrity checks. // If we choose to persist all data fields in the metadata, it will // require additional storage slots. meta_ = TaikoData.BlockMetadataV2({ anchorBlockHash: blockhash(local.params.anchorBlockId), difficulty: keccak256(abi.encode("TAIKO_DIFFICULTY", local.b.numBlocks)), blobHash: 0, // to be initialized below // To make sure each L2 block can be exexucated deterministiclly by the client // without referering to its metadata on Ethereum, we need to encode // config.sharingPctg into the extraData. extraData: local.postFork ? _encodeBaseFeeConfig(_config.baseFeeConfig) : local.extraData, coinbase: local.params.coinbase, id: local.b.numBlocks, gasLimit: _config.blockMaxGasLimit, timestamp: local.params.timestamp, anchorBlockId: local.params.anchorBlockId, minTier: 0, // to be initialized below blobUsed: _txList.length == 0, parentMetaHash: local.params.parentMetaHash, proposer: local.params.proposer, livenessBond: _config.livenessBond, proposedAt: uint64(block.timestamp), proposedIn: uint64(block.number), blobTxListOffset: local.params.blobTxListOffset, blobTxListLength: local.params.blobTxListLength, blobIndex: local.params.blobIndex, baseFeeConfig: _config.baseFeeConfig }); // Update certain meta fields if (meta_.blobUsed) { if (!LibNetwork.isDencunSupported(block.chainid)) revert L1_BLOB_NOT_AVAILABLE(); // Always use the first blob in this transaction. If the // proposeBlock functions are called more than once in the same // L1 transaction, these multiple L2 blocks will share the same // blob. meta_.blobHash = blobhash(local.params.blobIndex); if (meta_.blobHash == 0) revert L1_BLOB_NOT_FOUND(); } else { meta_.blobHash = keccak256(_txList); emit CalldataTxList(meta_.id, _txList); } local.tierProvider = ITierProvider( ITierRouter(_resolver.resolve(LibStrings.B_TIER_ROUTER, false)).getProvider( local.b.numBlocks ) ); // Use the difficulty as a random number meta_.minTier = local.tierProvider.getMinTier(meta_.proposer, uint256(meta_.difficulty)); if (!local.postFork) { metaV1_ = LibData.blockMetadataV2toV1(meta_); } // Create the block that will be stored onchain TaikoData.BlockV2 memory blk = TaikoData.BlockV2({ metaHash: local.postFork ? keccak256(abi.encode(meta_)) : keccak256(abi.encode(metaV1_)), assignedProver: address(0), livenessBond: local.postFork ? 0 : meta_.livenessBond, blockId: local.b.numBlocks, proposedAt: local.postFork ? local.params.timestamp : uint64(block.timestamp), proposedIn: local.postFork ? local.params.anchorBlockId : uint64(block.number), // For a new block, the next transition ID is always 1, not 0. nextTransitionId: 1, livenessBondReturned: false, // For unverified block, its verifiedTransitionId is always 0. verifiedTransitionId: 0 }); // Store the block in the ring buffer _state.blocks[local.b.numBlocks % _config.blockRingBufferSize] = blk; // Increment the counter (cursor) by 1. unchecked { ++_state.slotB.numBlocks; } LibBonds.debitBond(_state, _resolver, local.params.proposer, _config.livenessBond); // Bribe the block builder. Unlike 1559-tips, this tip is only made // if this transaction succeeds. if (msg.value != 0 && block.coinbase != address(0)) { address(block.coinbase).sendEtherAndVerify(msg.value); } if (local.postFork) { emit BlockProposedV2(meta_.id, meta_); } else { emit BlockProposed({ blockId: metaV1_.id, assignedProver: local.params.proposer, livenessBond: _config.livenessBond, meta: metaV1_, depositsProcessed: new TaikoData.EthDeposit[](0) }); } } function _encodeBaseFeeConfig(LibSharedData.BaseFeeConfig memory _baseFeeConfig) private pure returns (bytes32) { return bytes32(uint256(_baseFeeConfig.sharingPctg)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /// @title LibAddress /// @dev Provides utilities for address-related operations. /// @custom:security-contact [email protected] library LibAddress { error ETH_TRANSFER_FAILED(); /// @dev Sends Ether to the specified address. This method will not revert even if sending ether /// fails. /// This function is inspired by /// https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol /// @param _to The recipient address. /// @param _amount The amount of Ether to send in wei. /// @param _gasLimit The max amount gas to pay for this transaction. /// @return success_ true if the call is successful, false otherwise. function sendEther( address _to, uint256 _amount, uint256 _gasLimit, bytes memory _calldata ) internal returns (bool success_) { // Check for zero-address transactions if (_to == address(0)) revert ETH_TRANSFER_FAILED(); // dispatch message to recipient // by assembly calling "handle" function // we call via assembly to avoid memcopying a very large returndata // returned by a malicious contract assembly { success_ := call( _gasLimit, // gas _to, // recipient _amount, // ether value add(_calldata, 0x20), // inloc mload(_calldata), // inlen 0, // outloc 0 // outlen ) } } /// @dev Sends Ether to the specified address. This method will revert if sending ether fails. /// @param _to The recipient address. /// @param _amount The amount of Ether to send in wei. /// @param _gasLimit The max amount gas to pay for this transaction. function sendEtherAndVerify(address _to, uint256 _amount, uint256 _gasLimit) internal { if (_amount == 0) return; if (!sendEther(_to, _amount, _gasLimit, "")) { revert ETH_TRANSFER_FAILED(); } } /// @dev Sends Ether to the specified address. This method will revert if sending ether fails. /// @param _to The recipient address. /// @param _amount The amount of Ether to send in wei. function sendEtherAndVerify(address _to, uint256 _amount) internal { sendEtherAndVerify(_to, _amount, gasleft()); } function supportsInterface( address _addr, bytes4 _interfaceId ) internal view returns (bool result_) { (bool success, bytes memory data) = _addr.staticcall(abi.encodeCall(IERC165.supportsInterface, (_interfaceId))); if (success && data.length == 32) { result_ = abi.decode(data, (bool)); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; /// @title LibNetwork library LibNetwork { uint256 internal constant ETHEREUM_MAINNET = 1; uint256 internal constant ETHEREUM_ROPSTEN = 2; uint256 internal constant ETHEREUM_RINKEBY = 4; uint256 internal constant ETHEREUM_GOERLI = 5; uint256 internal constant ETHEREUM_KOVAN = 42; uint256 internal constant ETHEREUM_HOLESKY = 17_000; uint256 internal constant ETHEREUM_SEPOLIA = 11_155_111; uint64 internal constant TAIKO_MAINNET = 167_000; uint64 internal constant TAIKO_HEKLA = 167_009; /// @dev Checks if the chain ID represents an Ethereum testnet. /// @param _chainId The chain ID. /// @return true if the chain ID represents an Ethereum testnet, false otherwise. function isEthereumTestnet(uint256 _chainId) internal pure returns (bool) { return _chainId == LibNetwork.ETHEREUM_ROPSTEN || _chainId == LibNetwork.ETHEREUM_RINKEBY || _chainId == LibNetwork.ETHEREUM_GOERLI || _chainId == LibNetwork.ETHEREUM_KOVAN || _chainId == LibNetwork.ETHEREUM_HOLESKY || _chainId == LibNetwork.ETHEREUM_SEPOLIA; } /// @dev Checks if the chain ID represents an Ethereum testnet or the Etheruem mainnet. /// @param _chainId The chain ID. /// @return true if the chain ID represents an Ethereum testnet or the Etheruem mainnet, false /// otherwise. function isEthereumMainnetOrTestnet(uint256 _chainId) internal pure returns (bool) { return _chainId == LibNetwork.ETHEREUM_MAINNET || isEthereumTestnet(_chainId); } /// @dev Checks if the chain ID represents the Taiko L2 mainnet. /// @param _chainId The chain ID. /// @return true if the chain ID represents the Taiko L2 mainnet. function isTaikoMainnet(uint256 _chainId) internal pure returns (bool) { return _chainId == TAIKO_MAINNET; } /// @dev Checks if the chain ID represents an internal Taiko devnet's base layer. /// @param _chainId The chain ID. /// @return true if the chain ID represents an internal Taiko devnet's base layer, false /// otherwise. function isTaikoDevnet(uint256 _chainId) internal pure returns (bool) { return _chainId >= 32_300 && _chainId <= 32_400; } /// @dev Checks if the chain supports Dencun hardfork. Note that this check doesn't need to be /// exhaustive. /// @param _chainId The chain ID. /// @return true if the chain supports Dencun hardfork, false otherwise. function isDencunSupported(uint256 _chainId) internal pure returns (bool) { return _chainId == LibNetwork.ETHEREUM_MAINNET || _chainId == LibNetwork.ETHEREUM_HOLESKY || _chainId == LibNetwork.ETHEREUM_SEPOLIA || isTaikoDevnet(_chainId); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "src/shared/common/IAddressResolver.sol"; import "src/shared/common/LibStrings.sol"; import "./TaikoData.sol"; /// @title LibBonds /// @notice A library that offers helper functions to handle bonds. /// @custom:security-contact [email protected] library LibBonds { /// @dev Emitted when token is credited back to a user's bond balance. event BondCredited(address indexed user, uint256 amount); /// @dev Emitted when token is debited from a user's bond balance. event BondDebited(address indexed user, uint256 amount); /// @dev Deposits Taiko token to be used as bonds. /// @param _state Current TaikoData.State. /// @param _resolver Address resolver interface. /// @param _amount The amount of token to deposit. function depositBond( TaikoData.State storage _state, IAddressResolver _resolver, uint256 _amount ) internal { _state.bondBalance[msg.sender] += _amount; _tko(_resolver).transferFrom(msg.sender, address(this), _amount); } /// @dev Withdraws Taiko token. /// @param _state Current TaikoData.State. /// @param _resolver Address resolver interface. /// @param _amount The amount of token to withdraw. function withdrawBond( TaikoData.State storage _state, IAddressResolver _resolver, uint256 _amount ) internal { _state.bondBalance[msg.sender] -= _amount; _tko(_resolver).transfer(msg.sender, _amount); } /// @dev Debits Taiko tokens as bonds. /// @param _state Current TaikoData.State. /// @param _resolver Address resolver interface. /// @param _user The user address to debit. /// @param _amount The amount of token to debit. function debitBond( TaikoData.State storage _state, IAddressResolver _resolver, address _user, uint256 _amount ) internal { uint256 balance = _state.bondBalance[_user]; if (balance >= _amount) { unchecked { _state.bondBalance[_user] = balance - _amount; } emit BondDebited(_user, _amount); } else { _tko(_resolver).transferFrom(_user, address(this), _amount); } } /// @dev Credits Taiko tokens to user's bond balance. /// @param _state Current TaikoData.State. /// @param _user The user address to credit. /// @param _amount The amount of token to credit. function creditBond(TaikoData.State storage _state, address _user, uint256 _amount) internal { _state.bondBalance[_user] += _amount; emit BondCredited(_user, _amount); } /// @dev Gets a user's current Taiko token bond balance. /// @param _state Current TaikoData.State. /// @param _user The user address to credit. /// @return The current token balance. function bondBalanceOf( TaikoData.State storage _state, address _user ) internal view returns (uint256) { return _state.bondBalance[_user]; } function _tko(IAddressResolver _resolver) private view returns (IERC20) { return IERC20(_resolver.resolve(LibStrings.B_TAIKO_TOKEN, false)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "../verifiers/IVerifier.sol"; import "./TaikoData.sol"; /// @title LibData /// @notice A library that offers helper functions. /// @custom:security-contact [email protected] library LibData { // = keccak256(abi.encode(new TaikoData.EthDeposit[](0))) bytes32 internal constant EMPTY_ETH_DEPOSIT_HASH = 0x569e75fc77c1a856f6daaf9e69d8a9566ca34aa47f9133711ce065a571af0cfd; function blockParamsV1ToV2(TaikoData.BlockParams memory _v1) internal pure returns (TaikoData.BlockParamsV2 memory) { return TaikoData.BlockParamsV2({ proposer: address(0), coinbase: _v1.coinbase, parentMetaHash: _v1.parentMetaHash, anchorBlockId: 0, timestamp: 0, blobTxListOffset: 0, blobTxListLength: 0, blobIndex: 0 }); } function blockMetadataV2toV1(TaikoData.BlockMetadataV2 memory _v2) internal pure returns (TaikoData.BlockMetadata memory) { return TaikoData.BlockMetadata({ l1Hash: _v2.anchorBlockHash, difficulty: _v2.difficulty, blobHash: _v2.blobHash, extraData: _v2.extraData, depositsHash: EMPTY_ETH_DEPOSIT_HASH, coinbase: _v2.coinbase, id: _v2.id, gasLimit: _v2.gasLimit, timestamp: _v2.timestamp, l1Height: _v2.anchorBlockId, minTier: _v2.minTier, blobUsed: _v2.blobUsed, parentMetaHash: _v2.parentMetaHash, sender: _v2.proposer }); } function blockMetadataV1toV2(TaikoData.BlockMetadata memory _v1) internal pure returns (TaikoData.BlockMetadataV2 memory) { return TaikoData.BlockMetadataV2({ anchorBlockHash: _v1.l1Hash, difficulty: _v1.difficulty, blobHash: _v1.blobHash, extraData: _v1.extraData, coinbase: _v1.coinbase, id: _v1.id, gasLimit: _v1.gasLimit, timestamp: _v1.timestamp, anchorBlockId: _v1.l1Height, minTier: _v1.minTier, blobUsed: _v1.blobUsed, parentMetaHash: _v1.parentMetaHash, proposer: _v1.sender, livenessBond: 0, proposedAt: 0, proposedIn: 0, blobTxListOffset: 0, blobTxListLength: 0, blobIndex: 0, baseFeeConfig: LibSharedData.BaseFeeConfig(0, 0, 0, 0, 0) }); } function blockV2toV1(TaikoData.BlockV2 memory _v2) internal pure returns (TaikoData.Block memory) { return TaikoData.Block({ metaHash: _v2.metaHash, assignedProver: _v2.assignedProver, livenessBond: _v2.livenessBond, blockId: _v2.blockId, proposedAt: _v2.proposedAt, proposedIn: _v2.proposedIn, nextTransitionId: _v2.nextTransitionId, verifiedTransitionId: _v2.verifiedTransitionId }); } function verifierContextV2toV1(IVerifier.ContextV2 memory _v2) internal pure returns (IVerifier.Context memory) { return IVerifier.Context({ metaHash: _v2.metaHash, blobHash: _v2.blobHash, prover: _v2.prover, blockId: _v2.blockId, isContesting: _v2.isContesting, blobUsed: _v2.blobUsed, msgSender: _v2.msgSender }); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "src/shared/common/IAddressResolver.sol"; import "src/shared/common/LibStrings.sol"; import "src/shared/common/LibMath.sol"; import "../tiers/ITierProvider.sol"; import "../tiers/ITierRouter.sol"; import "./TaikoData.sol"; /// @title LibUtils /// @notice A library that offers helper functions. /// @custom:security-contact [email protected] library LibUtils { using LibMath for uint256; /// @dev Emitted when a block is verified. /// @param blockId The ID of the verified block. /// @param prover The prover whose transition is used for verifying the /// block. /// @param blockHash The hash of the verified block. /// @param stateRoot Deprecated and is always zero. /// @param tier The tier ID of the proof. event BlockVerified( uint256 indexed blockId, address indexed prover, bytes32 blockHash, bytes32 stateRoot, uint16 tier ); /// @dev Emitted when a block is verified. /// @param blockId The ID of the verified block. /// @param prover The prover whose transition is used for verifying the /// block. /// @param blockHash The hash of the verified block. /// @param tier The tier ID of the proof. event BlockVerifiedV2( uint256 indexed blockId, address indexed prover, bytes32 blockHash, uint16 tier ); error L1_BLOCK_MISMATCH(); error L1_INVALID_BLOCK_ID(); error L1_INVALID_PARAMS(); error L1_INVALID_GENESIS_HASH(); error L1_TRANSITION_NOT_FOUND(); error L1_UNEXPECTED_TRANSITION_ID(); /// @notice Initializes the Taiko protocol state. /// @param _state The state to initialize. /// @param _genesisBlockHash The block hash of the genesis block. function init( TaikoData.State storage _state, TaikoData.Config memory _config, bytes32 _genesisBlockHash ) internal { if (_genesisBlockHash == 0) revert L1_INVALID_GENESIS_HASH(); // Init state _state.slotA.genesisHeight = uint64(block.number); _state.slotA.genesisTimestamp = uint64(block.timestamp); _state.slotB.numBlocks = 1; // Init the genesis block TaikoData.BlockV2 storage blk = _state.blocks[0]; blk.nextTransitionId = 2; blk.proposedAt = uint64(block.timestamp); blk.verifiedTransitionId = 1; blk.metaHash = bytes32(uint256(1)); // Give the genesis metahash a non-zero value. // Init the first state transition TaikoData.TransitionState storage ts = _state.transitions[0][1]; ts.blockHash = _genesisBlockHash; ts.prover = address(0); ts.timestamp = uint64(block.timestamp); if (_config.ontakeForkHeight == 0) { emit BlockVerifiedV2({ blockId: 0, prover: address(0), blockHash: _genesisBlockHash, tier: 0 }); } else { emit BlockVerified({ blockId: 0, prover: address(0), blockHash: _genesisBlockHash, stateRoot: 0, tier: 0 }); } } /// @dev Retrieves a block based on its ID. /// @param _state Current TaikoData.State. /// @param _config Actual TaikoData.Config. /// @param _blockId Id of the block. /// @return blk_ The block storage pointer. /// @return slot_ The slot value. function getBlock( TaikoData.State storage _state, TaikoData.Config memory _config, uint64 _blockId ) internal view returns (TaikoData.BlockV2 storage blk_, uint64 slot_) { slot_ = _blockId % _config.blockRingBufferSize; blk_ = _state.blocks[slot_]; if (blk_.blockId != _blockId) revert L1_INVALID_BLOCK_ID(); } /// @dev Retrieves a block's block hash and state root. /// @param _state Current TaikoData.State. /// @param _config Actual TaikoData.Config. /// @param _blockId Id of the block. /// @return blockHash_ The block's block hash. /// @return stateRoot_ The block's storage root. function getBlockInfo( TaikoData.State storage _state, TaikoData.Config memory _config, uint64 _blockId ) internal view returns (bytes32 blockHash_, bytes32 stateRoot_, uint64 verifiedAt_) { (TaikoData.BlockV2 storage blk, uint64 slot) = getBlock(_state, _config, _blockId); if (blk.verifiedTransitionId != 0) { TaikoData.TransitionState storage transition = _state.transitions[slot][blk.verifiedTransitionId]; blockHash_ = transition.blockHash; stateRoot_ = transition.stateRoot; verifiedAt_ = transition.timestamp; } } /// @notice This function will revert if the transition is not found. /// @dev Retrieves the transition with a given parentHash. /// @param _state Current TaikoData.State. /// @param _config Actual TaikoData.Config. /// @param _blockId Id of the block. /// @param _tid The transition id. /// @return The state transition pointer. function getTransition( TaikoData.State storage _state, TaikoData.Config memory _config, uint64 _blockId, uint32 _tid ) internal view returns (TaikoData.TransitionState storage) { (TaikoData.BlockV2 storage blk, uint64 slot) = getBlock(_state, _config, _blockId); if (_tid == 0 || _tid >= blk.nextTransitionId) revert L1_TRANSITION_NOT_FOUND(); return _state.transitions[slot][_tid]; } /// @notice This function will revert if the transition is not found. This function will revert /// if the transition is not found. /// @dev Retrieves the transition with a given parentHash. /// @param _state Current TaikoData.State. /// @param _config Actual TaikoData.Config. /// @param _blockId Id of the block. /// @param _parentHash Parent hash of the block. /// @return The state transition pointer. function getTransition( TaikoData.State storage _state, TaikoData.Config memory _config, uint64 _blockId, bytes32 _parentHash ) internal view returns (TaikoData.TransitionState storage) { (TaikoData.BlockV2 storage blk, uint64 slot) = getBlock(_state, _config, _blockId); uint24 tid = getTransitionId(_state, blk, slot, _parentHash); if (tid == 0) revert L1_TRANSITION_NOT_FOUND(); return _state.transitions[slot][tid]; } /// @notice Gets the state transitions for a batch of block. For transition that doesn't exist, /// the corresponding transition state will be empty. /// @param _state Current TaikoData.State. /// @param _config Actual TaikoData.Config. /// @param _blockIds Id array of the blocks. /// @param _parentHashes Parent hashes of the blocks. /// @return transitions_ The state transition pointer array. function getTransitions( TaikoData.State storage _state, TaikoData.Config memory _config, uint64[] calldata _blockIds, bytes32[] calldata _parentHashes ) internal view returns (TaikoData.TransitionState[] memory transitions_) { if (_blockIds.length == 0 || _blockIds.length != _parentHashes.length) { revert L1_INVALID_PARAMS(); } transitions_ = new TaikoData.TransitionState[](_blockIds.length); for (uint256 i; i < _blockIds.length; ++i) { (TaikoData.BlockV2 storage blk, uint64 slot) = getBlock(_state, _config, _blockIds[i]); uint24 tid = getTransitionId(_state, blk, slot, _parentHashes[i]); if (tid != 0) { transitions_[i] = _state.transitions[slot][tid]; } } } /// @dev Retrieves the ID of the transition with a given parentHash. /// This function will return 0 if the transition is not found. function getTransitionId( TaikoData.State storage _state, TaikoData.BlockV2 storage _blk, uint64 _slot, bytes32 _parentHash ) internal view returns (uint24 tid_) { if (_state.transitions[_slot][1].key == _parentHash) { tid_ = 1; if (tid_ >= _blk.nextTransitionId) revert L1_UNEXPECTED_TRANSITION_ID(); } else { tid_ = _state.transitionIds[_blk.blockId][_parentHash]; if (tid_ != 0 && tid_ >= _blk.nextTransitionId) revert L1_UNEXPECTED_TRANSITION_ID(); } } function isPostDeadline( uint256 _tsTimestamp, uint256 _lastUnpausedAt, uint256 _windowMinutes ) internal view returns (bool) { unchecked { uint256 deadline = _tsTimestamp.max(_lastUnpausedAt) + _windowMinutes * 60; return block.timestamp >= deadline; } } function shouldVerifyBlocks( TaikoData.Config memory _config, uint64 _blockId, bool _isBlockProposed ) internal pure returns (bool) { if (_config.maxBlocksToVerify == 0) return false; // Consider each segment of 8 blocks, verification is attempted either on block 3 if it has // been // proved, or on block 7 if it has been proposed. Over time, the ratio of blocks to // verification attempts averages 4:1, meaning each verification attempt typically covers 4 // blocks. However, considering worst cases caused by blocks being proved out of order, some // verification attempts may verify few or no blocks. In such cases, additional // verifications are needed to catch up. Consequently, the `maxBlocksToVerify` parameter // should be set high enough, for example 16, to allow for efficient catch-up. // Now lets use `maxBlocksToVerify` as an input to calculate the size of each block // segment, instead of using 8 as a constant. uint256 segmentSize = _config.maxBlocksToVerify >> 1; if (segmentSize <= 1) return true; return _blockId % segmentSize == (_isBlockProposed ? 0 : segmentSize >> 1); } function shouldSyncStateRoot( uint256 _stateRootSyncInternal, uint256 _blockId ) internal pure returns (bool) { if (_stateRootSyncInternal <= 1) return true; unchecked { // We could use `_blockId % _stateRootSyncInternal == 0`, but this will break many unit // tests as in most of these tests, we test block#1, so by setting // config._stateRootSyncInternal = 2, we can keep the tests unchanged. return _blockId % _stateRootSyncInternal == _stateRootSyncInternal - 1; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "src/shared/signal/ISignalService.sol"; import "./LibBonds.sol"; import "./LibUtils.sol"; /// @title LibVerifying /// @notice A library for handling block verification in the Taiko protocol. /// @custom:security-contact [email protected] library LibVerifying { using LibMath for uint256; struct Local { TaikoData.SlotB b; uint64 blockId; uint64 slot; uint64 numBlocksVerified; uint24 tid; uint24 lastVerifiedTransitionId; uint16 tier; bytes32 blockHash; bytes32 syncStateRoot; uint64 syncBlockId; uint24 syncTransitionId; address prover; bool postFork; ITierRouter tierRouter; } error L1_BLOCK_MISMATCH(); error L1_INVALID_CONFIG(); error L1_TRANSITION_ID_ZERO(); error L1_TOO_LATE(); /// @dev Verifies up to N blocks. function verifyBlocks( TaikoData.State storage _state, TaikoData.Config memory _config, IAddressResolver _resolver, uint64 _maxBlocksToVerify ) internal { if (_maxBlocksToVerify == 0) { return; } Local memory local; local.b = _state.slotB; local.blockId = local.b.lastVerifiedBlockId; local.slot = local.blockId % _config.blockRingBufferSize; TaikoData.BlockV2 storage blk = _state.blocks[local.slot]; if (blk.blockId != local.blockId) revert L1_BLOCK_MISMATCH(); local.lastVerifiedTransitionId = blk.verifiedTransitionId; local.tid = local.lastVerifiedTransitionId; // The following scenario should never occur but is included as a // precaution. if (local.tid == 0) revert L1_TRANSITION_ID_ZERO(); // The `blockHash` variable represents the most recently trusted // blockHash on L2. local.blockHash = _state.transitions[local.slot][local.tid].blockHash; // Unchecked is safe: // - assignment is within ranges // - blockId and numBlocksVerified values incremented will still be OK in the // next 584K years if we verifying one block per every second unchecked { ++local.blockId; while ( local.blockId < local.b.numBlocks && local.numBlocksVerified < _maxBlocksToVerify ) { local.slot = local.blockId % _config.blockRingBufferSize; local.postFork = local.blockId >= _config.ontakeForkHeight; blk = _state.blocks[local.slot]; if (blk.blockId != local.blockId) revert L1_BLOCK_MISMATCH(); local.tid = LibUtils.getTransitionId(_state, blk, local.slot, local.blockHash); // When `tid` is 0, it indicates that there is no proven // transition with its parentHash equal to the blockHash of the // most recently verified block. if (local.tid == 0) break; // A transition with the correct `parentHash` has been located. TaikoData.TransitionState storage ts = _state.transitions[local.slot][local.tid]; // It's not possible to verify this block if either the // transition is contested and awaiting higher-tier proof or if // the transition is still within its cooldown period. local.tier = ts.tier; if (ts.contester != address(0)) { break; } if (local.tierRouter == ITierRouter(address(0))) { local.tierRouter = ITierRouter(_resolver.resolve(LibStrings.B_TIER_ROUTER, false)); } uint24 cooldown = ITierProvider(local.tierRouter.getProvider(local.blockId)).getTier( local.tier ).cooldownWindow; if (!LibUtils.isPostDeadline(ts.timestamp, local.b.lastUnpausedAt, cooldown)) { // If cooldownWindow is 0, the block can theoretically // be proved and verified within the same L1 block. break; } // Update variables local.lastVerifiedTransitionId = local.tid; local.blockHash = ts.blockHash; local.prover = ts.prover; LibBonds.creditBond(_state, local.prover, ts.validityBond); // Note: We exclusively address the bonds linked to the // transition used for verification. While there may exist // other transitions for this block, we disregard them entirely. // The bonds for these other transitions are burned (more precisely held in custody) // either when the transitions are generated or proven. In such cases, both the // provers and contesters of those transitions forfeit their bonds. if (local.postFork) { emit LibUtils.BlockVerifiedV2({ blockId: local.blockId, prover: local.prover, blockHash: local.blockHash, tier: local.tier }); } else { emit LibUtils.BlockVerified({ blockId: local.blockId, prover: local.prover, blockHash: local.blockHash, stateRoot: 0, // DEPRECATED and is always zero. tier: local.tier }); } if (LibUtils.shouldSyncStateRoot(_config.stateRootSyncInternal, local.blockId)) { bytes32 stateRoot = ts.stateRoot; if (stateRoot != 0) { local.syncStateRoot = stateRoot; local.syncBlockId = local.blockId; local.syncTransitionId = local.tid; } } ++local.blockId; ++local.numBlocksVerified; } if (local.numBlocksVerified != 0) { uint64 lastVerifiedBlockId = local.b.lastVerifiedBlockId + local.numBlocksVerified; local.slot = lastVerifiedBlockId % _config.blockRingBufferSize; _state.slotB.lastVerifiedBlockId = lastVerifiedBlockId; _state.blocks[local.slot].verifiedTransitionId = local.lastVerifiedTransitionId; if (local.syncStateRoot != 0) { _state.slotA.lastSyncedBlockId = local.syncBlockId; _state.slotA.lastSynecdAt = uint64(block.timestamp); // We write the synced block's verifiedTransitionId to storage if (local.syncBlockId != lastVerifiedBlockId) { local.slot = local.syncBlockId % _config.blockRingBufferSize; _state.blocks[local.slot].verifiedTransitionId = local.syncTransitionId; } // Ask signal service to write cross chain signal ISignalService(_resolver.resolve(LibStrings.B_SIGNAL_SERVICE, false)) .syncChainData( _config.chainId, LibStrings.H_STATE_ROOT, local.syncBlockId, local.syncStateRoot ); } } } } function getVerifiedBlockProver( TaikoData.State storage _state, TaikoData.Config memory _config, uint64 _blockId ) internal view returns (address) { (TaikoData.BlockV2 storage blk,) = LibUtils.getBlock(_state, _config, _blockId); uint24 tid = blk.verifiedTransitionId; if (tid == 0) return address(0); return LibUtils.getTransition(_state, _config, _blockId, tid).prover; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; /// @title IAddressResolver /// @notice This contract acts as a bridge for name-to-address resolution. /// It delegates the resolution to the AddressManager. By separating the logic, /// we can maintain flexibility in address management without affecting the /// resolving process. /// @dev Note that the address manager should be changed using upgradability, there /// is no setAddressManager() function to guarantee atomicity across all /// contracts that are resolvers. /// @custom:security-contact [email protected] interface IAddressResolver { /// @notice Resolves a name to its address deployed on this chain. /// @param _name Name whose address is to be resolved. /// @param _allowZeroAddress If set to true, does not throw if the resolved /// address is `address(0)`. /// @return Address associated with the given name. function resolve(bytes32 _name, bool _allowZeroAddress) external view returns (address); /// @notice Resolves a name to its address deployed on a specified chain. /// @param _chainId The chainId of interest. /// @param _name Name whose address is to be resolved. /// @param _allowZeroAddress If set to true, does not throw if the resolved /// address is `address(0)`. /// @return Address associated with the given name on the specified /// chain. function resolve( uint64 _chainId, bytes32 _name, bool _allowZeroAddress ) external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; /// @title LibStrings /// @custom:security-contact [email protected] library LibStrings { bytes32 internal constant B_AUTOMATA_DCAP_ATTESTATION = bytes32("automata_dcap_attestation"); bytes32 internal constant B_BRIDGE = bytes32("bridge"); bytes32 internal constant B_BRIDGE_WATCHDOG = bytes32("bridge_watchdog"); bytes32 internal constant B_BRIDGED_ERC1155 = bytes32("bridged_erc1155"); bytes32 internal constant B_BRIDGED_ERC20 = bytes32("bridged_erc20"); bytes32 internal constant B_BRIDGED_ERC721 = bytes32("bridged_erc721"); bytes32 internal constant B_CHAIN_WATCHDOG = bytes32("chain_watchdog"); bytes32 internal constant B_ERC1155_VAULT = bytes32("erc1155_vault"); bytes32 internal constant B_ERC20_VAULT = bytes32("erc20_vault"); bytes32 internal constant B_ERC721_VAULT = bytes32("erc721_vault"); bytes32 internal constant B_PRECONF_REGISTRY = bytes32("preconf_registry"); bytes32 internal constant B_PROVER_ASSIGNMENT = bytes32("PROVER_ASSIGNMENT"); bytes32 internal constant B_PROVER_SET = bytes32("prover_set"); bytes32 internal constant B_QUOTA_MANAGER = bytes32("quota_manager"); bytes32 internal constant B_SGX_WATCHDOG = bytes32("sgx_watchdog"); bytes32 internal constant B_SIGNAL_SERVICE = bytes32("signal_service"); bytes32 internal constant B_SP1_REMOTE_VERIFIER = bytes32("sp1_remote_verifier"); bytes32 internal constant B_TAIKO = bytes32("taiko"); bytes32 internal constant B_TAIKO_TOKEN = bytes32("taiko_token"); bytes32 internal constant B_TIER_GUARDIAN = bytes32("tier_guardian"); bytes32 internal constant B_TIER_GUARDIAN_MINORITY = bytes32("tier_guardian_minority"); bytes32 internal constant B_TIER_ROUTER = bytes32("tier_router"); bytes32 internal constant B_TIER_SGX = bytes32("tier_sgx"); bytes32 internal constant B_TIER_TDX = bytes32("tier_tdx"); bytes32 internal constant B_TIER_TEE_ANY = bytes32("tier_tee_any"); bytes32 internal constant B_TIER_ZKVM_RISC0 = bytes32("tier_zkvm_risc0"); bytes32 internal constant B_TIER_ZKVM_SP1 = bytes32("tier_zkvm_sp1"); bytes32 internal constant B_TIER_ZKVM_ANY = bytes32("tier_zkvm_any"); bytes32 internal constant B_TIER_ZKVM_AND_TEE = bytes32("tier_zkvm_and_tee"); bytes32 internal constant B_RISCZERO_GROTH16_VERIFIER = bytes32("risc0_groth16_verifier"); bytes32 internal constant B_WITHDRAWER = bytes32("withdrawer"); bytes32 internal constant H_RETURN_LIVENESS_BOND = keccak256("RETURN_LIVENESS_BOND"); bytes32 internal constant H_SIGNAL_ROOT = keccak256("SIGNAL_ROOT"); bytes32 internal constant H_STATE_ROOT = keccak256("STATE_ROOT"); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "src/shared/data/LibSharedData.sol"; /// @title TaikoData /// @notice This library defines various data structures used in the Taiko /// protocol. /// @custom:security-contact [email protected] library TaikoData { /// @dev Struct holding Taiko configuration parameters. See {TaikoConfig}. struct Config { // --------------------------------------------------------------------- // Group 1: General configs // --------------------------------------------------------------------- // The chain ID of the network where Taiko contracts are deployed. uint64 chainId; // --------------------------------------------------------------------- // Group 2: Block level configs // --------------------------------------------------------------------- // The maximum number of proposals allowed in a single block. uint64 blockMaxProposals; // Size of the block ring buffer, allowing extra space for proposals. uint64 blockRingBufferSize; // The maximum number of verifications allowed when a block is proposed // or proved. uint64 maxBlocksToVerify; // The maximum gas limit allowed for a block. uint32 blockMaxGasLimit; // --------------------------------------------------------------------- // Group 3: Proof related configs // --------------------------------------------------------------------- // The amount of Taiko token as a prover liveness bond uint96 livenessBond; // --------------------------------------------------------------------- // Group 4: Cross-chain sync // --------------------------------------------------------------------- // The number of L2 blocks between each L2-to-L1 state root sync. uint8 stateRootSyncInternal; uint64 maxAnchorHeightOffset; // --------------------------------------------------------------------- // Group 5: Previous configs in TaikoL2 // --------------------------------------------------------------------- LibSharedData.BaseFeeConfig baseFeeConfig; // --------------------------------------------------------------------- // Group 6: Others // --------------------------------------------------------------------- uint64 ontakeForkHeight; } /// @dev A proof and the tier of proof it belongs to struct TierProof { uint16 tier; bytes data; } /// @dev Hook and it's data (currently used only during proposeBlock) struct HookCall { address hook; bytes data; } /// @dev Represents proposeBlock's _data input parameter struct BlockParams { address assignedProver; // DEPRECATED, value ignored. address coinbase; bytes32 extraData; bytes32 parentMetaHash; HookCall[] hookCalls; // DEPRECATED, value ignored. bytes signature; // DEPRECATED, value ignored. } struct BlockParamsV2 { address proposer; address coinbase; bytes32 parentMetaHash; uint64 anchorBlockId; // NEW uint64 timestamp; // NEW uint32 blobTxListOffset; // NEW uint32 blobTxListLength; // NEW uint8 blobIndex; // NEW } /// @dev Struct containing data only required for proving a block /// Note: On L2, `block.difficulty` is the pseudo name of /// `block.prevrandao`, which returns a random number provided by the layer /// 1 chain. struct BlockMetadata { bytes32 l1Hash; bytes32 difficulty; bytes32 blobHash; //or txListHash (if Blob not yet supported) bytes32 extraData; bytes32 depositsHash; address coinbase; // L2 coinbase, uint64 id; uint32 gasLimit; uint64 timestamp; uint64 l1Height; uint16 minTier; bool blobUsed; bytes32 parentMetaHash; address sender; // a.k.a proposer } struct BlockMetadataV2 { bytes32 anchorBlockHash; // `_l1BlockHash` in TaikoL2's anchor tx. bytes32 difficulty; bytes32 blobHash; bytes32 extraData; address coinbase; uint64 id; uint32 gasLimit; uint64 timestamp; uint64 anchorBlockId; // `_l1BlockId` in TaikoL2's anchor tx. uint16 minTier; bool blobUsed; bytes32 parentMetaHash; address proposer; uint96 livenessBond; // Time this block is proposed at, used to check proving window and cooldown window. uint64 proposedAt; // L1 block number, required/used by node/client. uint64 proposedIn; uint32 blobTxListOffset; uint32 blobTxListLength; uint8 blobIndex; LibSharedData.BaseFeeConfig baseFeeConfig; } /// @dev Struct representing transition to be proven. struct Transition { bytes32 parentHash; bytes32 blockHash; bytes32 stateRoot; bytes32 graffiti; // Arbitrary data that the prover can use for various purposes. } /// @dev Struct representing state transition data. /// 6 slots used. struct TransitionState { bytes32 key; // slot 1, only written/read for the 1st state transition. bytes32 blockHash; // slot 2 bytes32 stateRoot; // slot 3 address prover; // slot 4 uint96 validityBond; address contester; // slot 5 uint96 contestBond; uint64 timestamp; // slot 6 (90 bits) uint16 tier; uint8 __reserved1; } /// @dev Struct containing data required for verifying a block. /// 3 slots used. struct Block { bytes32 metaHash; // slot 1 address assignedProver; // slot 2 uint96 livenessBond; uint64 blockId; // slot 3 uint64 proposedAt; // timestamp uint64 proposedIn; // L1 block number, required/used by node/client. uint32 nextTransitionId; // The ID of the transaction that is used to verify this block. However, if // this block is not verified as the last block in a batch, verifiedTransitionId // will remain zero. uint32 verifiedTransitionId; } /// @dev Struct containing data required for verifying a block. /// 3 slots used. struct BlockV2 { bytes32 metaHash; // slot 1 address assignedProver; // slot 2 uint96 livenessBond; uint64 blockId; // slot 3 // Before the fork, this field is the L1 timestamp when this block is proposed. // After the fork, this is the timestamp of the L2 block. // In a later fork, we an rename this field to `timestamp`. uint64 proposedAt; // Before the fork, this field is the L1 block number where this block is proposed. // After the fork, this is the L1 block number input for the anchor transaction. // In a later fork, we an rename this field to `anchorBlockId`. uint64 proposedIn; uint24 nextTransitionId; bool livenessBondReturned; // The ID of the transaction that is used to verify this block. However, if // this block is not verified as the last block in a batch, verifiedTransitionId // will remain zero. uint24 verifiedTransitionId; } /// @dev Struct representing an Ethereum deposit. /// 2 slot used. Currently removed from protocol, but to be backwards compatible, the struct and /// return values stayed for now. struct EthDeposit { address recipient; uint96 amount; uint64 id; } /// @dev Forge is only able to run coverage in case the contracts by default /// capable of compiling without any optimization (neither optimizer runs, /// no compiling --via-ir flag). /// In order to resolve stack too deep without optimizations, we needed to /// introduce outsourcing vars into structs below. struct SlotA { uint64 genesisHeight; uint64 genesisTimestamp; uint64 lastSyncedBlockId; uint64 lastSynecdAt; // typo! } struct SlotB { uint64 numBlocks; uint64 lastVerifiedBlockId; bool provingPaused; uint8 __reservedB1; uint16 __reservedB2; uint32 __reservedB3; uint64 lastUnpausedAt; } /// @dev Struct holding the state variables for the {TaikoL1} contract. struct State { // Ring buffer for proposed blocks and a some recent verified blocks. mapping(uint64 blockId_mod_blockRingBufferSize => BlockV2 blk) blocks; // Indexing to transition ids (ring buffer not possible) mapping(uint64 blockId => mapping(bytes32 parentHash => uint24 transitionId)) transitionIds; // Ring buffer for transitions mapping( uint64 blockId_mod_blockRingBufferSize => mapping(uint32 transitionId => TransitionState ts) ) transitions; bytes32 __reserve1; // Used as a ring buffer for Ether deposits SlotA slotA; // slot 5 SlotB slotB; // slot 6 mapping(address account => uint256 bond) bondBalance; uint256[43] __gap; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "../based/TaikoData.sol"; /// @title IVerifier /// @notice Defines the function that handles proof verification. /// @custom:security-contact [email protected] interface IVerifier { struct Context { bytes32 metaHash; bytes32 blobHash; address prover; uint64 blockId; bool isContesting; bool blobUsed; address msgSender; } struct ContextV2 { bytes32 metaHash; bytes32 blobHash; address prover; uint64 blockId; bool isContesting; bool blobUsed; address msgSender; TaikoData.Transition tran; } /// @notice Verifies a proof. /// @param _ctx The context of the proof verification. /// @param _tran The transition to verify. /// @param _proof The proof to verify. function verifyProof( Context calldata _ctx, TaikoData.Transition calldata _tran, TaikoData.TierProof calldata _proof ) external; /// @notice Verifies multiple proofs. /// @param _ctxs The array of contexts for the proof verifications. /// @param _proof The batch proof to verify. function verifyBatchProof( ContextV2[] calldata _ctxs, TaikoData.TierProof calldata _proof ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; /// @title LibMath /// @dev This library offers additional math functions for uint256. /// @custom:security-contact [email protected] library LibMath { /// @dev Returns the smaller of the two given values. /// @param _a The first number to compare. /// @param _b The second number to compare. /// @return The smaller of the two numbers. function min(uint256 _a, uint256 _b) internal pure returns (uint256) { return _a > _b ? _b : _a; } /// @dev Returns the larger of the two given values. /// @param _a The first number to compare. /// @param _b The second number to compare. /// @return The larger of the two numbers. function max(uint256 _a, uint256 _b) internal pure returns (uint256) { return _a > _b ? _a : _b; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; /// @title ITierProvider /// @notice Defines interface to return tier configuration. /// @custom:security-contact [email protected] interface ITierProvider { struct Tier { bytes32 verifierName; uint96 validityBond; uint96 contestBond; uint24 cooldownWindow; // in minutes uint16 provingWindow; // in minutes uint8 maxBlocksToVerifyPerProof; // DEPRECATED } error TIER_NOT_FOUND(); /// @dev Retrieves the configuration for a specified tier. /// @param tierId ID of the tier. /// @return Tier struct containing the tier's parameters. function getTier(uint16 tierId) external view returns (Tier memory); /// @dev Retrieves the IDs of all supported tiers. /// Note that the core protocol requires the number of tiers to be smaller /// than 256. In reality, this number should be much smaller. /// @return The ids of the tiers. function getTierIds() external view returns (uint16[] memory); /// @dev Determines the minimal tier for a block based on a random input. /// @param proposer The address of the block proposer. /// @param rand A pseudo-random number. /// @return The tier id. function getMinTier(address proposer, uint256 rand) external view returns (uint16); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; /// @title ITierRouter /// @notice Defines interface to return an ITierProvider /// @custom:security-contact [email protected] interface ITierRouter { /// @dev Returns the address of the TierProvider for a given block. /// @param blockId ID of the block. /// @return The address of the corresponding TierProvider. function getProvider(uint256 blockId) external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; /// @title ISignalService /// @notice The SignalService contract serves as a secure cross-chain message /// passing system. It defines methods for sending and verifying signals with /// merkle proofs. The trust assumption is that the target chain has secure /// access to the merkle root (such as Taiko injects it in the anchor /// transaction). With this, verifying a signal is reduced to simply verifying /// a merkle proof. /// @custom:security-contact [email protected] interface ISignalService { enum CacheOption { CACHE_NOTHING, CACHE_SIGNAL_ROOT, CACHE_STATE_ROOT, CACHE_BOTH } struct HopProof { /// @notice This hop's destination chain ID. If there is a next hop, this ID is the next /// hop's source chain ID. uint64 chainId; /// @notice The ID of a source chain block whose state root has been synced to the hop's /// destination chain. /// Note that this block ID must be greater than or equal to the block ID where the signal /// was sent on the source chain. uint64 blockId; /// @notice The state root or signal root of the source chain at the above blockId. This /// value has been synced to the destination chain. /// @dev To get both the blockId and the rootHash, apps should subscribe to the /// ChainDataSynced event or query `topBlockId` first using the source chain's ID and /// LibStrings.H_STATE_ROOT to get the most recent block ID synced, then call /// `getSyncedChainData` to read the synchronized data. bytes32 rootHash; /// @notice Options to cache either the state roots or signal roots of middle-hops to the /// current chain. CacheOption cacheOption; /// @notice The signal service's account proof. If this value is empty, then `rootHash` will /// be used as the signal root, otherwise, `rootHash` will be used as the state root. bytes[] accountProof; /// @notice The signal service's storage proof. bytes[] storageProof; } /// @notice Emitted when a remote chain's state root or signal root is /// synced locally as a signal. /// @param chainId The remote chainId. /// @param blockId The chain data's corresponding blockId. /// @param kind A value to mark the data type. /// @param data The remote data. /// @param signal The signal for this chain data. event ChainDataSynced( uint64 indexed chainId, uint64 indexed blockId, bytes32 indexed kind, bytes32 data, bytes32 signal ); /// @notice Emitted when a signal is sent. /// @param app The address that initiated the signal. /// @param signal The signal (message) that was sent. /// @param slot The location in storage where this signal is stored. /// @param value The value of the signal. event SignalSent(address app, bytes32 signal, bytes32 slot, bytes32 value); /// @notice Emitted when an address is authorized or deauthorized. /// @param addr The address to be authorized or deauthorized. /// @param authorized True if authorized, false otherwise. event Authorized(address indexed addr, bool authorized); /// @notice Send a signal (message) by setting the storage slot to the same value as the signal /// itself. /// @param _signal The signal (message) to send. /// @return slot_ The location in storage where this signal is stored. function sendSignal(bytes32 _signal) external returns (bytes32 slot_); /// @notice Sync a data from a remote chain locally as a signal. The signal is calculated /// uniquely from chainId, kind, and data. /// @param _chainId The remote chainId. /// @param _kind A value to mark the data type. /// @param _blockId The chain data's corresponding blockId /// @param _chainData The remote data. /// @return signal_ The signal for this chain data. function syncChainData( uint64 _chainId, bytes32 _kind, uint64 _blockId, bytes32 _chainData ) external returns (bytes32 signal_); /// @notice Verifies if a signal has been received on the target chain. /// @param _chainId The identifier for the source chain from which the /// signal originated. /// @param _app The address that initiated the signal. /// @param _signal The signal (message) to send. /// @param _proof Merkle proof that the signal was persisted on the /// source chain. /// @return numCacheOps_ The number of newly cached items. function proveSignalReceived( uint64 _chainId, address _app, bytes32 _signal, bytes calldata _proof ) external returns (uint256 numCacheOps_); /// @notice Verifies if a signal has been received on the target chain. /// This is the "readonly" version of proveSignalReceived. /// @param _chainId The identifier for the source chain from which the /// signal originated. /// @param _app The address that initiated the signal. /// @param _signal The signal (message) to send. /// @param _proof Merkle proof that the signal was persisted on the /// source chain. function verifySignalReceived( uint64 _chainId, address _app, bytes32 _signal, bytes calldata _proof ) external view; /// @notice Verifies if a particular signal has already been sent. /// @param _app The address that initiated the signal. /// @param _signal The signal (message) that was sent. /// @return true if the signal has been sent, otherwise false. function isSignalSent(address _app, bytes32 _signal) external view returns (bool); /// @notice Checks if a chain data has been synced. /// @param _chainId The remote chainId. /// @param _kind A value to mark the data type. /// @param _blockId The chain data's corresponding blockId /// @param _chainData The remote data. /// @return true if the data has been synced, otherwise false. function isChainDataSynced( uint64 _chainId, bytes32 _kind, uint64 _blockId, bytes32 _chainData ) external view returns (bool); /// @notice Returns the given block's chain data. /// @param _chainId Identifier of the chainId. /// @param _kind A value to mark the data type. /// @param _blockId The chain data's corresponding block id. If this value is 0, use the top /// block id. /// @return blockId_ The actual block id. /// @return chainData_ The synced chain data. function getSyncedChainData( uint64 _chainId, bytes32 _kind, uint64 _blockId ) external view returns (uint64 blockId_, bytes32 chainData_); /// @notice Returns the data to be used for caching slot generation. /// @param _chainId Identifier of the chainId. /// @param _kind A value to mark the data type. /// @param _blockId The chain data's corresponding block id. If this value is 0, use the top /// block id. /// @return signal_ The signal used for caching slot creation. function signalForChainData( uint64 _chainId, bytes32 _kind, uint64 _blockId ) external pure returns (bytes32 signal_); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; library LibSharedData { /// @dev Struct that represents L2 basefee configurations struct BaseFeeConfig { uint8 adjustmentQuotient; uint8 sharingPctg; uint32 gasIssuancePerSecond; uint64 minGasExcess; uint32 maxGasIssuancePerBlock; } }
{ "remappings": [ "@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/", "openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/", "@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/", "openzeppelin/contracts/=node_modules/@openzeppelin/contracts/", "@risc0/contracts/=node_modules/risc0-ethereum/contracts/src/", "@solady/=node_modules/solady/", "@optimism/=node_modules/optimism/", "@sp1-contracts/=node_modules/sp1-contracts/contracts/", "forge-std/=node_modules/forge-std/", "ds-test/=node_modules/ds-test/src/", "@p256-verifier/contracts/=node_modules/p256-verifier/src/", "src/=contracts/", "test/=test/", "script/=script/", "optimism/=node_modules/optimism/", "p256-verifier/=node_modules/p256-verifier/", "risc0-ethereum/=node_modules/risc0-ethereum/", "solady/=node_modules/solady/", "sp1-contracts/=node_modules/sp1-contracts/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "cancun", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"name":"ETH_TRANSFER_FAILED","type":"error"},{"inputs":[],"name":"L1_BLOB_NOT_AVAILABLE","type":"error"},{"inputs":[],"name":"L1_BLOB_NOT_FOUND","type":"error"},{"inputs":[],"name":"L1_BLOCK_MISMATCH","type":"error"},{"inputs":[],"name":"L1_INVALID_ANCHOR_BLOCK","type":"error"},{"inputs":[],"name":"L1_INVALID_CUSTOM_PROPOSER","type":"error"},{"inputs":[],"name":"L1_INVALID_PARAMS","type":"error"},{"inputs":[],"name":"L1_INVALID_PROPOSER","type":"error"},{"inputs":[],"name":"L1_INVALID_TIMESTAMP","type":"error"},{"inputs":[],"name":"L1_LIVENESS_BOND_NOT_RECEIVED","type":"error"},{"inputs":[],"name":"L1_TOO_MANY_BLOCKS","type":"error"},{"inputs":[],"name":"L1_TRANSITION_ID_ZERO","type":"error"},{"inputs":[],"name":"L1_UNEXPECTED_PARENT","type":"error"},{"inputs":[],"name":"L1_UNEXPECTED_TRANSITION_ID","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"blockId","type":"uint256"},{"indexed":true,"internalType":"address","name":"assignedProver","type":"address"},{"indexed":false,"internalType":"uint96","name":"livenessBond","type":"uint96"},{"components":[{"internalType":"bytes32","name":"l1Hash","type":"bytes32"},{"internalType":"bytes32","name":"difficulty","type":"bytes32"},{"internalType":"bytes32","name":"blobHash","type":"bytes32"},{"internalType":"bytes32","name":"extraData","type":"bytes32"},{"internalType":"bytes32","name":"depositsHash","type":"bytes32"},{"internalType":"address","name":"coinbase","type":"address"},{"internalType":"uint64","name":"id","type":"uint64"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"uint64","name":"l1Height","type":"uint64"},{"internalType":"uint16","name":"minTier","type":"uint16"},{"internalType":"bool","name":"blobUsed","type":"bool"},{"internalType":"bytes32","name":"parentMetaHash","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"}],"indexed":false,"internalType":"struct TaikoData.BlockMetadata","name":"meta","type":"tuple"},{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint96","name":"amount","type":"uint96"},{"internalType":"uint64","name":"id","type":"uint64"}],"indexed":false,"internalType":"struct TaikoData.EthDeposit[]","name":"depositsProcessed","type":"tuple[]"}],"name":"BlockProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"blockId","type":"uint256"},{"components":[{"internalType":"bytes32","name":"anchorBlockHash","type":"bytes32"},{"internalType":"bytes32","name":"difficulty","type":"bytes32"},{"internalType":"bytes32","name":"blobHash","type":"bytes32"},{"internalType":"bytes32","name":"extraData","type":"bytes32"},{"internalType":"address","name":"coinbase","type":"address"},{"internalType":"uint64","name":"id","type":"uint64"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"uint64","name":"anchorBlockId","type":"uint64"},{"internalType":"uint16","name":"minTier","type":"uint16"},{"internalType":"bool","name":"blobUsed","type":"bool"},{"internalType":"bytes32","name":"parentMetaHash","type":"bytes32"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"uint96","name":"livenessBond","type":"uint96"},{"internalType":"uint64","name":"proposedAt","type":"uint64"},{"internalType":"uint64","name":"proposedIn","type":"uint64"},{"internalType":"uint32","name":"blobTxListOffset","type":"uint32"},{"internalType":"uint32","name":"blobTxListLength","type":"uint32"},{"internalType":"uint8","name":"blobIndex","type":"uint8"},{"components":[{"internalType":"uint8","name":"adjustmentQuotient","type":"uint8"},{"internalType":"uint8","name":"sharingPctg","type":"uint8"},{"internalType":"uint32","name":"gasIssuancePerSecond","type":"uint32"},{"internalType":"uint64","name":"minGasExcess","type":"uint64"},{"internalType":"uint32","name":"maxGasIssuancePerBlock","type":"uint32"}],"internalType":"struct LibSharedData.BaseFeeConfig","name":"baseFeeConfig","type":"tuple"}],"indexed":false,"internalType":"struct TaikoData.BlockMetadataV2","name":"meta","type":"tuple"}],"name":"BlockProposedV2","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"blockId","type":"uint256"},{"indexed":true,"internalType":"address","name":"prover","type":"address"},{"indexed":false,"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"stateRoot","type":"bytes32"},{"indexed":false,"internalType":"uint16","name":"tier","type":"uint16"}],"name":"BlockVerified","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"blockId","type":"uint256"},{"indexed":true,"internalType":"address","name":"prover","type":"address"},{"indexed":false,"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"indexed":false,"internalType":"uint16","name":"tier","type":"uint16"}],"name":"BlockVerifiedV2","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BondCredited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BondDebited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"blockId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"txList","type":"bytes"}],"name":"CalldataTxList","type":"event"}]
Contract Creation Code
6131bb610034600b8282823980515f1a607314602857634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040526004361061003f575f3560e01c806397fa596514610043578063fed97c5214610079575b5f5ffd5b81801561004e575f5ffd5b5061006261005d3660046124cf565b6100a6565b604051610070929190612877565b60405180910390f35b818015610084575f5ffd5b506100986100933660046128d4565b61010d565b60405161007092919061295f565b6100ae6120a7565b6100b661211a565b6100c5898989898989896102f2565b60058b01549193509150600160801b900460ff16610101576100ec888260a001515f61116b565b15610101576101018989898b606001516111dc565b97509795505050505050565b60608084158061011d5750848314155b1561013b576040516336c7c68960e01b815260040160405180910390fd5b846001600160401b03811115610153576101536121de565b60405190808252806020026020018201604052801561018c57816020015b6101796120a7565b8152602001906001900390816101715790505b509150846001600160401b038111156101a7576101a76121de565b6040519080825280602002602001820160405280156101e057816020015b6101cd61211a565b8152602001906001900390816101c55790505b5090505f5b85811015610282576102408a8a8a8a8a86818110610205576102056129f7565b90506020028101906102179190612a0b565b8a8a88818110610229576102296129f7565b905060200281019061023b9190612a0b565b6102f2565b848381518110610252576102526129f7565b6020026020010184848151811061026b5761026b6129f7565b6020908102919091010191909152526001016101e5565b506005890154600160801b900460ff16610101575f5b858110156102e5576102c8898383815181106102b6576102b66129f7565b602002602001015160a001515f61116b565b156102dd576102dd8a8a8a8c606001516111dc565b600101610298565b5097509795505050505050565b6102fa6120a7565b61030261211a565b6103b7604080516101c081019091525f60e08201818152610100830182905261012083018290526101408301829052610160830182905261018083018290526101a08301919091528190815260408051610100810182525f8082526020828101829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082015291019081525f6020820181905260408201819052606082018190526080820181905260a09091015290565b6040805160e08101825260058c01546001600160401b038082168352600160401b82048116602080850191825260ff600160801b85048116151596860196909652600160881b8404909516606085015261ffff600160901b84041660808086019190915263ffffffff600160a01b85041660a0860152600160c01b909304821660c08501528386526101208e0151935193821693909116929092101590840152908a015190516104679190612a61565b610472906001612a61565b8151516001600160401b039182169116106104a0576040516351ec7d5360e01b815260040160405180910390fd5b604051635437cecf60e11b81526f707265636f6e665f726567697374727960801b6004820152600160248201525f906001600160a01b038a169063a86f9d9e90604401602060405180830381865afa1580156104fe573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105229190612a80565b90506001600160a01b03811615610564576001600160a01b038116331461055c576040516306b7162d60e51b815260040160405180910390fd5b600160a08301525b81608001511561058b5786156105865761058087890189612aa6565b60208301525b610640565b5f610598888a018a612ca1565b90506106318160408051610100810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101919091525060408051610100810182525f8082526020848101516001600160a01b031690830152606093840151928201929092529182018190526080820181905260a0820181905260c0820181905260e082015290565b60208401526040015160c08301525b6020820151516001600160a01b031661066057602082015133905261069e565b6020820151516001600160a01b0316331480159061068057508160a00151155b1561069e57604051636021831560e11b815260040160405180910390fd5b60208083015101516001600160a01b03166106c85760208083015180516001600160a01b03169101525b8160200151606001516001600160401b03165f036106f95760208201516001600160401b035f194301166060909101525b8160200151608001516001600160401b03165f036107275760208201516001600160401b0342166080909101525b60408a01518251515f918d9183916001600160401b03908116915f1901168161075257610752612d6b565b066001600160401b03166001600160401b031681526020019081526020015f2090508260800151156108a057438b60e001518460200151606001516107979190612a61565b6001600160401b031610806107bd5750438360200151606001516001600160401b031610155b806107e7575060028101546020840151606001516001600160401b03600160801b90920482169116105b15610805576040516330c7248160e11b815260040160405180910390fd5b42600c8c60e001516001600160401b03166108209190612d7f565b8460200151608001516001600160401b031661083c9190612d96565b10806108585750428360200151608001516001600160401b0316115b80610882575060028101546020840151608001516001600160401b03600160401b90920482169116105b156108a0576040516313f7f80d60e01b815260040160405180910390fd5b6020830151604001515f036108bf5780546020840151604001526108e8565b8054602084015160400151146108e857604051630d41ec8760e11b815260040160405180910390fd5b6040805161028081018252602080860151606001516001600160401b03164082528551519251919281840192610954920160408082526010908201526f5441494b4f5f444946464943554c545960801b60608201526001600160401b0391909116602082015260800190565b6040516020818303038152906040528051906020012081526020015f5f1b8152602001846080015161098a578460c00151610998565b6101008d01516020015160ff165b81526020018460200151602001516001600160a01b03168152602001845f01515f01516001600160401b031681526020018c6080015163ffffffff1681526020018460200151608001516001600160401b031681526020018460200151606001516001600160401b031681526020015f61ffff168152602001888890505f1415158152602001846020015160400151815260200184602001515f01516001600160a01b031681526020018c60a001516001600160601b03168152602001426001600160401b03168152602001436001600160401b03168152602001846020015160a0015163ffffffff168152602001846020015160c0015163ffffffff168152602001846020015160e0015160ff1681526020018c6101000151815250935083610140015115610b2057610acb46611b98565b610ae85760405163df9969ef60e01b815260040160405180910390fd5b602083015160e0015160ff1649604085018190525f03610b1b57604051639e7e2ddd60e01b815260040160405180910390fd5b610b89565b8686604051610b30929190612da9565b60405180910390208460400181815250508360a001516001600160401b03167fa07bc5e8f00f6065c8727821591c519efd2348e4ff0c26560a85592e85b6f4188888604051610b80929190612db8565b60405180910390a25b604051635437cecf60e11b81526a3a34b2b92fb937baba32b960a91b60048201525f60248201526001600160a01b038b169063a86f9d9e90604401602060405180830381865afa158015610bdf573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c039190612a80565b835151604051635c42d07960e01b81526001600160401b0390911660048201526001600160a01b039190911690635c42d07990602401602060405180830381865afa158015610c54573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c789190612a80565b6001600160a01b039081166040858101829052610180870151602088015191516352c5c56b60e01b8152931660048401526024830152906352c5c56b90604401602060405180830381865afa158015610cd3573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cf79190612df7565b61ffff166101208501526080830151610d1657610d1384611bcb565b94505b5f6040518061012001604052808560800151610d585787604051602001610d3d9190612e10565b60405160208183030381529060405280519060200120610d80565b86604051602001610d699190612e1f565b604051602081830303815290604052805190602001205b81526020015f6001600160a01b031681526020018560800151610da857866101a00151610daa565b5f5b6001600160601b031681528551516001600160401b031660208201526080860151604090910190610ddb5742610de5565b8560200151608001515b6001600160401b031681526020018560800151610e025743610e0c565b8560200151606001515b6001600160401b03168152602001600162ffffff1681526020015f151581526020015f62ffffff168152509050808d5f015f8e60400151875f01515f0151610e549190612fe3565b6001600160401b03166001600160401b031681526020019081526020015f205f820151815f01556020820151816001015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160010160146101000a8154816001600160601b0302191690836001600160601b031602179055506060820151816002015f6101000a8154816001600160401b0302191690836001600160401b0316021790555060808201518160020160086101000a8154816001600160401b0302191690836001600160401b0316021790555060a08201518160020160106101000a8154816001600160401b0302191690836001600160401b0316021790555060c08201518160020160186101000a81548162ffffff021916908362ffffff16021790555060e082015181600201601b6101000a81548160ff02191690831515021790555061010082015181600201601c6101000a81548162ffffff021916908362ffffff1602179055509050508c6005015f015f81819054906101000a90046001600160401b031660010191906101000a8154816001600160401b0302191690836001600160401b0316021790555061102a8d8c86602001515f01518f60a001516001600160601b0316611ccb565b341580159061103857504115155b15611047576110474134611dd1565b83608001511561109b578460a001516001600160401b03167fefe9c6c0b5cbd9c0eed2d1e9c00cfc1a010d6f1aff50f7facd665a639b622b268660405161108e9190612e1f565b60405180910390a261115b565b83602001515f01516001600160a01b03168660c001516001600160401b03167fcda4e564245eb15494bc6da29f6a42e1941cf57f5314bf35bab8a1fca0a9c60a8e60a00151895f6001600160401b038111156110f9576110f96121de565b60405190808252806020026020018201604052801561114257816020015b604080516060810182525f80825260208083018290529282015282525f199092019101816111175790505b5060405161115293929190613010565b60405180910390a35b5050505097509795505050505050565b5f83606001516001600160401b03165f0361118757505f6111d5565b6060840151677fffffffffffffff600191821c169081116111ac5760019150506111d5565b826111bb57600181901c6111bd565b5f5b6111d0826001600160401b0387166130aa565b149150505b9392505050565b6001600160401b03811615611b9257604080516102a0810182525f6101c082018181526101e0830182905261020083018290526102208301829052610240830182905261026083018290526102808301829052825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a08101919091526040805160e08101825260058701546001600160401b038082168352600160401b82048116602080850191825260ff600160801b85048116151586880152600160881b850416606086015261ffff600160901b850416608086015263ffffffff600160a01b85041660a0860152600160c01b909304821660c085015292855291519091169083018190529085015161132991612fe3565b6001600160401b0390811660408084018290525f91825260208881529120908301516002820154919291821691161461137557604051632ec3485560e11b815260040160405180910390fd5b6002810154600160e01b900462ffffff1660a08301819052608083018190525f036113b35760405163d4345b9760e01b815260040160405180910390fd5b6040808301516001600160401b039081165f908152600289016020908152838220608087015162ffffff168352815292902060019081015460e086015291840180519092011690525b81515160208301516001600160401b0391821691161080156114335750826001600160401b031682606001516001600160401b0316105b156118d45784604001516001600160401b031682602001516001600160401b03168161146157611461612d6b565b066001600160401b0390811660408481018290526101208801516020808701805192861692861692909210156101808801525f9384528a905291209051600282015491935082169116146114c857604051632ec3485560e11b815260040160405180910390fd5b6114dc868284604001518560e00151611de0565b62ffffff1660808301819052156118d4576040828101516001600160401b03165f908152600288016020908152828220608086015162ffffff1683529052206005810154600160401b900461ffff1660c084015260048101546001600160a01b03161561154957506118d4565b6101a08301516001600160a01b03166115e657604051635437cecf60e11b81526a3a34b2b92fb937baba32b960a91b60048201525f60248201526001600160a01b0386169063a86f9d9e90604401602060405180830381865afa1580156115b2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115d69190612a80565b6001600160a01b03166101a08401525b6101a08301516020840151604051635c42d07960e01b81526001600160401b0390911660048201525f916001600160a01b031690635c42d07990602401602060405180830381865afa15801561163e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116629190612a80565b60c085015160405163576c3de760e01b815261ffff90911660048201526001600160a01b03919091169063576c3de79060240160c060405180830381865afa1580156116b0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116d491906130c8565b606001516005830154855160c00151919250611702916001600160401b03918216911662ffffff8416611ebe565b61170d5750506118d4565b608084015162ffffff1660a0850152600182015460e085015260038201546001600160a01b0381166101608601819052611759918a9190600160a01b90046001600160601b0316611edb565b836101800151156117d4578361016001516001600160a01b031684602001516001600160401b03167fe5a390d9800811154279af0c1a80d3bdf558ea91f1301e7c6ec3c1ad83e80aef8660e001518760c001516040516117c792919091825261ffff16602082015260400190565b60405180910390a361184a565b8361016001516001600160a01b031684602001516001600160401b03167fdecbd2c61cbda254917d6fd4c980a470701e8f9f1b744f6ad163ca70ca5db2898660e001515f8860c0015160405161184193929190928352602083019190915261ffff16604082015260600190565b60405180910390a35b6118688760c0015160ff1685602001516001600160401b0316611f4c565b156118a757600282015480156118a557610100850181905260208501516001600160401b0316610120860152608085015162ffffff166101408601525b505b50506020820180516001600160401b036001918201811690925260608401805190910190911690526113fc565b60608201516001600160401b031615611b8f57606082015182516020015160408701519101906001600160401b039081169082168161191557611915612d6b565b6001600160401b039190068116604080860182905260058a018054938516600160401b026fffffffffffffffff0000000000000000199094169390931790925560a08501515f91825260208a9052919020600201805462ffffff909216600160e01b0262ffffff60e01b1990921691909117905561010083015115611b8d576101208301516004880180546fffffffffffffffffffffffffffffffff16600160801b6001600160401b039384169081026001600160c01b031691909117600160c01b428516021790915590821614611a595785604001516001600160401b03168361012001516001600160401b031681611a1157611a11612d6b565b066001600160401b031660408481018290526101408501515f92835260208a90529120600201805462ffffff60e01b1916600160e01b62ffffff909316929092029190911790555b604051635437cecf60e11b81526d7369676e616c5f7365727669636560901b60048201525f60248201526001600160a01b0386169063a86f9d9e90604401602060405180830381865afa158015611ab2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ad69190612a80565b86516101208501516101008601516040516313e4299d60e21b81526001600160401b0393841660048201527f73e6d340850343cc6f001515dc593377337c95a6ffe034fe1e844d4dab5da169602482015292909116604483015260648201526001600160a01b039190911690634f90a674906084016020604051808303815f875af1158015611b67573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b8b919061314f565b505b505b50505b50505050565b5f6001821480611ba9575061426882145b80611bb6575062aa36a782145b80611bc55750611bc582611f79565b92915050565b611bd36120a7565b604051806101c00160405280835f015181526020018360200151815260200183604001518152602001836060015181526020017f569e75fc77c1a856f6daaf9e69d8a9566ca34aa47f9133711ce065a571af0cfd5f1b815260200183608001516001600160a01b031681526020018360a001516001600160401b031681526020018360c0015163ffffffff1681526020018360e001516001600160401b031681526020018361010001516001600160401b0316815260200183610120015161ffff1681526020018361014001511515815260200183610160015181526020018361018001516001600160a01b03168152509050919050565b6001600160a01b0382165f908152600685016020526040902054818110611d49576001600160a01b0383165f818152600687016020526040908190208484039055517f85f32beeaff2d0019a8d196f06790c9a652191759c46643311344fd38920423c90611d3c9085815260200190565b60405180910390a2611dca565b611d5284611f90565b6040516323b872dd60e01b81526001600160a01b0385811660048301523060248301526044820185905291909116906323b872dd906064016020604051808303815f875af1158015611da6573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b8f9190613166565b5050505050565b611ddc82825a61200d565b5050565b6001600160401b0382165f908152600285016020908152604080832060018452909152812054829003611e4657506002830154600190600160c01b900462ffffff168110611e41576040516367a1907f60e01b815260040160405180910390fd5b611eb6565b5060028301546001600160401b03165f908152600185016020908152604080832084845290915290205462ffffff168015801590611e985750600284015462ffffff600160c01b909104811690821610155b15611eb6576040516367a1907f60e01b815260040160405180910390fd5b949350505050565b5f80603c8302611ece8686612055565b0142101595945050505050565b6001600160a01b0382165f90815260068401602052604081208054839290611f04908490612d96565b90915550506040518181526001600160a01b038316907f6de6fe586196fa05b73b973026c5fda3968a2933989bff3a0b6bd57644fab6069060200160405180910390a2505050565b5f60018311611f5d57506001611bc5565b60018303838381611f7057611f70612d6b565b06149392505050565b5f617e2c8210158015611bc5575050617e90101590565b604051635437cecf60e11b81526a3a30b4b5b7afba37b5b2b760a91b60048201525f60248201819052906001600160a01b0383169063a86f9d9e90604401602060405180830381865afa158015611fe9573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bc59190612a80565b815f0361201957505050565b61203383838360405180602001604052805f81525061206a565b61205057604051634c67134d60e11b815260040160405180910390fd5b505050565b5f81831161206357816111d5565b5090919050565b5f6001600160a01b03851661209257604051634c67134d60e11b815260040160405180910390fd5b5f5f835160208501878988f195945050505050565b604080516101c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081019190915290565b60408051610280810182525f80825260208083018290528284018290526060808401839052608080850184905260a080860185905260c0860185905260e08601859052610100860185905261012086018590526101408601859052610160860185905261018086018590526101a086018590526101c086018590526101e08601859052610200860185905261022086018590526102408601859052865190810187528481529283018490529482018390528101829052928301529061026082015290565b634e487b7160e01b5f52604160045260245ffd5b60405161014081016001600160401b0381118282101715612215576122156121de565b60405290565b60405161010081016001600160401b0381118282101715612215576122156121de565b604080519081016001600160401b0381118282101715612215576122156121de565b60405160c081016001600160401b0381118282101715612215576122156121de565b604051601f8201601f191681016001600160401b03811182821017156122aa576122aa6121de565b604052919050565b80356001600160401b03811681146122c8575f5ffd5b919050565b803563ffffffff811681146122c8575f5ffd5b6001600160601b03811681146122f4575f5ffd5b50565b80356122c8816122e0565b60ff811681146122f4575f5ffd5b80356122c881612302565b5f60a0828403121561232b575f5ffd5b60405160a081016001600160401b038111828210171561234d5761234d6121de565b604052905080823561235e81612302565b8152602083013561236e81612302565b602082015261237f604084016122cd565b6040820152612390606084016122b2565b60608201526123a1608084016122cd565b60808201525092915050565b5f6101c082840312156123be575f5ffd5b6123c66121f2565b90506123d1826122b2565b81526123df602083016122b2565b60208201526123f0604083016122b2565b6040820152612401606083016122b2565b6060820152612412608083016122cd565b608082015261242360a083016122f7565b60a082015261243460c08301612310565b60c082015261244560e083016122b2565b60e082015261245883610100840161231b565b61010082015261246b6101a083016122b2565b61012082015292915050565b6001600160a01b03811681146122f4575f5ffd5b5f5f83601f84011261249b575f5ffd5b5081356001600160401b038111156124b1575f5ffd5b6020830191508360208285010111156124c8575f5ffd5b9250929050565b5f5f5f5f5f5f5f610240888a0312156124e6575f5ffd5b873596506124f78960208a016123ad565b95506101e088013561250881612477565b94506102008801356001600160401b03811115612523575f5ffd5b61252f8a828b0161248b565b9095509350506102208801356001600160401b0381111561254e575f5ffd5b61255a8a828b0161248b565b989b979a50959850939692959293505050565b805182526020810151602083015260408101516040830152606081015160608301526080810151608083015260a08101516125b360a08401826001600160a01b03169052565b5060c08101516125ce60c08401826001600160401b03169052565b5060e08101516125e660e084018263ffffffff169052565b506101008101516126036101008401826001600160401b03169052565b506101208101516126206101208401826001600160401b03169052565b5061014081015161263861014084018261ffff169052565b5061016081015161264e61016084018215159052565b506101808101516101808301526101a08101516120506101a08401826001600160a01b03169052565b60ff815116825260ff602082015116602083015263ffffffff60408201511660408301526001600160401b03606082015116606083015263ffffffff60808201511660808301525050565b8051825260208101516020830152604081015160408301526060810151606083015260808101516126fe60808401826001600160a01b03169052565b5060a081015161271960a08401826001600160401b03169052565b5060c081015161273160c084018263ffffffff169052565b5060e081015161274c60e08401826001600160401b03169052565b506101008101516127696101008401826001600160401b03169052565b5061012081015161278161012084018261ffff169052565b5061014081015161279761014084018215159052565b506101608101516101608301526101808101516127c06101808401826001600160a01b03169052565b506101a08101516127dd6101a08401826001600160601b03169052565b506101c08101516127fa6101c08401826001600160401b03169052565b506101e08101516128176101e08401826001600160401b03169052565b5061020081015161283161020084018263ffffffff169052565b5061022081015161284b61022084018263ffffffff169052565b5061024081015161286261024084018260ff169052565b50610260810151612050610260840182612677565b6104c08101612886828561256d565b6111d56101c08301846126c2565b5f5f83601f8401126128a4575f5ffd5b5081356001600160401b038111156128ba575f5ffd5b6020830191508360208260051b85010111156124c8575f5ffd5b5f5f5f5f5f5f5f610240888a0312156128eb575f5ffd5b873596506128fc8960208a016123ad565b95506101e088013561290d81612477565b94506102008801356001600160401b03811115612928575f5ffd5b6129348a828b01612894565b9095509350506102208801356001600160401b03811115612953575f5ffd5b61255a8a828b01612894565b604080825283519082018190525f9060208501906060840190835b818110156129a45761298d83855161256d565b602093909301926101c0929092019160010161297a565b5050838103602080860191909152855180835291810192508501905f5b818110156129eb576129d48484516126c2565b6103009390930192602092909201916001016129c1565b50919695505050505050565b634e487b7160e01b5f52603260045260245ffd5b5f5f8335601e19843603018112612a20575f5ffd5b8301803591506001600160401b03821115612a39575f5ffd5b6020019150368190038213156124c8575f5ffd5b634e487b7160e01b5f52601160045260245ffd5b6001600160401b038181168382160190811115611bc557611bc5612a4d565b5f60208284031215612a90575f5ffd5b81516111d581612477565b80356122c881612477565b5f610100828403128015612ab8575f5ffd5b50612ac161221b565b8235612acc81612477565b8152612ada60208401612a9b565b602082015260408381013590820152612af5606084016122b2565b6060820152612b06608084016122b2565b6080820152612b1760a084016122cd565b60a0820152612b2860c084016122cd565b60c0820152612b3960e08401612310565b60e08201529392505050565b5f82601f830112612b54575f5ffd5b81356001600160401b03811115612b6d57612b6d6121de565b612b80601f8201601f1916602001612282565b818152846020838601011115612b94575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f82601f830112612bbf575f5ffd5b81356001600160401b03811115612bd857612bd86121de565b8060051b612be860208201612282565b91825260208185018101929081019086841115612c03575f5ffd5b6020860192505b83831015612c975782356001600160401b03811115612c27575f5ffd5b86016040818903601f19011215612c3c575f5ffd5b612c4461223e565b6020820135612c5281612477565b815260408201356001600160401b03811115612c6c575f5ffd5b612c7b8a602083860101612b45565b6020830152508084525050602082019150602083019250612c0a565b9695505050505050565b5f60208284031215612cb1575f5ffd5b81356001600160401b03811115612cc6575f5ffd5b820160c08185031215612cd7575f5ffd5b612cdf612260565b612ce882612a9b565b8152612cf660208301612a9b565b6020820152604082810135908201526060808301359082015260808201356001600160401b03811115612d27575f5ffd5b612d3386828501612bb0565b60808301525060a08201356001600160401b03811115612d51575f5ffd5b612d5d86828501612b45565b60a083015250949350505050565b634e487b7160e01b5f52601260045260245ffd5b8082028115828204841417611bc557611bc5612a4d565b80820180821115611bc557611bc5612a4d565b818382375f9101908152919050565b60208152816020820152818360408301375f818301604090810191909152601f909201601f19160101919050565b805161ffff811681146122c8575f5ffd5b5f60208284031215612e07575f5ffd5b6111d582612de6565b6101c08101611bc5828461256d565b5f61030082019050825182526020830151602083015260408301516040830152606083015160608301526080830151612e6360808401826001600160a01b03169052565b5060a0830151612e7e60a08401826001600160401b03169052565b5060c0830151612e9660c084018263ffffffff169052565b5060e0830151612eb160e08401826001600160401b03169052565b50610100830151612ece6101008401826001600160401b03169052565b50610120830151612ee661012084018261ffff169052565b50610140830151612efc61014084018215159052565b50610160830151610160830152610180830151612f256101808401826001600160a01b03169052565b506101a0830151612f426101a08401826001600160601b03169052565b506101c0830151612f5f6101c08401826001600160401b03169052565b506101e0830151612f7c6101e08401826001600160401b03169052565b50610200830151612f9661020084018263ffffffff169052565b50610220830151612fb061022084018263ffffffff169052565b50610240830151612fc761024084018260ff169052565b50610260830151612fdc610260840182612677565b5092915050565b5f6001600160401b03831680612ffb57612ffb612d6b565b806001600160401b0384160691505092915050565b5f61020082016001600160601b038616835261302f602084018661256d565b6102006101e084015283519081905260208401906102208401905f5b8181101561309d57835180516001600160a01b031684526020808201516001600160601b0316818601526040918201516001600160401b0316918501919091529093019260609092019160010161304b565b5090979650505050505050565b5f826130b8576130b8612d6b565b500690565b80516122c881612302565b5f60c08284031280156130d9575f5ffd5b506130e2612260565b8251815260208301516130f4816122e0565b60208201526040830151613107816122e0565b6040820152606083015162ffffff81168114613121575f5ffd5b606082015261313260808401612de6565b608082015261314360a084016130bd565b60a08201529392505050565b5f6020828403121561315f575f5ffd5b5051919050565b5f60208284031215613176575f5ffd5b815180151581146111d5575f5ffdfea264697066735822122059b797ed8b30928e2f1f585710724c1c9ead4534f63dae0afbf4fd0cfe46e08364736f6c634300081b0033
Deployed Bytecode
0x7398371b6283ace937b0367764cc49e4c3edc29d14301460806040526004361061003f575f3560e01c806397fa596514610043578063fed97c5214610079575b5f5ffd5b81801561004e575f5ffd5b5061006261005d3660046124cf565b6100a6565b604051610070929190612877565b60405180910390f35b818015610084575f5ffd5b506100986100933660046128d4565b61010d565b60405161007092919061295f565b6100ae6120a7565b6100b661211a565b6100c5898989898989896102f2565b60058b01549193509150600160801b900460ff16610101576100ec888260a001515f61116b565b15610101576101018989898b606001516111dc565b97509795505050505050565b60608084158061011d5750848314155b1561013b576040516336c7c68960e01b815260040160405180910390fd5b846001600160401b03811115610153576101536121de565b60405190808252806020026020018201604052801561018c57816020015b6101796120a7565b8152602001906001900390816101715790505b509150846001600160401b038111156101a7576101a76121de565b6040519080825280602002602001820160405280156101e057816020015b6101cd61211a565b8152602001906001900390816101c55790505b5090505f5b85811015610282576102408a8a8a8a8a86818110610205576102056129f7565b90506020028101906102179190612a0b565b8a8a88818110610229576102296129f7565b905060200281019061023b9190612a0b565b6102f2565b848381518110610252576102526129f7565b6020026020010184848151811061026b5761026b6129f7565b6020908102919091010191909152526001016101e5565b506005890154600160801b900460ff16610101575f5b858110156102e5576102c8898383815181106102b6576102b66129f7565b602002602001015160a001515f61116b565b156102dd576102dd8a8a8a8c606001516111dc565b600101610298565b5097509795505050505050565b6102fa6120a7565b61030261211a565b6103b7604080516101c081019091525f60e08201818152610100830182905261012083018290526101408301829052610160830182905261018083018290526101a08301919091528190815260408051610100810182525f8082526020828101829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082015291019081525f6020820181905260408201819052606082018190526080820181905260a09091015290565b6040805160e08101825260058c01546001600160401b038082168352600160401b82048116602080850191825260ff600160801b85048116151596860196909652600160881b8404909516606085015261ffff600160901b84041660808086019190915263ffffffff600160a01b85041660a0860152600160c01b909304821660c08501528386526101208e0151935193821693909116929092101590840152908a015190516104679190612a61565b610472906001612a61565b8151516001600160401b039182169116106104a0576040516351ec7d5360e01b815260040160405180910390fd5b604051635437cecf60e11b81526f707265636f6e665f726567697374727960801b6004820152600160248201525f906001600160a01b038a169063a86f9d9e90604401602060405180830381865afa1580156104fe573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105229190612a80565b90506001600160a01b03811615610564576001600160a01b038116331461055c576040516306b7162d60e51b815260040160405180910390fd5b600160a08301525b81608001511561058b5786156105865761058087890189612aa6565b60208301525b610640565b5f610598888a018a612ca1565b90506106318160408051610100810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101919091525060408051610100810182525f8082526020848101516001600160a01b031690830152606093840151928201929092529182018190526080820181905260a0820181905260c0820181905260e082015290565b60208401526040015160c08301525b6020820151516001600160a01b031661066057602082015133905261069e565b6020820151516001600160a01b0316331480159061068057508160a00151155b1561069e57604051636021831560e11b815260040160405180910390fd5b60208083015101516001600160a01b03166106c85760208083015180516001600160a01b03169101525b8160200151606001516001600160401b03165f036106f95760208201516001600160401b035f194301166060909101525b8160200151608001516001600160401b03165f036107275760208201516001600160401b0342166080909101525b60408a01518251515f918d9183916001600160401b03908116915f1901168161075257610752612d6b565b066001600160401b03166001600160401b031681526020019081526020015f2090508260800151156108a057438b60e001518460200151606001516107979190612a61565b6001600160401b031610806107bd5750438360200151606001516001600160401b031610155b806107e7575060028101546020840151606001516001600160401b03600160801b90920482169116105b15610805576040516330c7248160e11b815260040160405180910390fd5b42600c8c60e001516001600160401b03166108209190612d7f565b8460200151608001516001600160401b031661083c9190612d96565b10806108585750428360200151608001516001600160401b0316115b80610882575060028101546020840151608001516001600160401b03600160401b90920482169116105b156108a0576040516313f7f80d60e01b815260040160405180910390fd5b6020830151604001515f036108bf5780546020840151604001526108e8565b8054602084015160400151146108e857604051630d41ec8760e11b815260040160405180910390fd5b6040805161028081018252602080860151606001516001600160401b03164082528551519251919281840192610954920160408082526010908201526f5441494b4f5f444946464943554c545960801b60608201526001600160401b0391909116602082015260800190565b6040516020818303038152906040528051906020012081526020015f5f1b8152602001846080015161098a578460c00151610998565b6101008d01516020015160ff165b81526020018460200151602001516001600160a01b03168152602001845f01515f01516001600160401b031681526020018c6080015163ffffffff1681526020018460200151608001516001600160401b031681526020018460200151606001516001600160401b031681526020015f61ffff168152602001888890505f1415158152602001846020015160400151815260200184602001515f01516001600160a01b031681526020018c60a001516001600160601b03168152602001426001600160401b03168152602001436001600160401b03168152602001846020015160a0015163ffffffff168152602001846020015160c0015163ffffffff168152602001846020015160e0015160ff1681526020018c6101000151815250935083610140015115610b2057610acb46611b98565b610ae85760405163df9969ef60e01b815260040160405180910390fd5b602083015160e0015160ff1649604085018190525f03610b1b57604051639e7e2ddd60e01b815260040160405180910390fd5b610b89565b8686604051610b30929190612da9565b60405180910390208460400181815250508360a001516001600160401b03167fa07bc5e8f00f6065c8727821591c519efd2348e4ff0c26560a85592e85b6f4188888604051610b80929190612db8565b60405180910390a25b604051635437cecf60e11b81526a3a34b2b92fb937baba32b960a91b60048201525f60248201526001600160a01b038b169063a86f9d9e90604401602060405180830381865afa158015610bdf573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c039190612a80565b835151604051635c42d07960e01b81526001600160401b0390911660048201526001600160a01b039190911690635c42d07990602401602060405180830381865afa158015610c54573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c789190612a80565b6001600160a01b039081166040858101829052610180870151602088015191516352c5c56b60e01b8152931660048401526024830152906352c5c56b90604401602060405180830381865afa158015610cd3573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cf79190612df7565b61ffff166101208501526080830151610d1657610d1384611bcb565b94505b5f6040518061012001604052808560800151610d585787604051602001610d3d9190612e10565b60405160208183030381529060405280519060200120610d80565b86604051602001610d699190612e1f565b604051602081830303815290604052805190602001205b81526020015f6001600160a01b031681526020018560800151610da857866101a00151610daa565b5f5b6001600160601b031681528551516001600160401b031660208201526080860151604090910190610ddb5742610de5565b8560200151608001515b6001600160401b031681526020018560800151610e025743610e0c565b8560200151606001515b6001600160401b03168152602001600162ffffff1681526020015f151581526020015f62ffffff168152509050808d5f015f8e60400151875f01515f0151610e549190612fe3565b6001600160401b03166001600160401b031681526020019081526020015f205f820151815f01556020820151816001015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160010160146101000a8154816001600160601b0302191690836001600160601b031602179055506060820151816002015f6101000a8154816001600160401b0302191690836001600160401b0316021790555060808201518160020160086101000a8154816001600160401b0302191690836001600160401b0316021790555060a08201518160020160106101000a8154816001600160401b0302191690836001600160401b0316021790555060c08201518160020160186101000a81548162ffffff021916908362ffffff16021790555060e082015181600201601b6101000a81548160ff02191690831515021790555061010082015181600201601c6101000a81548162ffffff021916908362ffffff1602179055509050508c6005015f015f81819054906101000a90046001600160401b031660010191906101000a8154816001600160401b0302191690836001600160401b0316021790555061102a8d8c86602001515f01518f60a001516001600160601b0316611ccb565b341580159061103857504115155b15611047576110474134611dd1565b83608001511561109b578460a001516001600160401b03167fefe9c6c0b5cbd9c0eed2d1e9c00cfc1a010d6f1aff50f7facd665a639b622b268660405161108e9190612e1f565b60405180910390a261115b565b83602001515f01516001600160a01b03168660c001516001600160401b03167fcda4e564245eb15494bc6da29f6a42e1941cf57f5314bf35bab8a1fca0a9c60a8e60a00151895f6001600160401b038111156110f9576110f96121de565b60405190808252806020026020018201604052801561114257816020015b604080516060810182525f80825260208083018290529282015282525f199092019101816111175790505b5060405161115293929190613010565b60405180910390a35b5050505097509795505050505050565b5f83606001516001600160401b03165f0361118757505f6111d5565b6060840151677fffffffffffffff600191821c169081116111ac5760019150506111d5565b826111bb57600181901c6111bd565b5f5b6111d0826001600160401b0387166130aa565b149150505b9392505050565b6001600160401b03811615611b9257604080516102a0810182525f6101c082018181526101e0830182905261020083018290526102208301829052610240830182905261026083018290526102808301829052825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a08101919091526040805160e08101825260058701546001600160401b038082168352600160401b82048116602080850191825260ff600160801b85048116151586880152600160881b850416606086015261ffff600160901b850416608086015263ffffffff600160a01b85041660a0860152600160c01b909304821660c085015292855291519091169083018190529085015161132991612fe3565b6001600160401b0390811660408084018290525f91825260208881529120908301516002820154919291821691161461137557604051632ec3485560e11b815260040160405180910390fd5b6002810154600160e01b900462ffffff1660a08301819052608083018190525f036113b35760405163d4345b9760e01b815260040160405180910390fd5b6040808301516001600160401b039081165f908152600289016020908152838220608087015162ffffff168352815292902060019081015460e086015291840180519092011690525b81515160208301516001600160401b0391821691161080156114335750826001600160401b031682606001516001600160401b0316105b156118d45784604001516001600160401b031682602001516001600160401b03168161146157611461612d6b565b066001600160401b0390811660408481018290526101208801516020808701805192861692861692909210156101808801525f9384528a905291209051600282015491935082169116146114c857604051632ec3485560e11b815260040160405180910390fd5b6114dc868284604001518560e00151611de0565b62ffffff1660808301819052156118d4576040828101516001600160401b03165f908152600288016020908152828220608086015162ffffff1683529052206005810154600160401b900461ffff1660c084015260048101546001600160a01b03161561154957506118d4565b6101a08301516001600160a01b03166115e657604051635437cecf60e11b81526a3a34b2b92fb937baba32b960a91b60048201525f60248201526001600160a01b0386169063a86f9d9e90604401602060405180830381865afa1580156115b2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115d69190612a80565b6001600160a01b03166101a08401525b6101a08301516020840151604051635c42d07960e01b81526001600160401b0390911660048201525f916001600160a01b031690635c42d07990602401602060405180830381865afa15801561163e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116629190612a80565b60c085015160405163576c3de760e01b815261ffff90911660048201526001600160a01b03919091169063576c3de79060240160c060405180830381865afa1580156116b0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116d491906130c8565b606001516005830154855160c00151919250611702916001600160401b03918216911662ffffff8416611ebe565b61170d5750506118d4565b608084015162ffffff1660a0850152600182015460e085015260038201546001600160a01b0381166101608601819052611759918a9190600160a01b90046001600160601b0316611edb565b836101800151156117d4578361016001516001600160a01b031684602001516001600160401b03167fe5a390d9800811154279af0c1a80d3bdf558ea91f1301e7c6ec3c1ad83e80aef8660e001518760c001516040516117c792919091825261ffff16602082015260400190565b60405180910390a361184a565b8361016001516001600160a01b031684602001516001600160401b03167fdecbd2c61cbda254917d6fd4c980a470701e8f9f1b744f6ad163ca70ca5db2898660e001515f8860c0015160405161184193929190928352602083019190915261ffff16604082015260600190565b60405180910390a35b6118688760c0015160ff1685602001516001600160401b0316611f4c565b156118a757600282015480156118a557610100850181905260208501516001600160401b0316610120860152608085015162ffffff166101408601525b505b50506020820180516001600160401b036001918201811690925260608401805190910190911690526113fc565b60608201516001600160401b031615611b8f57606082015182516020015160408701519101906001600160401b039081169082168161191557611915612d6b565b6001600160401b039190068116604080860182905260058a018054938516600160401b026fffffffffffffffff0000000000000000199094169390931790925560a08501515f91825260208a9052919020600201805462ffffff909216600160e01b0262ffffff60e01b1990921691909117905561010083015115611b8d576101208301516004880180546fffffffffffffffffffffffffffffffff16600160801b6001600160401b039384169081026001600160c01b031691909117600160c01b428516021790915590821614611a595785604001516001600160401b03168361012001516001600160401b031681611a1157611a11612d6b565b066001600160401b031660408481018290526101408501515f92835260208a90529120600201805462ffffff60e01b1916600160e01b62ffffff909316929092029190911790555b604051635437cecf60e11b81526d7369676e616c5f7365727669636560901b60048201525f60248201526001600160a01b0386169063a86f9d9e90604401602060405180830381865afa158015611ab2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ad69190612a80565b86516101208501516101008601516040516313e4299d60e21b81526001600160401b0393841660048201527f73e6d340850343cc6f001515dc593377337c95a6ffe034fe1e844d4dab5da169602482015292909116604483015260648201526001600160a01b039190911690634f90a674906084016020604051808303815f875af1158015611b67573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b8b919061314f565b505b505b50505b50505050565b5f6001821480611ba9575061426882145b80611bb6575062aa36a782145b80611bc55750611bc582611f79565b92915050565b611bd36120a7565b604051806101c00160405280835f015181526020018360200151815260200183604001518152602001836060015181526020017f569e75fc77c1a856f6daaf9e69d8a9566ca34aa47f9133711ce065a571af0cfd5f1b815260200183608001516001600160a01b031681526020018360a001516001600160401b031681526020018360c0015163ffffffff1681526020018360e001516001600160401b031681526020018361010001516001600160401b0316815260200183610120015161ffff1681526020018361014001511515815260200183610160015181526020018361018001516001600160a01b03168152509050919050565b6001600160a01b0382165f908152600685016020526040902054818110611d49576001600160a01b0383165f818152600687016020526040908190208484039055517f85f32beeaff2d0019a8d196f06790c9a652191759c46643311344fd38920423c90611d3c9085815260200190565b60405180910390a2611dca565b611d5284611f90565b6040516323b872dd60e01b81526001600160a01b0385811660048301523060248301526044820185905291909116906323b872dd906064016020604051808303815f875af1158015611da6573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b8f9190613166565b5050505050565b611ddc82825a61200d565b5050565b6001600160401b0382165f908152600285016020908152604080832060018452909152812054829003611e4657506002830154600190600160c01b900462ffffff168110611e41576040516367a1907f60e01b815260040160405180910390fd5b611eb6565b5060028301546001600160401b03165f908152600185016020908152604080832084845290915290205462ffffff168015801590611e985750600284015462ffffff600160c01b909104811690821610155b15611eb6576040516367a1907f60e01b815260040160405180910390fd5b949350505050565b5f80603c8302611ece8686612055565b0142101595945050505050565b6001600160a01b0382165f90815260068401602052604081208054839290611f04908490612d96565b90915550506040518181526001600160a01b038316907f6de6fe586196fa05b73b973026c5fda3968a2933989bff3a0b6bd57644fab6069060200160405180910390a2505050565b5f60018311611f5d57506001611bc5565b60018303838381611f7057611f70612d6b565b06149392505050565b5f617e2c8210158015611bc5575050617e90101590565b604051635437cecf60e11b81526a3a30b4b5b7afba37b5b2b760a91b60048201525f60248201819052906001600160a01b0383169063a86f9d9e90604401602060405180830381865afa158015611fe9573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bc59190612a80565b815f0361201957505050565b61203383838360405180602001604052805f81525061206a565b61205057604051634c67134d60e11b815260040160405180910390fd5b505050565b5f81831161206357816111d5565b5090919050565b5f6001600160a01b03851661209257604051634c67134d60e11b815260040160405180910390fd5b5f5f835160208501878988f195945050505050565b604080516101c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081019190915290565b60408051610280810182525f80825260208083018290528284018290526060808401839052608080850184905260a080860185905260c0860185905260e08601859052610100860185905261012086018590526101408601859052610160860185905261018086018590526101a086018590526101c086018590526101e08601859052610200860185905261022086018590526102408601859052865190810187528481529283018490529482018390528101829052928301529061026082015290565b634e487b7160e01b5f52604160045260245ffd5b60405161014081016001600160401b0381118282101715612215576122156121de565b60405290565b60405161010081016001600160401b0381118282101715612215576122156121de565b604080519081016001600160401b0381118282101715612215576122156121de565b60405160c081016001600160401b0381118282101715612215576122156121de565b604051601f8201601f191681016001600160401b03811182821017156122aa576122aa6121de565b604052919050565b80356001600160401b03811681146122c8575f5ffd5b919050565b803563ffffffff811681146122c8575f5ffd5b6001600160601b03811681146122f4575f5ffd5b50565b80356122c8816122e0565b60ff811681146122f4575f5ffd5b80356122c881612302565b5f60a0828403121561232b575f5ffd5b60405160a081016001600160401b038111828210171561234d5761234d6121de565b604052905080823561235e81612302565b8152602083013561236e81612302565b602082015261237f604084016122cd565b6040820152612390606084016122b2565b60608201526123a1608084016122cd565b60808201525092915050565b5f6101c082840312156123be575f5ffd5b6123c66121f2565b90506123d1826122b2565b81526123df602083016122b2565b60208201526123f0604083016122b2565b6040820152612401606083016122b2565b6060820152612412608083016122cd565b608082015261242360a083016122f7565b60a082015261243460c08301612310565b60c082015261244560e083016122b2565b60e082015261245883610100840161231b565b61010082015261246b6101a083016122b2565b61012082015292915050565b6001600160a01b03811681146122f4575f5ffd5b5f5f83601f84011261249b575f5ffd5b5081356001600160401b038111156124b1575f5ffd5b6020830191508360208285010111156124c8575f5ffd5b9250929050565b5f5f5f5f5f5f5f610240888a0312156124e6575f5ffd5b873596506124f78960208a016123ad565b95506101e088013561250881612477565b94506102008801356001600160401b03811115612523575f5ffd5b61252f8a828b0161248b565b9095509350506102208801356001600160401b0381111561254e575f5ffd5b61255a8a828b0161248b565b989b979a50959850939692959293505050565b805182526020810151602083015260408101516040830152606081015160608301526080810151608083015260a08101516125b360a08401826001600160a01b03169052565b5060c08101516125ce60c08401826001600160401b03169052565b5060e08101516125e660e084018263ffffffff169052565b506101008101516126036101008401826001600160401b03169052565b506101208101516126206101208401826001600160401b03169052565b5061014081015161263861014084018261ffff169052565b5061016081015161264e61016084018215159052565b506101808101516101808301526101a08101516120506101a08401826001600160a01b03169052565b60ff815116825260ff602082015116602083015263ffffffff60408201511660408301526001600160401b03606082015116606083015263ffffffff60808201511660808301525050565b8051825260208101516020830152604081015160408301526060810151606083015260808101516126fe60808401826001600160a01b03169052565b5060a081015161271960a08401826001600160401b03169052565b5060c081015161273160c084018263ffffffff169052565b5060e081015161274c60e08401826001600160401b03169052565b506101008101516127696101008401826001600160401b03169052565b5061012081015161278161012084018261ffff169052565b5061014081015161279761014084018215159052565b506101608101516101608301526101808101516127c06101808401826001600160a01b03169052565b506101a08101516127dd6101a08401826001600160601b03169052565b506101c08101516127fa6101c08401826001600160401b03169052565b506101e08101516128176101e08401826001600160401b03169052565b5061020081015161283161020084018263ffffffff169052565b5061022081015161284b61022084018263ffffffff169052565b5061024081015161286261024084018260ff169052565b50610260810151612050610260840182612677565b6104c08101612886828561256d565b6111d56101c08301846126c2565b5f5f83601f8401126128a4575f5ffd5b5081356001600160401b038111156128ba575f5ffd5b6020830191508360208260051b85010111156124c8575f5ffd5b5f5f5f5f5f5f5f610240888a0312156128eb575f5ffd5b873596506128fc8960208a016123ad565b95506101e088013561290d81612477565b94506102008801356001600160401b03811115612928575f5ffd5b6129348a828b01612894565b9095509350506102208801356001600160401b03811115612953575f5ffd5b61255a8a828b01612894565b604080825283519082018190525f9060208501906060840190835b818110156129a45761298d83855161256d565b602093909301926101c0929092019160010161297a565b5050838103602080860191909152855180835291810192508501905f5b818110156129eb576129d48484516126c2565b6103009390930192602092909201916001016129c1565b50919695505050505050565b634e487b7160e01b5f52603260045260245ffd5b5f5f8335601e19843603018112612a20575f5ffd5b8301803591506001600160401b03821115612a39575f5ffd5b6020019150368190038213156124c8575f5ffd5b634e487b7160e01b5f52601160045260245ffd5b6001600160401b038181168382160190811115611bc557611bc5612a4d565b5f60208284031215612a90575f5ffd5b81516111d581612477565b80356122c881612477565b5f610100828403128015612ab8575f5ffd5b50612ac161221b565b8235612acc81612477565b8152612ada60208401612a9b565b602082015260408381013590820152612af5606084016122b2565b6060820152612b06608084016122b2565b6080820152612b1760a084016122cd565b60a0820152612b2860c084016122cd565b60c0820152612b3960e08401612310565b60e08201529392505050565b5f82601f830112612b54575f5ffd5b81356001600160401b03811115612b6d57612b6d6121de565b612b80601f8201601f1916602001612282565b818152846020838601011115612b94575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f82601f830112612bbf575f5ffd5b81356001600160401b03811115612bd857612bd86121de565b8060051b612be860208201612282565b91825260208185018101929081019086841115612c03575f5ffd5b6020860192505b83831015612c975782356001600160401b03811115612c27575f5ffd5b86016040818903601f19011215612c3c575f5ffd5b612c4461223e565b6020820135612c5281612477565b815260408201356001600160401b03811115612c6c575f5ffd5b612c7b8a602083860101612b45565b6020830152508084525050602082019150602083019250612c0a565b9695505050505050565b5f60208284031215612cb1575f5ffd5b81356001600160401b03811115612cc6575f5ffd5b820160c08185031215612cd7575f5ffd5b612cdf612260565b612ce882612a9b565b8152612cf660208301612a9b565b6020820152604082810135908201526060808301359082015260808201356001600160401b03811115612d27575f5ffd5b612d3386828501612bb0565b60808301525060a08201356001600160401b03811115612d51575f5ffd5b612d5d86828501612b45565b60a083015250949350505050565b634e487b7160e01b5f52601260045260245ffd5b8082028115828204841417611bc557611bc5612a4d565b80820180821115611bc557611bc5612a4d565b818382375f9101908152919050565b60208152816020820152818360408301375f818301604090810191909152601f909201601f19160101919050565b805161ffff811681146122c8575f5ffd5b5f60208284031215612e07575f5ffd5b6111d582612de6565b6101c08101611bc5828461256d565b5f61030082019050825182526020830151602083015260408301516040830152606083015160608301526080830151612e6360808401826001600160a01b03169052565b5060a0830151612e7e60a08401826001600160401b03169052565b5060c0830151612e9660c084018263ffffffff169052565b5060e0830151612eb160e08401826001600160401b03169052565b50610100830151612ece6101008401826001600160401b03169052565b50610120830151612ee661012084018261ffff169052565b50610140830151612efc61014084018215159052565b50610160830151610160830152610180830151612f256101808401826001600160a01b03169052565b506101a0830151612f426101a08401826001600160601b03169052565b506101c0830151612f5f6101c08401826001600160401b03169052565b506101e0830151612f7c6101e08401826001600160401b03169052565b50610200830151612f9661020084018263ffffffff169052565b50610220830151612fb061022084018263ffffffff169052565b50610240830151612fc761024084018260ff169052565b50610260830151612fdc610260840182612677565b5092915050565b5f6001600160401b03831680612ffb57612ffb612d6b565b806001600160401b0384160691505092915050565b5f61020082016001600160601b038616835261302f602084018661256d565b6102006101e084015283519081905260208401906102208401905f5b8181101561309d57835180516001600160a01b031684526020808201516001600160601b0316818601526040918201516001600160401b0316918501919091529093019260609092019160010161304b565b5090979650505050505050565b5f826130b8576130b8612d6b565b500690565b80516122c881612302565b5f60c08284031280156130d9575f5ffd5b506130e2612260565b8251815260208301516130f4816122e0565b60208201526040830151613107816122e0565b6040820152606083015162ffffff81168114613121575f5ffd5b606082015261313260808401612de6565b608082015261314360a084016130bd565b60a08201529392505050565b5f6020828403121561315f575f5ffd5b5051919050565b5f60208284031215613176575f5ffd5b815180151581146111d5575f5ffdfea264697066735822122059b797ed8b30928e2f1f585710724c1c9ead4534f63dae0afbf4fd0cfe46e08364736f6c634300081b0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ 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.