Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
0x613bc461 | 2661843 | 136 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
LibProving
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 "../verifiers/IVerifier.sol"; import "./LibBonds.sol"; import "./LibData.sol"; import "./LibUtils.sol"; import "./LibVerifying.sol"; /// @title LibProving /// @notice A library for handling block contestation and proving in the Taiko /// protocol. /// @custom:security-contact [email protected] library LibProving { using LibMath for uint256; // A struct to get around stack too deep issue and to cache state variables for multiple reads. struct Local { TaikoData.SlotB b; ITierProvider.Tier tier; ITierProvider.Tier minTier; TaikoData.BlockMetadataV2 meta; TaikoData.TierProof proof; bytes32 metaHash; address assignedProver; bytes32 stateRoot; uint96 livenessBond; uint64 slot; uint64 blockId; uint24 tid; bool lastUnpausedAt; bool isTopTier; bool inProvingWindow; bool sameTransition; bool postFork; uint64 proposedAt; bool isSyncBlock; } /// @notice Emitted when a transition is proved. /// @param blockId The block ID. /// @param tran The transition data. /// @param prover The prover's address. /// @param validityBond The validity bond amount. /// @param tier The tier of the proof. event TransitionProved( uint256 indexed blockId, TaikoData.Transition tran, address prover, uint96 validityBond, uint16 tier ); /// @notice Emitted when a transition is proved. /// @param blockId The block ID. /// @param tran The transition data. /// @param prover The prover's address. /// @param validityBond The validity bond amount. /// @param tier The tier of the proof. /// @param proposedIn The L1 block in which a transition is proved. event TransitionProvedV2( uint256 indexed blockId, TaikoData.Transition tran, address prover, uint96 validityBond, uint16 tier, uint64 proposedIn ); /// @notice Emitted when a transition is contested. /// @param blockId The block ID. /// @param tran The transition data. /// @param contester The contester's address. /// @param contestBond The contest bond amount. /// @param tier The tier of the proof. event TransitionContested( uint256 indexed blockId, TaikoData.Transition tran, address contester, uint96 contestBond, uint16 tier ); /// @notice Emitted when a transition is contested. /// @param blockId The block ID. /// @param tran The transition data. /// @param contester The contester's address. /// @param contestBond The contest bond amount. /// @param tier The tier of the proof. /// @param proposedIn The L1 block in which this L2 block is proposed. event TransitionContestedV2( uint256 indexed blockId, TaikoData.Transition tran, address contester, uint96 contestBond, uint16 tier, uint64 proposedIn ); /// @notice Emitted when proving is paused or unpaused. /// @param paused The pause status. event ProvingPaused(bool paused); error L1_ALREADY_CONTESTED(); error L1_ALREADY_PROVED(); error L1_BLOCK_MISMATCH(); error L1_CANNOT_CONTEST(); error L1_DIFF_VERIFIER(); error L1_INVALID_PARAMS(); error L1_INVALID_PAUSE_STATUS(); error L1_INVALID_TIER(); error L1_INVALID_TRANSITION(); error L1_NOT_ASSIGNED_PROVER(); error L1_PROVING_PAUSED(); /// @notice Pauses or unpauses the proving process. /// @param _state Current TaikoData.State. /// @param _pause The pause status. function pauseProving(TaikoData.State storage _state, bool _pause) internal { if (_state.slotB.provingPaused == _pause) revert L1_INVALID_PAUSE_STATUS(); _state.slotB.provingPaused = _pause; if (!_pause) { _state.slotB.lastUnpausedAt = uint64(block.timestamp); } emit ProvingPaused(_pause); } /// @dev Proves or contests multiple Taiko L2 blocks. /// @param _state Current TaikoData.State. /// @param _config Actual TaikoData.Config. /// @param _resolver Address resolver interface. /// @param _blockIds The index of the block to prove. This is also used to /// select the right implementation version. /// @param _inputs An abi-encoded (TaikoData.BlockMetadata, TaikoData.Transition, /// TaikoData.TierProof) tuple. /// @param _batchProof An abi-encoded TaikoData.TierProof that contains the batch/aggregated /// proof for the given blocks. function proveBlocks( TaikoData.State storage _state, TaikoData.Config memory _config, IAddressResolver _resolver, uint64[] calldata _blockIds, bytes[] calldata _inputs, bytes calldata _batchProof ) public { if (_blockIds.length == 0 || _blockIds.length != _inputs.length) { revert L1_INVALID_PARAMS(); } TaikoData.TierProof memory batchProof; if (_batchProof.length != 0) { batchProof = abi.decode(_batchProof, (TaikoData.TierProof)); if (batchProof.tier == 0) revert L1_INVALID_TIER(); } IVerifier.ContextV2[] memory ctxs = new IVerifier.ContextV2[](_blockIds.length); bytes32 batchVerifierName; bool batchVerifierNameSet; // This loop iterates over each block ID in the _blockIds array. // For each block ID, it calls the _proveBlock function to get the context and verifier. for (uint256 i; i < _blockIds.length; ++i) { bytes32 _verifierName; (ctxs[i], _verifierName) = _proveBlock(_state, _config, _resolver, _blockIds[i], _inputs[i], batchProof); // Verify that if batchProof is used, the verifier is the same for all blocks. if (batchProof.tier != 0) { if (!batchVerifierNameSet) { batchVerifierNameSet = true; batchVerifierName = _verifierName; } else if (batchVerifierName != _verifierName) { revert L1_DIFF_VERIFIER(); } } } // If batch verifier name is not empty, verify the batch proof. if (batchVerifierName != "") { IVerifier(_resolver.resolve(batchVerifierName, false)).verifyBatchProof( ctxs, batchProof ); } } /// @dev Proves or contests a single Taiko L2 block. /// @param _state Current TaikoData.State. /// @param _config Actual TaikoData.Config. /// @param _resolver Address resolver interface. /// @param _blockId The index of the block to prove. This is also used to /// select the right implementation version. /// @param _input An abi-encoded (TaikoData.BlockMetadata, TaikoData.Transition, /// TaikoData.TierProof) tuple. function proveBlock( TaikoData.State storage _state, TaikoData.Config memory _config, IAddressResolver _resolver, uint64 _blockId, bytes calldata _input ) public { TaikoData.TierProof memory noBatchProof; _proveBlock(_state, _config, _resolver, _blockId, _input, noBatchProof); } function _proveBlock( TaikoData.State storage _state, TaikoData.Config memory _config, IAddressResolver _resolver, uint64 _blockId, bytes calldata _input, TaikoData.TierProof memory _batchProof ) private returns (IVerifier.ContextV2 memory ctx_, bytes32 verifierName_) { Local memory local; local.b = _state.slotB; local.blockId = _blockId; local.postFork = _blockId >= _config.ontakeForkHeight; if (local.postFork) { if (_batchProof.tier == 0) { // No batch proof is available, each transition is proving using a separate proof. (local.meta, ctx_.tran, local.proof) = abi.decode( _input, (TaikoData.BlockMetadataV2, TaikoData.Transition, TaikoData.TierProof) ); } else { // All transitions are proving using the batch proof. (local.meta, ctx_.tran) = abi.decode(_input, (TaikoData.BlockMetadataV2, TaikoData.Transition)); local.proof = _batchProof; } } else { TaikoData.BlockMetadata memory metaV1; (metaV1, ctx_.tran, local.proof) = abi.decode( _input, (TaikoData.BlockMetadata, TaikoData.Transition, TaikoData.TierProof) ); local.meta = LibData.blockMetadataV1toV2(metaV1); } if (_blockId != local.meta.id) revert LibUtils.L1_INVALID_BLOCK_ID(); // Make sure parentHash is not zero // To contest an existing transition, simply use any non-zero value as // the blockHash and stateRoot. if (ctx_.tran.parentHash == 0 || ctx_.tran.blockHash == 0 || ctx_.tran.stateRoot == 0) { revert L1_INVALID_TRANSITION(); } // Check that the block has been proposed but has not yet been verified. if (local.meta.id <= local.b.lastVerifiedBlockId || local.meta.id >= local.b.numBlocks) { revert LibUtils.L1_INVALID_BLOCK_ID(); } local.slot = local.meta.id % _config.blockRingBufferSize; TaikoData.BlockV2 storage blk = _state.blocks[local.slot]; local.proposedAt = local.postFork ? local.meta.proposedAt : blk.proposedAt; local.isSyncBlock = LibUtils.shouldSyncStateRoot(_config.stateRootSyncInternal, local.blockId); if (local.isSyncBlock) { local.stateRoot = ctx_.tran.stateRoot; } local.assignedProver = blk.assignedProver; if (local.assignedProver == address(0)) { local.assignedProver = local.meta.proposer; } if (!blk.livenessBondReturned) { local.livenessBond = local.meta.livenessBond == 0 ? blk.livenessBond : local.meta.livenessBond; } local.metaHash = blk.metaHash; // Check the integrity of the block data. It's worth noting that in // theory, this check may be skipped, but it's included for added // caution. { bytes32 metaHash = local.postFork ? keccak256(abi.encode(local.meta)) : keccak256(abi.encode(LibData.blockMetadataV2toV1(local.meta))); if (local.metaHash != metaHash) revert L1_BLOCK_MISMATCH(); } // Each transition is uniquely identified by the parentHash, with the // blockHash and stateRoot open for later updates as higher-tier proofs // become available. In cases where a transition with the specified // parentHash does not exist, the transition ID (tid) will be set to 0. TaikoData.TransitionState memory ts; (local.tid, ts) = _fetchOrCreateTransition(_state, blk, ctx_.tran, local); // The new proof must meet or exceed the minimum tier required by the // block or the previous proof; it cannot be on a lower tier. if ( local.proof.tier == 0 || local.proof.tier < local.meta.minTier || local.proof.tier < ts.tier ) { revert L1_INVALID_TIER(); } // Retrieve the tier configurations. If the tier is not supported, the // subsequent action will result in a revert. { ITierRouter tierRouter = ITierRouter(_resolver.resolve(LibStrings.B_TIER_ROUTER, false)); ITierProvider tierProvider = ITierProvider(tierRouter.getProvider(local.blockId)); local.tier = tierProvider.getTier(local.proof.tier); local.minTier = tierProvider.getTier(local.meta.minTier); local.isTopTier = local.tier.contestBond == 0; } local.inProvingWindow = !LibUtils.isPostDeadline({ _tsTimestamp: ts.timestamp, _lastUnpausedAt: local.b.lastUnpausedAt, _windowMinutes: local.minTier.provingWindow }); // Checks if only the assigned prover is permissioned to prove the block. // The assigned prover is granted exclusive permission to prove only the first // transition. if ( !local.isTopTier && ts.contester == address(0) && local.tid == 1 && ts.tier == 0 && local.inProvingWindow ) { if (msg.sender != local.assignedProver) revert L1_NOT_ASSIGNED_PROVER(); } // We must verify the proof, and any failure in proof verification will // result in a revert. // // It's crucial to emphasize that the proof can be assessed in two // potential modes: "proving mode" and "contesting mode." However, the // precise verification logic is defined within each tier's IVerifier // contract implementation. We simply specify to the verifier contract // which mode it should utilize - if the new tier is higher than the // previous tier, we employ the proving mode; otherwise, we employ the // contesting mode (the new tier cannot be lower than the previous tier, // this has been checked above). // // It's obvious that proof verification is entirely decoupled from // Taiko's core protocol. if (local.tier.verifierName != "") { ctx_ = IVerifier.ContextV2({ metaHash: local.metaHash, blobHash: local.meta.blobHash, // Separate msgSender to allow the prover to be any address in the future. prover: msg.sender, msgSender: msg.sender, blockId: local.blockId, isContesting: local.proof.tier == ts.tier && !local.isTopTier, blobUsed: local.meta.blobUsed, tran: ctx_.tran }); verifierName_ = local.tier.verifierName; if (_batchProof.tier == 0) { // In the case of per-transition proof, we verify the proof. IVerifier(_resolver.resolve(local.tier.verifierName, false)).verifyProof( LibData.verifierContextV2toV1(ctx_), ctx_.tran, local.proof ); } } local.sameTransition = local.isSyncBlock ? ctx_.tran.blockHash == ts.blockHash && local.stateRoot == ts.stateRoot : ctx_.tran.blockHash == ts.blockHash; if (local.proof.tier > ts.tier) { // Handles the case when an incoming tier is higher than the current transition's tier. // Reverts when the incoming proof tries to prove the same transition // (L1_ALREADY_PROVED). _overrideWithHigherProof(_state, _resolver, blk, ts, ctx_.tran, local.proof, local); if (local.postFork) { emit TransitionProvedV2({ blockId: local.blockId, tran: ctx_.tran, prover: msg.sender, validityBond: local.tier.validityBond, tier: local.proof.tier, proposedIn: local.meta.proposedIn }); } else { emit TransitionProved({ blockId: local.blockId, tran: ctx_.tran, prover: msg.sender, validityBond: local.tier.validityBond, tier: local.proof.tier }); } } else { // New transition and old transition on the same tier - and if this transaction tries to // prove the same, it reverts if (local.sameTransition) revert L1_ALREADY_PROVED(); if (local.isTopTier) { // The top tier prover re-proves. assert(local.tier.validityBond == 0); assert(ts.validityBond == 0 && ts.contester == address(0)); ts.prover = msg.sender; ts.blockHash = ctx_.tran.blockHash; ts.stateRoot = local.stateRoot; if (local.postFork) { emit TransitionProvedV2({ blockId: local.blockId, tran: ctx_.tran, prover: msg.sender, validityBond: 0, tier: local.proof.tier, proposedIn: local.meta.proposedIn }); } else { emit TransitionProved({ blockId: local.blockId, tran: ctx_.tran, prover: msg.sender, validityBond: 0, tier: local.proof.tier }); } } else { // Contesting but not on the highest tier if (ts.contester != address(0)) revert L1_ALREADY_CONTESTED(); // Making it a non-sliding window, relative when ts.timestamp was registered (or to // lastUnpaused if that one is bigger) if ( LibUtils.isPostDeadline( ts.timestamp, local.b.lastUnpausedAt, local.tier.cooldownWindow ) ) { revert L1_CANNOT_CONTEST(); } // _checkIfContestable(/*_state,*/ tier.cooldownWindow, ts.timestamp); // Burn the contest bond from the prover. LibBonds.debitBond(_state, _resolver, msg.sender, local.tier.contestBond); // We retain the contest bond within the transition, just in // case this configuration is altered to a different value // before the contest is resolved. // // It's worth noting that the previous value of ts.contestBond // doesn't have any significance. ts.contestBond = local.tier.contestBond; ts.contester = msg.sender; if (local.postFork) { emit TransitionContestedV2({ blockId: local.blockId, tran: ctx_.tran, contester: msg.sender, contestBond: local.tier.contestBond, tier: local.proof.tier, proposedIn: local.meta.proposedIn }); } else { emit TransitionContested({ blockId: local.blockId, tran: ctx_.tran, contester: msg.sender, contestBond: local.tier.contestBond, tier: local.proof.tier }); } } } ts.timestamp = uint64(block.timestamp); _state.transitions[local.slot][local.tid] = ts; if ( !_state.slotB.provingPaused && LibUtils.shouldVerifyBlocks(_config, local.meta.id, true) ) { LibVerifying.verifyBlocks(_state, _config, _resolver, _config.maxBlocksToVerify); } } /// @dev Handle the transition initialization logic function _fetchOrCreateTransition( TaikoData.State storage _state, TaikoData.BlockV2 storage _blk, TaikoData.Transition memory _tran, Local memory _local ) private returns (uint24 tid_, TaikoData.TransitionState memory ts_) { tid_ = LibUtils.getTransitionId(_state, _blk, _local.slot, _tran.parentHash); if (tid_ == 0) { // In cases where a transition with the provided parentHash is not // found, we must essentially "create" one and set it to its initial // state. This initial state can be viewed as a special transition // on tier-0. // // Subsequently, we transform this tier-0 transition into a // non-zero-tier transition with a proof. This approach ensures that // the same logic is applicable for both 0-to-non-zero transition // updates and non-zero-to-non-zero transition updates. unchecked { // Unchecked is safe: Not realistic 2**32 different fork choice // per block will be proven and none of them is valid tid_ = _blk.nextTransitionId++; } // Keep in mind that state.transitions are also reusable storage // slots, so it's necessary to reinitialize all transition fields // below. ts_.timestamp = _local.proposedAt; if (tid_ == 1) { // This approach serves as a cost-saving technique for the // majority of blocks, where the first transition is expected to // be the correct one. Writing to `transitions` is more economical // since it resides in the ring buffer, whereas writing to // `transitionIds` is not as cost-effective. ts_.key = _tran.parentHash; // In the case of this first transition, the block's assigned // prover has the privilege to re-prove it, but only when the // assigned prover matches the previous prover. To ensure this, // we establish the transition's prover as the block's assigned // prover. Consequently, when we carry out a 0-to-non-zero // transition update, the previous prover will consistently be // the block's assigned prover. // // While alternative implementations are possible, introducing // such changes would require additional if-else logic. ts_.prover = _local.assignedProver; } else { // Furthermore, we index the transition for future retrieval. // It's worth emphasizing that this mapping for indexing is not // reusable. However, given that the majority of blocks will // only possess one transition — the correct one — we don't need // to be concerned about the cost in this case. // There is no need to initialize ts.key here because it's only used when tid == 1 _state.transitionIds[_local.blockId][_tran.parentHash] = tid_; } } else { // A transition with the provided parentHash has been located. ts_ = _state.transitions[_local.slot][tid_]; } } /// @dev Handles what happens when either the first transition is being proven or there is a /// higher tier proof incoming /// /// Assume Alice is the initial prover, Bob is the contester, and Cindy is the subsequent /// prover. The validity bond `V` is set at 100, and the contestation bond `C` at 500. If Bob /// successfully contests, he receives a reward of 65.625, calculated as 3/4 of 7/8 of 100. Cindy /// receives 21.875, which is 1/4 of 7/8 of 100, while the protocol retains 12.5 as friction. /// Bob's Return on Investment (ROI) is 13.125%, calculated from 65.625 divided by 500. // To establish the expected ROI `r` for valid contestations, where the contestation bond `C` to // validity bond `V` ratio is `C/V = 21/(32*r)`, and if `r` set at 10%, the C/V ratio will be // 6.5625. function _overrideWithHigherProof( TaikoData.State storage _state, IAddressResolver _resolver, TaikoData.BlockV2 storage _blk, TaikoData.TransitionState memory _ts, TaikoData.Transition memory _tran, TaikoData.TierProof memory _proof, Local memory _local ) private { // Higher tier proof overwriting lower tier proof uint256 reward; // reward to the new (current) prover if (_ts.contester != address(0)) { if (_local.sameTransition) { // The contested transition is proven to be valid, contester loses the game reward = _rewardAfterFriction(_ts.contestBond); // We return the validity bond back, but the original prover doesn't get any reward. LibBonds.creditBond(_state, _ts.prover, _ts.validityBond); } else { // The contested transition is proven to be invalid, contester wins the game. // Contester gets 3/4 of reward, the new prover gets 1/4. reward = _rewardAfterFriction(_ts.validityBond) >> 2; unchecked { LibBonds.creditBond(_state, _ts.contester, _ts.contestBond + reward * 3); } } } else { if (_local.sameTransition) revert L1_ALREADY_PROVED(); // The code below will be executed if // - 1) the transition is proved for the fist time, or // - 2) the transition is contested. reward = _rewardAfterFriction(_ts.validityBond); if (_local.livenessBond != 0) { // After the first proof, the block's liveness bond will always be reset to 0. // This means liveness bond will be handled only once for any given block. _blk.livenessBond = 0; _blk.livenessBondReturned = true; if (_returnLivenessBond(_local, _proof.data)) { if (_local.assignedProver == msg.sender) { unchecked { reward += _local.livenessBond; } } else { LibBonds.creditBond(_state, _local.assignedProver, _local.livenessBond); } } else { // Reward a majority of liveness bond to the actual prover unchecked { reward += _rewardAfterFriction(_local.livenessBond); } } } } unchecked { if (reward > _local.tier.validityBond) { LibBonds.creditBond(_state, msg.sender, reward - _local.tier.validityBond); } else if (reward < _local.tier.validityBond) { LibBonds.debitBond(_state, _resolver, msg.sender, _local.tier.validityBond - reward); } } _ts.validityBond = _local.tier.validityBond; _ts.contester = address(0); _ts.prover = msg.sender; _ts.tier = _proof.tier; if (!_local.sameTransition) { _ts.blockHash = _tran.blockHash; _ts.stateRoot = _local.stateRoot; } } /// @dev Returns the reward after applying 12.5% friction. function _rewardAfterFriction(uint256 _amount) private pure returns (uint256) { return (_amount * 7) >> 3; } /// @dev Returns if the liveness bond shall be returned. function _returnLivenessBond( Local memory _local, bytes memory _proofData ) private pure returns (bool) { return _local.inProvingWindow && _local.tid == 1 || _local.isTopTier && _proofData.length == 32 && bytes32(_proofData) == LibStrings.H_RETURN_LIVENESS_BOND; } }
// 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; 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 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 // 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; /// @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 ABI
API[{"inputs":[],"name":"L1_ALREADY_CONTESTED","type":"error"},{"inputs":[],"name":"L1_ALREADY_PROVED","type":"error"},{"inputs":[],"name":"L1_BLOCK_MISMATCH","type":"error"},{"inputs":[],"name":"L1_BLOCK_MISMATCH","type":"error"},{"inputs":[],"name":"L1_CANNOT_CONTEST","type":"error"},{"inputs":[],"name":"L1_DIFF_VERIFIER","type":"error"},{"inputs":[],"name":"L1_INVALID_BLOCK_ID","type":"error"},{"inputs":[],"name":"L1_INVALID_PARAMS","type":"error"},{"inputs":[],"name":"L1_INVALID_PAUSE_STATUS","type":"error"},{"inputs":[],"name":"L1_INVALID_TIER","type":"error"},{"inputs":[],"name":"L1_INVALID_TRANSITION","type":"error"},{"inputs":[],"name":"L1_NOT_ASSIGNED_PROVER","type":"error"},{"inputs":[],"name":"L1_PROVING_PAUSED","type":"error"},{"inputs":[],"name":"L1_TRANSITION_ID_ZERO","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":"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":false,"internalType":"bool","name":"paused","type":"bool"}],"name":"ProvingPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"blockId","type":"uint256"},{"components":[{"internalType":"bytes32","name":"parentHash","type":"bytes32"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"bytes32","name":"stateRoot","type":"bytes32"},{"internalType":"bytes32","name":"graffiti","type":"bytes32"}],"indexed":false,"internalType":"struct TaikoData.Transition","name":"tran","type":"tuple"},{"indexed":false,"internalType":"address","name":"contester","type":"address"},{"indexed":false,"internalType":"uint96","name":"contestBond","type":"uint96"},{"indexed":false,"internalType":"uint16","name":"tier","type":"uint16"}],"name":"TransitionContested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"blockId","type":"uint256"},{"components":[{"internalType":"bytes32","name":"parentHash","type":"bytes32"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"bytes32","name":"stateRoot","type":"bytes32"},{"internalType":"bytes32","name":"graffiti","type":"bytes32"}],"indexed":false,"internalType":"struct TaikoData.Transition","name":"tran","type":"tuple"},{"indexed":false,"internalType":"address","name":"contester","type":"address"},{"indexed":false,"internalType":"uint96","name":"contestBond","type":"uint96"},{"indexed":false,"internalType":"uint16","name":"tier","type":"uint16"},{"indexed":false,"internalType":"uint64","name":"proposedIn","type":"uint64"}],"name":"TransitionContestedV2","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"blockId","type":"uint256"},{"components":[{"internalType":"bytes32","name":"parentHash","type":"bytes32"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"bytes32","name":"stateRoot","type":"bytes32"},{"internalType":"bytes32","name":"graffiti","type":"bytes32"}],"indexed":false,"internalType":"struct TaikoData.Transition","name":"tran","type":"tuple"},{"indexed":false,"internalType":"address","name":"prover","type":"address"},{"indexed":false,"internalType":"uint96","name":"validityBond","type":"uint96"},{"indexed":false,"internalType":"uint16","name":"tier","type":"uint16"}],"name":"TransitionProved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"blockId","type":"uint256"},{"components":[{"internalType":"bytes32","name":"parentHash","type":"bytes32"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"bytes32","name":"stateRoot","type":"bytes32"},{"internalType":"bytes32","name":"graffiti","type":"bytes32"}],"indexed":false,"internalType":"struct TaikoData.Transition","name":"tran","type":"tuple"},{"indexed":false,"internalType":"address","name":"prover","type":"address"},{"indexed":false,"internalType":"uint96","name":"validityBond","type":"uint96"},{"indexed":false,"internalType":"uint16","name":"tier","type":"uint16"},{"indexed":false,"internalType":"uint64","name":"proposedIn","type":"uint64"}],"name":"TransitionProvedV2","type":"event"}]
Contract Creation Code
613bc4610034600b8282823980515f1a607314602857634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040526004361061003f575f3560e01c8063805f2d2e146100435780638609dced14610064575b5f5ffd5b81801561004e575f5ffd5b5061006261005d366004612dd3565b610083565b005b81801561006f575f5ffd5b5061006261007e366004612ea2565b6102fc565b8415806100905750848314155b156100ae576040516336c7c68960e01b815260040160405180910390fd5b604080518082019091525f81526060602082015281156100fc576100d482840184612fec565b805190915061ffff165f036100fc57604051631a32f51360e01b815260040160405180910390fd5b5f866001600160401b0381111561011557610115612a7f565b60405190808252806020026020018201604052801561014e57816020015b61013b612724565b8152602001906001900390816101335790505b5090505f5f5f5b8981101561021e575f6101b58f8f8f8f8f878181106101765761017661301d565b905060200201602081019061018b9190613031565b8e8e8881811061019d5761019d61301d565b90506020028101906101af919061304a565b8c61032a565b8684815181106101c7576101c761301d565b602002602001018193508290525050855f015161ffff165f1461021557826101f55760019250809350610215565b80841461021557604051632794eda760e11b815260040160405180910390fd5b50600101610155565b5081156102ed57604051635437cecf60e11b8152600481018390525f60248201526001600160a01b038c169063a86f9d9e90604401602060405180830381865afa15801561026e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610292919061308c565b6001600160a01b0316637103b6da84866040518363ffffffff1660e01b81526004016102bf9291906130ed565b5f604051808303815f87803b1580156102d6575f5ffd5b505af11580156102e8573d5f5f3e3d5ffd5b505050505b50505050505050505050505050565b604080518082019091525f81526060602082015261031f8787878787878761032a565b505050505050505050565b610332612724565b5f61033b6127a5565b6040805160e08101825260058c01546001600160401b038082168352600160401b82048116602084015260ff600160801b83048116151594840194909452600160881b8204909316606083015261ffff600160901b820416608083015263ffffffff600160a01b82041660a0830152600160c01b9004821660c0820152825287811661014083018190526101208b015190911611801561020083015261042957835161ffff165f03610407576103f3858701876133cb565b608084015260e08501526060820152610459565b61041385870187613429565b60e0850152606082015260808101849052610459565b6104316128f5565b61043d8688018861345e565b608085015260e08601529050610452816112d5565b6060830152505b806060015160a001516001600160401b0316876001600160401b03161461049357604051638a1c400f60e01b815260040160405180910390fd5b60e08301515115806104ab575060e083015160200151155b806104bc575060e083015160400151155b156104da576040516317eddea160e11b815260040160405180910390fd5b805f0151602001516001600160401b0316816060015160a001516001600160401b03161115806105215750805151606082015160a001516001600160401b03918216911610155b1561053f57604051638a1c400f60e01b815260040160405180910390fd5b8860400151816060015160a001516105579190613591565b6001600160401b031661012082018190525f90815260208b905260409020610200820151610599576002810154600160401b90046001600160401b03166105a4565b81606001516101c001515b6001600160401b0390811661022084015260c08b01516101408401516105d09260ff9092169116611443565b1580156102408401526105ec5760e08085015160400151908301525b60018101546001600160a01b031660c0830181905261061e57606082015161018001516001600160a01b031660c08301525b6002810154600160d81b900460ff1661067e5760608201516101a001516001600160601b0316156106585781606001516101a0015161066e565b6001810154600160a01b90046001600160601b03165b6001600160601b03166101008301525b805460a08301526102008201515f906106c95761069e8360600151611472565b6040516020016106ae91906135be565b604051602081830303815290604052805190602001206106f5565b82606001516040516020016106de91906136d7565b604051602081830303815290604052805190602001205b9050808360a001511461071b57604051632ec3485560e11b815260040160405180910390fd5b50610724612968565b6107348c838760e0015186611572565b62ffffff90911661016085015260808401515190915061ffff16158061077157508260600151610120015161ffff1683608001515f015161ffff16105b8061078f575080610100015161ffff1683608001515f015161ffff16105b156107ad57604051631a32f51360e01b815260040160405180910390fd5b604051635437cecf60e11b81526a3a34b2b92fb937baba32b960a91b60048201525f60248201819052906001600160a01b038c169063a86f9d9e90604401602060405180830381865afa158015610806573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061082a919061308c565b610140850151604051635c42d07960e01b81526001600160401b0390911660048201529091505f906001600160a01b03831690635c42d07990602401602060405180830381865afa158015610881573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108a5919061308c565b60808601515160405163576c3de760e01b815261ffff90911660048201529091506001600160a01b0382169063576c3de79060240160c060405180830381865afa1580156108f5573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061091991906138f0565b60208601526060850151610120015160405163576c3de760e01b815261ffff90911660048201526001600160a01b0382169063576c3de79060240160c060405180830381865afa15801561096f573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061099391906138f0565b6040808701829052602087015101516001600160601b0316156101a087015260e0840151865160c001516080909201516109e194506001600160401b03918216935091169061ffff1661171a565b156101c08401526101a0830151158015610a06575060a08101516001600160a01b0316155b8015610a1c575082610160015162ffffff166001145b8015610a2f575061010081015161ffff16155b8015610a3d5750826101c001515b15610a78578260c001516001600160a01b0316336001600160a01b031614610a7857604051632185a2ad60e21b815260040160405180910390fd5b60208301515115610cb5576040518061010001604052808460a0015181526020018460600151604001518152602001336001600160a01b031681526020018461014001516001600160401b0316815260200182610100015161ffff1685608001515f015161ffff16148015610af05750846101a00151155b151581526060808601516101400151151560208084019190915233604084015260e0909801519101529483015151865190945061ffff165f03610cb557602083015151604051635437cecf60e11b815260048101919091525f60248201526001600160a01b038b169063a86f9d9e90604401602060405180830381865afa158015610b7d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ba1919061308c565b6001600160a01b03166321e89968610c5f876040805160e0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091526040518060e00160405280835f015181526020018360200151815260200183604001516001600160a01b0316815260200183606001516001600160401b031681526020018360800151151581526020018360a00151151581526020018360c001516001600160a01b03168152509050919050565b8760e0015186608001516040518463ffffffff1660e01b8152600401610c8793929190613977565b5f604051808303815f87803b158015610c9e575f5ffd5b505af1158015610cb0573d5f5f3e3d5ffd5b505050505b826102400151610cd35780602001518560e001516020015114610cf5565b80602001518560e0015160200151148015610cf5575080604001518360e00151145b15156101e084015261010081015160808401515161ffff91821691161115610dff57610d2e8c8b84848960e00151886080015189611739565b82610200015115610da8578261014001516001600160401b03167f11a9112e5724f21b226e2535a95a264a80c9626ed4c0923faaa9fa65564674888660e001513386602001516020015187608001515f015188606001516101e00151604051610d9b959493929190613a19565b60405180910390a26110d6565b8261014001516001600160401b03167fc195e4be3b936845492b8be4b1cf604db687a4d79ad84d979499c136f8e6701f8660e001513386602001516020015187608001515f0151604051610d9b9493929190613a7e565b826101e0015115610e2357604051639d49773160e01b815260040160405180910390fd5b826101a0015115610f505760208084015101516001600160601b031615610e4c57610e4c613ad1565b60808101516001600160601b0316158015610e72575060a08101516001600160a01b0316155b610e7e57610e7e613ad1565b33606082015260e08086015160209081015190830152830151604082015261020083015115610f01578261014001516001600160401b03167f11a9112e5724f21b226e2535a95a264a80c9626ed4c0923faaa9fa65564674888660e00151335f87608001515f015188606001516101e00151604051610d9b959493929190613a19565b8261014001516001600160401b03167fc195e4be3b936845492b8be4b1cf604db687a4d79ad84d979499c136f8e6701f8660e00151335f87608001515f0151604051610d9b9493929190613a7e565b60a08101516001600160a01b031615610f7c576040516382ef169960e01b815260040160405180910390fd5b610fb18160e001516001600160401b0316845f015160c001516001600160401b031685602001516060015162ffffff1661171a565b15610fcf5760405163378b1eff60e21b815260040160405180910390fd5b610fec8c8b338660200151604001516001600160601b031661198e565b6020830151604001516001600160601b031660c08201523360a082015261020083015115611076578261014001516001600160401b03167f53b2379d5e9bcacdfe56b4a51c3fd92ebfff4b1e8e8638f7f7e85163260a6f998660e001513386602001516040015187608001515f015188606001516101e00151604051610d9b959493929190613a19565b8261014001516001600160401b03167fb4c0a86c1ff239277697775b1e91d3375fd3a5ef6b345aa4e2f6001c890558f68660e001513386602001516040015187608001515f01516040516110cd9493929190613a7e565b60405180910390a25b428160e001906001600160401b031690816001600160401b031681525050808c6002015f8561012001516001600160401b03166001600160401b031681526020019081526020015f205f85610160015162ffffff1663ffffffff1681526020019081526020015f205f820151815f015560208201518160010155604082015181600201556060820151816003015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060808201518160030160146101000a8154816001600160601b0302191690836001600160601b0316021790555060a0820151816004015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c08201518160040160146101000a8154816001600160601b0302191690836001600160601b0316021790555060e0820151816005015f6101000a8154816001600160401b0302191690836001600160401b031602179055506101008201518160050160086101000a81548161ffff021916908361ffff16021790555061012082015181600501600a6101000a81548160ff021916908360ff1602179055509050508b6005015f0160109054906101000a900460ff161580156112b157506112b18b846060015160a001516001611a96565b156112c6576112c68c8c8c8e60600151611b05565b50505097509795505050505050565b6112dd6129bb565b604051806102800160405280835f015181526020018360200151815260200183604001518152602001836060015181526020018360a001516001600160a01b031681526020018360c001516001600160401b031681526020018360e0015163ffffffff1681526020018361010001516001600160401b031681526020018361012001516001600160401b0316815260200183610140015161ffff168152602001836101600151151581526020018361018001518152602001836101a001516001600160a01b031681526020015f6001600160601b031681526020015f6001600160401b031681526020015f6001600160401b031681526020015f63ffffffff1681526020015f63ffffffff1681526020015f60ff1681526020016040518060a001604052805f60ff1681526020015f60ff1681526020015f63ffffffff1681526020015f6001600160401b031681526020015f63ffffffff168152508152509050919050565b5f600183116114545750600161146c565b600183038383816114675761146761357d565b061490505b92915050565b61147a6128f5565b604051806101c00160405280835f015181526020018360200151815260200183604001518152602001836060015181526020017f569e75fc77c1a856f6daaf9e69d8a9566ca34aa47f9133711ce065a571af0cfd5f1b815260200183608001516001600160a01b031681526020018360a001516001600160401b031681526020018360c0015163ffffffff1681526020018360e001516001600160401b031681526020018361010001516001600160401b0316815260200183610120015161ffff1681526020018361014001511515815260200183610160015181526020018361018001516001600160a01b03168152509050919050565b5f61157b612968565b61158f8686856101200151875f01516124be565b91508162ffffff165f0361164557600285018054600162ffffff600160c01b80840482168381019092160262ffffff60c01b19909316929092179092556102208501516001600160401b031660e08401529250829003611605578351815260c08301516001600160a01b03166060820152611711565b6101408301516001600160401b03165f9081526001870160209081526040808320875184529091529020805462ffffff191662ffffff8416179055611711565b50610120828101516001600160401b039081165f90815260028881016020908152604080842062ffffff8816855282529283902083516101408101855281548152600182015492810192909252918201549281019290925260038101546001600160a01b038082166060850152600160a01b918290046001600160601b039081166080860152600484015491821660a08601529190041660c08301526005015491821660e0820152600160401b820461ffff16610100820152600160501b90910460ff16918101919091525b94509492505050565b5f80603c830261172a868661259c565b014210159150505b9392505050565b60a08401515f906001600160a01b0316156117cf57816101e00151156117925761176f8560c001516001600160601b03166125b1565b905061178d88866060015187608001516001600160601b03166125c7565b6118c3565b60026117aa86608001516001600160601b03166125b1565b901c905061178d888660a00151836003028860c001516001600160601b0316016125c7565b816101e00151156117f357604051639d49773160e01b815260040160405180910390fd5b61180985608001516001600160601b03166125b1565b90508161010001516001600160601b03165f146118c3576001860180546001600160a01b0316905560028601805460ff60d81b1916600160d81b1790556020830151611856908390612638565b156118aa57336001600160a01b03168260c001516001600160a01b03160361188d576101008201516001600160601b0316016118c3565b61178d888360c001518461010001516001600160601b03166125c7565b6118c18261010001516001600160601b03166125b1565b015b8160200151602001516001600160601b03168111156118ff576118fa88338460200151602001516001600160601b031684036125c7565b611937565b8160200151602001516001600160601b031681101561193757611937888833848660200151602001516001600160601b03160361198e565b60208083015101516001600160601b031660808601525f60a0860152336060860152825161ffff166101008601526101e0820151611984576020808501519086015260e082015160408601525b5050505050505050565b6001600160a01b0382165f908152600685016020526040902054818110611a0c576001600160a01b0383165f818152600687016020526040908190208484039055517f85f32beeaff2d0019a8d196f06790c9a652191759c46643311344fd38920423c906119ff9085815260200190565b60405180910390a2611a8f565b611a15846126a7565b6040516323b872dd60e01b81526001600160a01b0385811660048301523060248301526044820185905291909116906323b872dd906064016020604051808303815f875af1158015611a69573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a8d9190613ae5565b505b5050505050565b5f83606001516001600160401b03165f03611ab257505f611732565b6060840151677fffffffffffffff600191821c16908111611ad7576001915050611732565b82611ae657600181901c611ae8565b5f5b611afb826001600160401b038716613b00565b1495945050505050565b6001600160401b038116156124b857604080516102a0810182525f6101c082018181526101e0830182905261020083018290526102208301829052610240830182905261026083018290526102808301829052825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a08101919091526040805160e08101825260058701546001600160401b038082168352600160401b82048116602080850191825260ff600160801b85048116151586880152600160881b850416606086015261ffff600160901b850416608086015263ffffffff600160a01b85041660a0860152600160c01b909304821660c0850152928552915190911690830181905290850151611c5291613591565b6001600160401b0390811660408084018290525f918252602088815291209083015160028201549192918216911614611c9e57604051632ec3485560e11b815260040160405180910390fd5b6002810154600160e01b900462ffffff1660a08301819052608083018190525f03611cdc5760405163d4345b9760e01b815260040160405180910390fd5b6040808301516001600160401b039081165f908152600289016020908152838220608087015162ffffff168352815292902060019081015460e086015291840180519092011690525b81515160208301516001600160401b039182169116108015611d5c5750826001600160401b031682606001516001600160401b0316105b156121fd5784604001516001600160401b031682602001516001600160401b031681611d8a57611d8a61357d565b066001600160401b0390811660408481018290526101208801516020808701805192861692861692909210156101808801525f9384528a90529120905160028201549193508216911614611df157604051632ec3485560e11b815260040160405180910390fd5b611e05868284604001518560e001516124be565b62ffffff1660808301819052156121fd576040828101516001600160401b03165f908152600288016020908152828220608086015162ffffff1683529052206005810154600160401b900461ffff1660c084015260048101546001600160a01b031615611e7257506121fd565b6101a08301516001600160a01b0316611f0f57604051635437cecf60e11b81526a3a34b2b92fb937baba32b960a91b60048201525f60248201526001600160a01b0386169063a86f9d9e90604401602060405180830381865afa158015611edb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611eff919061308c565b6001600160a01b03166101a08401525b6101a08301516020840151604051635c42d07960e01b81526001600160401b0390911660048201525f916001600160a01b031690635c42d07990602401602060405180830381865afa158015611f67573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f8b919061308c565b60c085015160405163576c3de760e01b815261ffff90911660048201526001600160a01b03919091169063576c3de79060240160c060405180830381865afa158015611fd9573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ffd91906138f0565b606001516005830154855160c0015191925061202b916001600160401b03918216911662ffffff841661171a565b6120365750506121fd565b608084015162ffffff1660a0850152600182015460e085015260038201546001600160a01b0381166101608601819052612082918a9190600160a01b90046001600160601b03166125c7565b836101800151156120fd578361016001516001600160a01b031684602001516001600160401b03167fe5a390d9800811154279af0c1a80d3bdf558ea91f1301e7c6ec3c1ad83e80aef8660e001518760c001516040516120f092919091825261ffff16602082015260400190565b60405180910390a3612173565b8361016001516001600160a01b031684602001516001600160401b03167fdecbd2c61cbda254917d6fd4c980a470701e8f9f1b744f6ad163ca70ca5db2898660e001515f8860c0015160405161216a93929190928352602083019190915261ffff16604082015260600190565b60405180910390a35b6121918760c0015160ff1685602001516001600160401b0316611443565b156121d057600282015480156121ce57610100850181905260208501516001600160401b0316610120860152608085015162ffffff166101408601525b505b50506020820180516001600160401b03600191820181169092526060840180519091019091169052611d25565b60608201516001600160401b031615611a8d57606082015182516020015160408701519101906001600160401b039081169082168161223e5761223e61357d565b6001600160401b039190068116604080860182905260058a018054938516600160401b026fffffffffffffffff0000000000000000199094169390931790925560a08501515f91825260208a9052919020600201805462ffffff909216600160e01b0262ffffff60e01b19909216919091179055610100830151156124b4576101208301516004880180546fffffffffffffffffffffffffffffffff16600160801b6001600160401b039384169081026001600160c01b031691909117600160c01b4285160217909155908216146123825785604001516001600160401b03168361012001516001600160401b03168161233a5761233a61357d565b066001600160401b031660408481018290526101408501515f92835260208a90529120600201805462ffffff60e01b1916600160e01b62ffffff909316929092029190911790555b604051635437cecf60e11b81526d7369676e616c5f7365727669636560901b60048201525f60248201526001600160a01b0386169063a86f9d9e90604401602060405180830381865afa1580156123db573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123ff919061308c565b86516101208501516101008601516040516313e4299d60e21b81526001600160401b0393841660048201527f73e6d340850343cc6f001515dc593377337c95a6ffe034fe1e844d4dab5da169602482015292909116604483015260648201526001600160a01b039190911690634f90a674906084016020604051808303815f875af1158015612490573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119849190613b13565b5050505b50505050565b6001600160401b0382165f90815260028501602090815260408083206001845290915281205482900361252457506002830154600190600160c01b900462ffffff16811061251f576040516367a1907f60e01b815260040160405180910390fd5b612594565b5060028301546001600160401b03165f908152600185016020908152604080832084845290915290205462ffffff1680158015906125765750600284015462ffffff600160c01b909104811690821610155b15612594576040516367a1907f60e01b815260040160405180910390fd5b949350505050565b5f8183116125aa5781611732565b5090919050565b5f60036125bf836007613b3e565b901c92915050565b6001600160a01b0382165f908152600684016020526040812080548392906125f0908490613b55565b90915550506040518181526001600160a01b038316907f6de6fe586196fa05b73b973026c5fda3968a2933989bff3a0b6bd57644fab6069060200160405180910390a2505050565b5f826101c001518015612655575082610160015162ffffff166001145b806117325750826101a00151801561266e575081516020145b801561173257507f20d34d7a20a139f9be221ba2163925c0c86ed02d34033f288f010d23a63ef4b761269f83613b68565b149392505050565b604051635437cecf60e11b81526a3a30b4b5b7afba37b5b2b760a91b60048201525f60248201819052906001600160a01b0383169063a86f9d9e90604401602060405180830381865afa158015612700573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061146c919061308c565b6040518061010001604052805f81526020015f81526020015f6001600160a01b031681526020015f6001600160401b031681526020015f151581526020015f151581526020015f6001600160a01b031681526020016127a060405180608001604052805f81526020015f81526020015f81526020015f81525090565b905290565b6040805161034081019091525f610260820181815261028083018290526102a083018290526102c083018290526102e083018290526103008301829052610320830191909152819081526040805160c0810182525f8082526020828101829052928201819052606082018190526080820181905260a082015291019081526040805160c0810182525f8082526020828101829052928201819052606082018190526080820181905260a082015291019081526020016128626129bb565b815260200161288760405180604001604052805f61ffff168152602001606081525090565b81525f6020820181905260408201819052606082018190526080820181905260a0820181905260c0820181905260e08201819052610100820181905261012082018190526101408201819052610160820181905261018082018190526101a082018190526101c09091015290565b604080516101c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081019190915290565b60408051610140810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081019190915290565b60408051610280810182525f80825260208083018290528284018290526060808401839052608080850184905260a080860185905260c0860185905260e08601859052610100860185905261012086018590526101408601859052610160860185905261018086018590526101a086018590526101c086018590526101e08601859052610200860185905261022086018590526102408601859052865190810187528481529283018490529482018390528101829052928301529061026082015290565b634e487b7160e01b5f52604160045260245ffd5b60405161014081016001600160401b0381118282101715612ab657612ab6612a7f565b60405290565b604080519081016001600160401b0381118282101715612ab657612ab6612a7f565b60405161028081016001600160401b0381118282101715612ab657612ab6612a7f565b6040516101c081016001600160401b0381118282101715612ab657612ab6612a7f565b60405160c081016001600160401b0381118282101715612ab657612ab6612a7f565b604051601f8201601f191681016001600160401b0381118282101715612b6e57612b6e612a7f565b604052919050565b80356001600160401b0381168114612b8c575f5ffd5b919050565b803563ffffffff81168114612b8c575f5ffd5b6001600160601b0381168114612bb8575f5ffd5b50565b8035612b8c81612ba4565b60ff81168114612bb8575f5ffd5b8035612b8c81612bc6565b5f60a08284031215612bef575f5ffd5b60405160a081016001600160401b0381118282101715612c1157612c11612a7f565b6040529050808235612c2281612bc6565b81526020830135612c3281612bc6565b6020820152612c4360408401612b91565b6040820152612c5460608401612b76565b6060820152612c6560808401612b91565b60808201525092915050565b5f6101c08284031215612c82575f5ffd5b612c8a612a93565b9050612c9582612b76565b8152612ca360208301612b76565b6020820152612cb460408301612b76565b6040820152612cc560608301612b76565b6060820152612cd660808301612b91565b6080820152612ce760a08301612bbb565b60a0820152612cf860c08301612bd4565b60c0820152612d0960e08301612b76565b60e0820152612d1c836101008401612bdf565b610100820152612d2f6101a08301612b76565b61012082015292915050565b6001600160a01b0381168114612bb8575f5ffd5b5f5f83601f840112612d5f575f5ffd5b5081356001600160401b03811115612d75575f5ffd5b6020830191508360208260051b8501011115612d8f575f5ffd5b9250929050565b5f5f83601f840112612da6575f5ffd5b5081356001600160401b03811115612dbc575f5ffd5b602083019150836020828501011115612d8f575f5ffd5b5f5f5f5f5f5f5f5f5f6102608a8c031215612dec575f5ffd5b89359850612dfd8b60208c01612c71565b97506101e08a0135612e0e81612d3b565b96506102008a01356001600160401b03811115612e29575f5ffd5b612e358c828d01612d4f565b9097509550506102208a01356001600160401b03811115612e54575f5ffd5b612e608c828d01612d4f565b9095509350506102408a01356001600160401b03811115612e7f575f5ffd5b612e8b8c828d01612d96565b915080935050809150509295985092959850929598565b5f5f5f5f5f5f6102408789031215612eb8575f5ffd5b86359550612ec98860208901612c71565b94506101e0870135612eda81612d3b565b9350612ee96102008801612b76565b92506102208701356001600160401b03811115612f04575f5ffd5b612f1089828a01612d96565b979a9699509497509295939492505050565b61ffff81168114612bb8575f5ffd5b8035612b8c81612f22565b5f60408284031215612f4c575f5ffd5b612f54612abc565b90508135612f6181612f22565b815260208201356001600160401b03811115612f7b575f5ffd5b8201601f81018413612f8b575f5ffd5b80356001600160401b03811115612fa457612fa4612a7f565b612fb7601f8201601f1916602001612b46565b818152856020838501011115612fcb575f5ffd5b816020840160208301375f6020838301015280602085015250505092915050565b5f60208284031215612ffc575f5ffd5b81356001600160401b03811115613011575f5ffd5b61259484828501612f3c565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215613041575f5ffd5b61173282612b76565b5f5f8335601e1984360301811261305f575f5ffd5b8301803591506001600160401b03821115613078575f5ffd5b602001915036819003821315612d8f575f5ffd5b5f6020828403121561309c575f5ffd5b815161173281612d3b565b61ffff81511682525f60208201516040602085015280518060408601528060208301606087015e5f606082870101526060601f19601f8301168601019250505092915050565b604080825283519082018190525f9060208501906060840190835b818110156131c6578351805184526020810151602085015260018060a01b0360408201511660408501526001600160401b03606082015116606085015260808101511515608085015260a081015161316460a086018215159052565b5060c081015161317f60c08601826001600160a01b03169052565b5060e0908101518051918501919091526020808201516101008601526040820151610120860152606090910151610140850152939093019261016090920191600101613108565b505083810360208501526131da81866130a7565b9695505050505050565b8035612b8c81612d3b565b8015158114612bb8575f5ffd5b8035612b8c816131ef565b5f6103008284031215613218575f5ffd5b613220612ade565b823581526020808401359082015260408084013590820152606080840135908201529050613250608083016131e4565b608082015261326160a08301612b76565b60a082015261327260c08301612b91565b60c082015261328360e08301612b76565b60e08201526132956101008301612b76565b6101008201526132a86101208301612f31565b6101208201526132bb61014083016131fc565b61014082015261016082810135908201526132d961018083016131e4565b6101808201526132ec6101a08301612bbb565b6101a08201526132ff6101c08301612b76565b6101c08201526133126101e08301612b76565b6101e08201526133256102008301612b91565b6102008201526133386102208301612b91565b61022082015261334b6102408301612bd4565b61024082015261335f836102608401612bdf565b61026082015292915050565b5f6080828403121561337b575f5ffd5b604051608081016001600160401b038111828210171561339d5761339d612a7f565b6040908152833582526020808501359083015283810135908201526060928301359281019290925250919050565b5f5f5f6103a084860312156133de575f5ffd5b6133e88585613207565b92506133f885610300860161336b565b91506103808401356001600160401b03811115613413575f5ffd5b61341f86828701612f3c565b9150509250925092565b5f5f610380838503121561343b575f5ffd5b6134458484613207565b915061345584610300850161336b565b90509250929050565b5f5f5f838503610260811215613472575f5ffd5b6101c0811215613480575f5ffd5b50613489612b01565b84358152602080860135908201526040808601359082015260608086013590820152608080860135908201526134c160a086016131e4565b60a08201526134d260c08601612b76565b60c08201526134e360e08601612b91565b60e08201526134f56101008601612b76565b6101008201526135086101208601612b76565b61012082015261351b6101408601612f31565b61014082015261352e61016086016131fc565b610160820152610180858101359082015261354c6101a086016131e4565b6101a08201529250613562856101c0860161336b565b91506102408401356001600160401b03811115613413575f5ffd5b634e487b7160e01b5f52601260045260245ffd5b5f6001600160401b038316806135a9576135a961357d565b806001600160401b0384160691505092915050565b5f6101c082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015161360c60a08401826001600160a01b03169052565b5060c083015161362760c08401826001600160401b03169052565b5060e083015161363f60e084018263ffffffff169052565b5061010083015161365c6101008401826001600160401b03169052565b506101208301516136796101208401826001600160401b03169052565b5061014083015161369161014084018261ffff169052565b506101608301516136a761016084018215159052565b506101808301516101808301526101a08301516136d06101a08401826001600160a01b03169052565b5092915050565b5f6103008201905082518252602083015160208301526040830151604083015260608301516060830152608083015161371b60808401826001600160a01b03169052565b5060a083015161373660a08401826001600160401b03169052565b5060c083015161374e60c084018263ffffffff169052565b5060e083015161376960e08401826001600160401b03169052565b506101008301516137866101008401826001600160401b03169052565b5061012083015161379e61012084018261ffff169052565b506101408301516137b461014084018215159052565b506101608301516101608301526101808301516137dd6101808401826001600160a01b03169052565b506101a08301516137fa6101a08401826001600160601b03169052565b506101c08301516138176101c08401826001600160401b03169052565b506101e08301516138346101e08401826001600160401b03169052565b5061020083015161384e61020084018263ffffffff169052565b5061022083015161386861022084018263ffffffff169052565b5061024083015161387f61024084018260ff169052565b506102608301516136d061026084018260ff815116825260ff602082015116602083015263ffffffff60408201511660408301526001600160401b03606082015116606083015263ffffffff60808201511660808301525050565b8051612b8c81612f22565b8051612b8c81612bc6565b5f60c0828403128015613901575f5ffd5b5061390a612b24565b82518152602083015161391c81612ba4565b6020820152604083015161392f81612ba4565b6040820152606083015162ffffff81168114613949575f5ffd5b606082015261395a608084016138da565b608082015261396b60a084016138e5565b60a08201529392505050565b83518152602080850151818301526040808601516001600160a01b03908116828501526060808801516001600160401b03168186015260808089015115159086015260a08089015115159086015260c08089015190921691850191909152855160e0850152918501516101008401528401516101208301528301516101408201526101806101608201525f613a106101808301846130a7565b95945050505050565b855181526020808701519082015260408087015190820152606095860151958101959095526001600160a01b039390931660808501526001600160601b039190911660a084015261ffff1660c08301526001600160401b031660e08201526101000190565b845181526020808601519082015260408086015190820152606094850151948101949094526001600160a01b039290921660808401526001600160601b031660a083015261ffff1660c082015260e00190565b634e487b7160e01b5f52600160045260245ffd5b5f60208284031215613af5575f5ffd5b8151611732816131ef565b5f82613b0e57613b0e61357d565b500690565b5f60208284031215613b23575f5ffd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761146c5761146c613b2a565b8082018082111561146c5761146c613b2a565b80516020808301519190811015613b88575f198160200360031b1b821691505b5091905056fea26469706673582212207e4542707e1bd26337b310f97fd1eef74a365ef6ef6e0c012fd98c6193ab288b64736f6c634300081b0033
Deployed Bytecode
0x737a3d8e58d9010945fd7541665ea384c7287db6cb301460806040526004361061003f575f3560e01c8063805f2d2e146100435780638609dced14610064575b5f5ffd5b81801561004e575f5ffd5b5061006261005d366004612dd3565b610083565b005b81801561006f575f5ffd5b5061006261007e366004612ea2565b6102fc565b8415806100905750848314155b156100ae576040516336c7c68960e01b815260040160405180910390fd5b604080518082019091525f81526060602082015281156100fc576100d482840184612fec565b805190915061ffff165f036100fc57604051631a32f51360e01b815260040160405180910390fd5b5f866001600160401b0381111561011557610115612a7f565b60405190808252806020026020018201604052801561014e57816020015b61013b612724565b8152602001906001900390816101335790505b5090505f5f5f5b8981101561021e575f6101b58f8f8f8f8f878181106101765761017661301d565b905060200201602081019061018b9190613031565b8e8e8881811061019d5761019d61301d565b90506020028101906101af919061304a565b8c61032a565b8684815181106101c7576101c761301d565b602002602001018193508290525050855f015161ffff165f1461021557826101f55760019250809350610215565b80841461021557604051632794eda760e11b815260040160405180910390fd5b50600101610155565b5081156102ed57604051635437cecf60e11b8152600481018390525f60248201526001600160a01b038c169063a86f9d9e90604401602060405180830381865afa15801561026e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610292919061308c565b6001600160a01b0316637103b6da84866040518363ffffffff1660e01b81526004016102bf9291906130ed565b5f604051808303815f87803b1580156102d6575f5ffd5b505af11580156102e8573d5f5f3e3d5ffd5b505050505b50505050505050505050505050565b604080518082019091525f81526060602082015261031f8787878787878761032a565b505050505050505050565b610332612724565b5f61033b6127a5565b6040805160e08101825260058c01546001600160401b038082168352600160401b82048116602084015260ff600160801b83048116151594840194909452600160881b8204909316606083015261ffff600160901b820416608083015263ffffffff600160a01b82041660a0830152600160c01b9004821660c0820152825287811661014083018190526101208b015190911611801561020083015261042957835161ffff165f03610407576103f3858701876133cb565b608084015260e08501526060820152610459565b61041385870187613429565b60e0850152606082015260808101849052610459565b6104316128f5565b61043d8688018861345e565b608085015260e08601529050610452816112d5565b6060830152505b806060015160a001516001600160401b0316876001600160401b03161461049357604051638a1c400f60e01b815260040160405180910390fd5b60e08301515115806104ab575060e083015160200151155b806104bc575060e083015160400151155b156104da576040516317eddea160e11b815260040160405180910390fd5b805f0151602001516001600160401b0316816060015160a001516001600160401b03161115806105215750805151606082015160a001516001600160401b03918216911610155b1561053f57604051638a1c400f60e01b815260040160405180910390fd5b8860400151816060015160a001516105579190613591565b6001600160401b031661012082018190525f90815260208b905260409020610200820151610599576002810154600160401b90046001600160401b03166105a4565b81606001516101c001515b6001600160401b0390811661022084015260c08b01516101408401516105d09260ff9092169116611443565b1580156102408401526105ec5760e08085015160400151908301525b60018101546001600160a01b031660c0830181905261061e57606082015161018001516001600160a01b031660c08301525b6002810154600160d81b900460ff1661067e5760608201516101a001516001600160601b0316156106585781606001516101a0015161066e565b6001810154600160a01b90046001600160601b03165b6001600160601b03166101008301525b805460a08301526102008201515f906106c95761069e8360600151611472565b6040516020016106ae91906135be565b604051602081830303815290604052805190602001206106f5565b82606001516040516020016106de91906136d7565b604051602081830303815290604052805190602001205b9050808360a001511461071b57604051632ec3485560e11b815260040160405180910390fd5b50610724612968565b6107348c838760e0015186611572565b62ffffff90911661016085015260808401515190915061ffff16158061077157508260600151610120015161ffff1683608001515f015161ffff16105b8061078f575080610100015161ffff1683608001515f015161ffff16105b156107ad57604051631a32f51360e01b815260040160405180910390fd5b604051635437cecf60e11b81526a3a34b2b92fb937baba32b960a91b60048201525f60248201819052906001600160a01b038c169063a86f9d9e90604401602060405180830381865afa158015610806573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061082a919061308c565b610140850151604051635c42d07960e01b81526001600160401b0390911660048201529091505f906001600160a01b03831690635c42d07990602401602060405180830381865afa158015610881573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108a5919061308c565b60808601515160405163576c3de760e01b815261ffff90911660048201529091506001600160a01b0382169063576c3de79060240160c060405180830381865afa1580156108f5573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061091991906138f0565b60208601526060850151610120015160405163576c3de760e01b815261ffff90911660048201526001600160a01b0382169063576c3de79060240160c060405180830381865afa15801561096f573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061099391906138f0565b6040808701829052602087015101516001600160601b0316156101a087015260e0840151865160c001516080909201516109e194506001600160401b03918216935091169061ffff1661171a565b156101c08401526101a0830151158015610a06575060a08101516001600160a01b0316155b8015610a1c575082610160015162ffffff166001145b8015610a2f575061010081015161ffff16155b8015610a3d5750826101c001515b15610a78578260c001516001600160a01b0316336001600160a01b031614610a7857604051632185a2ad60e21b815260040160405180910390fd5b60208301515115610cb5576040518061010001604052808460a0015181526020018460600151604001518152602001336001600160a01b031681526020018461014001516001600160401b0316815260200182610100015161ffff1685608001515f015161ffff16148015610af05750846101a00151155b151581526060808601516101400151151560208084019190915233604084015260e0909801519101529483015151865190945061ffff165f03610cb557602083015151604051635437cecf60e11b815260048101919091525f60248201526001600160a01b038b169063a86f9d9e90604401602060405180830381865afa158015610b7d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ba1919061308c565b6001600160a01b03166321e89968610c5f876040805160e0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091526040518060e00160405280835f015181526020018360200151815260200183604001516001600160a01b0316815260200183606001516001600160401b031681526020018360800151151581526020018360a00151151581526020018360c001516001600160a01b03168152509050919050565b8760e0015186608001516040518463ffffffff1660e01b8152600401610c8793929190613977565b5f604051808303815f87803b158015610c9e575f5ffd5b505af1158015610cb0573d5f5f3e3d5ffd5b505050505b826102400151610cd35780602001518560e001516020015114610cf5565b80602001518560e0015160200151148015610cf5575080604001518360e00151145b15156101e084015261010081015160808401515161ffff91821691161115610dff57610d2e8c8b84848960e00151886080015189611739565b82610200015115610da8578261014001516001600160401b03167f11a9112e5724f21b226e2535a95a264a80c9626ed4c0923faaa9fa65564674888660e001513386602001516020015187608001515f015188606001516101e00151604051610d9b959493929190613a19565b60405180910390a26110d6565b8261014001516001600160401b03167fc195e4be3b936845492b8be4b1cf604db687a4d79ad84d979499c136f8e6701f8660e001513386602001516020015187608001515f0151604051610d9b9493929190613a7e565b826101e0015115610e2357604051639d49773160e01b815260040160405180910390fd5b826101a0015115610f505760208084015101516001600160601b031615610e4c57610e4c613ad1565b60808101516001600160601b0316158015610e72575060a08101516001600160a01b0316155b610e7e57610e7e613ad1565b33606082015260e08086015160209081015190830152830151604082015261020083015115610f01578261014001516001600160401b03167f11a9112e5724f21b226e2535a95a264a80c9626ed4c0923faaa9fa65564674888660e00151335f87608001515f015188606001516101e00151604051610d9b959493929190613a19565b8261014001516001600160401b03167fc195e4be3b936845492b8be4b1cf604db687a4d79ad84d979499c136f8e6701f8660e00151335f87608001515f0151604051610d9b9493929190613a7e565b60a08101516001600160a01b031615610f7c576040516382ef169960e01b815260040160405180910390fd5b610fb18160e001516001600160401b0316845f015160c001516001600160401b031685602001516060015162ffffff1661171a565b15610fcf5760405163378b1eff60e21b815260040160405180910390fd5b610fec8c8b338660200151604001516001600160601b031661198e565b6020830151604001516001600160601b031660c08201523360a082015261020083015115611076578261014001516001600160401b03167f53b2379d5e9bcacdfe56b4a51c3fd92ebfff4b1e8e8638f7f7e85163260a6f998660e001513386602001516040015187608001515f015188606001516101e00151604051610d9b959493929190613a19565b8261014001516001600160401b03167fb4c0a86c1ff239277697775b1e91d3375fd3a5ef6b345aa4e2f6001c890558f68660e001513386602001516040015187608001515f01516040516110cd9493929190613a7e565b60405180910390a25b428160e001906001600160401b031690816001600160401b031681525050808c6002015f8561012001516001600160401b03166001600160401b031681526020019081526020015f205f85610160015162ffffff1663ffffffff1681526020019081526020015f205f820151815f015560208201518160010155604082015181600201556060820151816003015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060808201518160030160146101000a8154816001600160601b0302191690836001600160601b0316021790555060a0820151816004015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c08201518160040160146101000a8154816001600160601b0302191690836001600160601b0316021790555060e0820151816005015f6101000a8154816001600160401b0302191690836001600160401b031602179055506101008201518160050160086101000a81548161ffff021916908361ffff16021790555061012082015181600501600a6101000a81548160ff021916908360ff1602179055509050508b6005015f0160109054906101000a900460ff161580156112b157506112b18b846060015160a001516001611a96565b156112c6576112c68c8c8c8e60600151611b05565b50505097509795505050505050565b6112dd6129bb565b604051806102800160405280835f015181526020018360200151815260200183604001518152602001836060015181526020018360a001516001600160a01b031681526020018360c001516001600160401b031681526020018360e0015163ffffffff1681526020018361010001516001600160401b031681526020018361012001516001600160401b0316815260200183610140015161ffff168152602001836101600151151581526020018361018001518152602001836101a001516001600160a01b031681526020015f6001600160601b031681526020015f6001600160401b031681526020015f6001600160401b031681526020015f63ffffffff1681526020015f63ffffffff1681526020015f60ff1681526020016040518060a001604052805f60ff1681526020015f60ff1681526020015f63ffffffff1681526020015f6001600160401b031681526020015f63ffffffff168152508152509050919050565b5f600183116114545750600161146c565b600183038383816114675761146761357d565b061490505b92915050565b61147a6128f5565b604051806101c00160405280835f015181526020018360200151815260200183604001518152602001836060015181526020017f569e75fc77c1a856f6daaf9e69d8a9566ca34aa47f9133711ce065a571af0cfd5f1b815260200183608001516001600160a01b031681526020018360a001516001600160401b031681526020018360c0015163ffffffff1681526020018360e001516001600160401b031681526020018361010001516001600160401b0316815260200183610120015161ffff1681526020018361014001511515815260200183610160015181526020018361018001516001600160a01b03168152509050919050565b5f61157b612968565b61158f8686856101200151875f01516124be565b91508162ffffff165f0361164557600285018054600162ffffff600160c01b80840482168381019092160262ffffff60c01b19909316929092179092556102208501516001600160401b031660e08401529250829003611605578351815260c08301516001600160a01b03166060820152611711565b6101408301516001600160401b03165f9081526001870160209081526040808320875184529091529020805462ffffff191662ffffff8416179055611711565b50610120828101516001600160401b039081165f90815260028881016020908152604080842062ffffff8816855282529283902083516101408101855281548152600182015492810192909252918201549281019290925260038101546001600160a01b038082166060850152600160a01b918290046001600160601b039081166080860152600484015491821660a08601529190041660c08301526005015491821660e0820152600160401b820461ffff16610100820152600160501b90910460ff16918101919091525b94509492505050565b5f80603c830261172a868661259c565b014210159150505b9392505050565b60a08401515f906001600160a01b0316156117cf57816101e00151156117925761176f8560c001516001600160601b03166125b1565b905061178d88866060015187608001516001600160601b03166125c7565b6118c3565b60026117aa86608001516001600160601b03166125b1565b901c905061178d888660a00151836003028860c001516001600160601b0316016125c7565b816101e00151156117f357604051639d49773160e01b815260040160405180910390fd5b61180985608001516001600160601b03166125b1565b90508161010001516001600160601b03165f146118c3576001860180546001600160a01b0316905560028601805460ff60d81b1916600160d81b1790556020830151611856908390612638565b156118aa57336001600160a01b03168260c001516001600160a01b03160361188d576101008201516001600160601b0316016118c3565b61178d888360c001518461010001516001600160601b03166125c7565b6118c18261010001516001600160601b03166125b1565b015b8160200151602001516001600160601b03168111156118ff576118fa88338460200151602001516001600160601b031684036125c7565b611937565b8160200151602001516001600160601b031681101561193757611937888833848660200151602001516001600160601b03160361198e565b60208083015101516001600160601b031660808601525f60a0860152336060860152825161ffff166101008601526101e0820151611984576020808501519086015260e082015160408601525b5050505050505050565b6001600160a01b0382165f908152600685016020526040902054818110611a0c576001600160a01b0383165f818152600687016020526040908190208484039055517f85f32beeaff2d0019a8d196f06790c9a652191759c46643311344fd38920423c906119ff9085815260200190565b60405180910390a2611a8f565b611a15846126a7565b6040516323b872dd60e01b81526001600160a01b0385811660048301523060248301526044820185905291909116906323b872dd906064016020604051808303815f875af1158015611a69573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a8d9190613ae5565b505b5050505050565b5f83606001516001600160401b03165f03611ab257505f611732565b6060840151677fffffffffffffff600191821c16908111611ad7576001915050611732565b82611ae657600181901c611ae8565b5f5b611afb826001600160401b038716613b00565b1495945050505050565b6001600160401b038116156124b857604080516102a0810182525f6101c082018181526101e0830182905261020083018290526102208301829052610240830182905261026083018290526102808301829052825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a08101919091526040805160e08101825260058701546001600160401b038082168352600160401b82048116602080850191825260ff600160801b85048116151586880152600160881b850416606086015261ffff600160901b850416608086015263ffffffff600160a01b85041660a0860152600160c01b909304821660c0850152928552915190911690830181905290850151611c5291613591565b6001600160401b0390811660408084018290525f918252602088815291209083015160028201549192918216911614611c9e57604051632ec3485560e11b815260040160405180910390fd5b6002810154600160e01b900462ffffff1660a08301819052608083018190525f03611cdc5760405163d4345b9760e01b815260040160405180910390fd5b6040808301516001600160401b039081165f908152600289016020908152838220608087015162ffffff168352815292902060019081015460e086015291840180519092011690525b81515160208301516001600160401b039182169116108015611d5c5750826001600160401b031682606001516001600160401b0316105b156121fd5784604001516001600160401b031682602001516001600160401b031681611d8a57611d8a61357d565b066001600160401b0390811660408481018290526101208801516020808701805192861692861692909210156101808801525f9384528a90529120905160028201549193508216911614611df157604051632ec3485560e11b815260040160405180910390fd5b611e05868284604001518560e001516124be565b62ffffff1660808301819052156121fd576040828101516001600160401b03165f908152600288016020908152828220608086015162ffffff1683529052206005810154600160401b900461ffff1660c084015260048101546001600160a01b031615611e7257506121fd565b6101a08301516001600160a01b0316611f0f57604051635437cecf60e11b81526a3a34b2b92fb937baba32b960a91b60048201525f60248201526001600160a01b0386169063a86f9d9e90604401602060405180830381865afa158015611edb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611eff919061308c565b6001600160a01b03166101a08401525b6101a08301516020840151604051635c42d07960e01b81526001600160401b0390911660048201525f916001600160a01b031690635c42d07990602401602060405180830381865afa158015611f67573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f8b919061308c565b60c085015160405163576c3de760e01b815261ffff90911660048201526001600160a01b03919091169063576c3de79060240160c060405180830381865afa158015611fd9573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ffd91906138f0565b606001516005830154855160c0015191925061202b916001600160401b03918216911662ffffff841661171a565b6120365750506121fd565b608084015162ffffff1660a0850152600182015460e085015260038201546001600160a01b0381166101608601819052612082918a9190600160a01b90046001600160601b03166125c7565b836101800151156120fd578361016001516001600160a01b031684602001516001600160401b03167fe5a390d9800811154279af0c1a80d3bdf558ea91f1301e7c6ec3c1ad83e80aef8660e001518760c001516040516120f092919091825261ffff16602082015260400190565b60405180910390a3612173565b8361016001516001600160a01b031684602001516001600160401b03167fdecbd2c61cbda254917d6fd4c980a470701e8f9f1b744f6ad163ca70ca5db2898660e001515f8860c0015160405161216a93929190928352602083019190915261ffff16604082015260600190565b60405180910390a35b6121918760c0015160ff1685602001516001600160401b0316611443565b156121d057600282015480156121ce57610100850181905260208501516001600160401b0316610120860152608085015162ffffff166101408601525b505b50506020820180516001600160401b03600191820181169092526060840180519091019091169052611d25565b60608201516001600160401b031615611a8d57606082015182516020015160408701519101906001600160401b039081169082168161223e5761223e61357d565b6001600160401b039190068116604080860182905260058a018054938516600160401b026fffffffffffffffff0000000000000000199094169390931790925560a08501515f91825260208a9052919020600201805462ffffff909216600160e01b0262ffffff60e01b19909216919091179055610100830151156124b4576101208301516004880180546fffffffffffffffffffffffffffffffff16600160801b6001600160401b039384169081026001600160c01b031691909117600160c01b4285160217909155908216146123825785604001516001600160401b03168361012001516001600160401b03168161233a5761233a61357d565b066001600160401b031660408481018290526101408501515f92835260208a90529120600201805462ffffff60e01b1916600160e01b62ffffff909316929092029190911790555b604051635437cecf60e11b81526d7369676e616c5f7365727669636560901b60048201525f60248201526001600160a01b0386169063a86f9d9e90604401602060405180830381865afa1580156123db573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123ff919061308c565b86516101208501516101008601516040516313e4299d60e21b81526001600160401b0393841660048201527f73e6d340850343cc6f001515dc593377337c95a6ffe034fe1e844d4dab5da169602482015292909116604483015260648201526001600160a01b039190911690634f90a674906084016020604051808303815f875af1158015612490573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119849190613b13565b5050505b50505050565b6001600160401b0382165f90815260028501602090815260408083206001845290915281205482900361252457506002830154600190600160c01b900462ffffff16811061251f576040516367a1907f60e01b815260040160405180910390fd5b612594565b5060028301546001600160401b03165f908152600185016020908152604080832084845290915290205462ffffff1680158015906125765750600284015462ffffff600160c01b909104811690821610155b15612594576040516367a1907f60e01b815260040160405180910390fd5b949350505050565b5f8183116125aa5781611732565b5090919050565b5f60036125bf836007613b3e565b901c92915050565b6001600160a01b0382165f908152600684016020526040812080548392906125f0908490613b55565b90915550506040518181526001600160a01b038316907f6de6fe586196fa05b73b973026c5fda3968a2933989bff3a0b6bd57644fab6069060200160405180910390a2505050565b5f826101c001518015612655575082610160015162ffffff166001145b806117325750826101a00151801561266e575081516020145b801561173257507f20d34d7a20a139f9be221ba2163925c0c86ed02d34033f288f010d23a63ef4b761269f83613b68565b149392505050565b604051635437cecf60e11b81526a3a30b4b5b7afba37b5b2b760a91b60048201525f60248201819052906001600160a01b0383169063a86f9d9e90604401602060405180830381865afa158015612700573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061146c919061308c565b6040518061010001604052805f81526020015f81526020015f6001600160a01b031681526020015f6001600160401b031681526020015f151581526020015f151581526020015f6001600160a01b031681526020016127a060405180608001604052805f81526020015f81526020015f81526020015f81525090565b905290565b6040805161034081019091525f610260820181815261028083018290526102a083018290526102c083018290526102e083018290526103008301829052610320830191909152819081526040805160c0810182525f8082526020828101829052928201819052606082018190526080820181905260a082015291019081526040805160c0810182525f8082526020828101829052928201819052606082018190526080820181905260a082015291019081526020016128626129bb565b815260200161288760405180604001604052805f61ffff168152602001606081525090565b81525f6020820181905260408201819052606082018190526080820181905260a0820181905260c0820181905260e08201819052610100820181905261012082018190526101408201819052610160820181905261018082018190526101a082018190526101c09091015290565b604080516101c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081019190915290565b60408051610140810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081019190915290565b60408051610280810182525f80825260208083018290528284018290526060808401839052608080850184905260a080860185905260c0860185905260e08601859052610100860185905261012086018590526101408601859052610160860185905261018086018590526101a086018590526101c086018590526101e08601859052610200860185905261022086018590526102408601859052865190810187528481529283018490529482018390528101829052928301529061026082015290565b634e487b7160e01b5f52604160045260245ffd5b60405161014081016001600160401b0381118282101715612ab657612ab6612a7f565b60405290565b604080519081016001600160401b0381118282101715612ab657612ab6612a7f565b60405161028081016001600160401b0381118282101715612ab657612ab6612a7f565b6040516101c081016001600160401b0381118282101715612ab657612ab6612a7f565b60405160c081016001600160401b0381118282101715612ab657612ab6612a7f565b604051601f8201601f191681016001600160401b0381118282101715612b6e57612b6e612a7f565b604052919050565b80356001600160401b0381168114612b8c575f5ffd5b919050565b803563ffffffff81168114612b8c575f5ffd5b6001600160601b0381168114612bb8575f5ffd5b50565b8035612b8c81612ba4565b60ff81168114612bb8575f5ffd5b8035612b8c81612bc6565b5f60a08284031215612bef575f5ffd5b60405160a081016001600160401b0381118282101715612c1157612c11612a7f565b6040529050808235612c2281612bc6565b81526020830135612c3281612bc6565b6020820152612c4360408401612b91565b6040820152612c5460608401612b76565b6060820152612c6560808401612b91565b60808201525092915050565b5f6101c08284031215612c82575f5ffd5b612c8a612a93565b9050612c9582612b76565b8152612ca360208301612b76565b6020820152612cb460408301612b76565b6040820152612cc560608301612b76565b6060820152612cd660808301612b91565b6080820152612ce760a08301612bbb565b60a0820152612cf860c08301612bd4565b60c0820152612d0960e08301612b76565b60e0820152612d1c836101008401612bdf565b610100820152612d2f6101a08301612b76565b61012082015292915050565b6001600160a01b0381168114612bb8575f5ffd5b5f5f83601f840112612d5f575f5ffd5b5081356001600160401b03811115612d75575f5ffd5b6020830191508360208260051b8501011115612d8f575f5ffd5b9250929050565b5f5f83601f840112612da6575f5ffd5b5081356001600160401b03811115612dbc575f5ffd5b602083019150836020828501011115612d8f575f5ffd5b5f5f5f5f5f5f5f5f5f6102608a8c031215612dec575f5ffd5b89359850612dfd8b60208c01612c71565b97506101e08a0135612e0e81612d3b565b96506102008a01356001600160401b03811115612e29575f5ffd5b612e358c828d01612d4f565b9097509550506102208a01356001600160401b03811115612e54575f5ffd5b612e608c828d01612d4f565b9095509350506102408a01356001600160401b03811115612e7f575f5ffd5b612e8b8c828d01612d96565b915080935050809150509295985092959850929598565b5f5f5f5f5f5f6102408789031215612eb8575f5ffd5b86359550612ec98860208901612c71565b94506101e0870135612eda81612d3b565b9350612ee96102008801612b76565b92506102208701356001600160401b03811115612f04575f5ffd5b612f1089828a01612d96565b979a9699509497509295939492505050565b61ffff81168114612bb8575f5ffd5b8035612b8c81612f22565b5f60408284031215612f4c575f5ffd5b612f54612abc565b90508135612f6181612f22565b815260208201356001600160401b03811115612f7b575f5ffd5b8201601f81018413612f8b575f5ffd5b80356001600160401b03811115612fa457612fa4612a7f565b612fb7601f8201601f1916602001612b46565b818152856020838501011115612fcb575f5ffd5b816020840160208301375f6020838301015280602085015250505092915050565b5f60208284031215612ffc575f5ffd5b81356001600160401b03811115613011575f5ffd5b61259484828501612f3c565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215613041575f5ffd5b61173282612b76565b5f5f8335601e1984360301811261305f575f5ffd5b8301803591506001600160401b03821115613078575f5ffd5b602001915036819003821315612d8f575f5ffd5b5f6020828403121561309c575f5ffd5b815161173281612d3b565b61ffff81511682525f60208201516040602085015280518060408601528060208301606087015e5f606082870101526060601f19601f8301168601019250505092915050565b604080825283519082018190525f9060208501906060840190835b818110156131c6578351805184526020810151602085015260018060a01b0360408201511660408501526001600160401b03606082015116606085015260808101511515608085015260a081015161316460a086018215159052565b5060c081015161317f60c08601826001600160a01b03169052565b5060e0908101518051918501919091526020808201516101008601526040820151610120860152606090910151610140850152939093019261016090920191600101613108565b505083810360208501526131da81866130a7565b9695505050505050565b8035612b8c81612d3b565b8015158114612bb8575f5ffd5b8035612b8c816131ef565b5f6103008284031215613218575f5ffd5b613220612ade565b823581526020808401359082015260408084013590820152606080840135908201529050613250608083016131e4565b608082015261326160a08301612b76565b60a082015261327260c08301612b91565b60c082015261328360e08301612b76565b60e08201526132956101008301612b76565b6101008201526132a86101208301612f31565b6101208201526132bb61014083016131fc565b61014082015261016082810135908201526132d961018083016131e4565b6101808201526132ec6101a08301612bbb565b6101a08201526132ff6101c08301612b76565b6101c08201526133126101e08301612b76565b6101e08201526133256102008301612b91565b6102008201526133386102208301612b91565b61022082015261334b6102408301612bd4565b61024082015261335f836102608401612bdf565b61026082015292915050565b5f6080828403121561337b575f5ffd5b604051608081016001600160401b038111828210171561339d5761339d612a7f565b6040908152833582526020808501359083015283810135908201526060928301359281019290925250919050565b5f5f5f6103a084860312156133de575f5ffd5b6133e88585613207565b92506133f885610300860161336b565b91506103808401356001600160401b03811115613413575f5ffd5b61341f86828701612f3c565b9150509250925092565b5f5f610380838503121561343b575f5ffd5b6134458484613207565b915061345584610300850161336b565b90509250929050565b5f5f5f838503610260811215613472575f5ffd5b6101c0811215613480575f5ffd5b50613489612b01565b84358152602080860135908201526040808601359082015260608086013590820152608080860135908201526134c160a086016131e4565b60a08201526134d260c08601612b76565b60c08201526134e360e08601612b91565b60e08201526134f56101008601612b76565b6101008201526135086101208601612b76565b61012082015261351b6101408601612f31565b61014082015261352e61016086016131fc565b610160820152610180858101359082015261354c6101a086016131e4565b6101a08201529250613562856101c0860161336b565b91506102408401356001600160401b03811115613413575f5ffd5b634e487b7160e01b5f52601260045260245ffd5b5f6001600160401b038316806135a9576135a961357d565b806001600160401b0384160691505092915050565b5f6101c082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015161360c60a08401826001600160a01b03169052565b5060c083015161362760c08401826001600160401b03169052565b5060e083015161363f60e084018263ffffffff169052565b5061010083015161365c6101008401826001600160401b03169052565b506101208301516136796101208401826001600160401b03169052565b5061014083015161369161014084018261ffff169052565b506101608301516136a761016084018215159052565b506101808301516101808301526101a08301516136d06101a08401826001600160a01b03169052565b5092915050565b5f6103008201905082518252602083015160208301526040830151604083015260608301516060830152608083015161371b60808401826001600160a01b03169052565b5060a083015161373660a08401826001600160401b03169052565b5060c083015161374e60c084018263ffffffff169052565b5060e083015161376960e08401826001600160401b03169052565b506101008301516137866101008401826001600160401b03169052565b5061012083015161379e61012084018261ffff169052565b506101408301516137b461014084018215159052565b506101608301516101608301526101808301516137dd6101808401826001600160a01b03169052565b506101a08301516137fa6101a08401826001600160601b03169052565b506101c08301516138176101c08401826001600160401b03169052565b506101e08301516138346101e08401826001600160401b03169052565b5061020083015161384e61020084018263ffffffff169052565b5061022083015161386861022084018263ffffffff169052565b5061024083015161387f61024084018260ff169052565b506102608301516136d061026084018260ff815116825260ff602082015116602083015263ffffffff60408201511660408301526001600160401b03606082015116606083015263ffffffff60808201511660808301525050565b8051612b8c81612f22565b8051612b8c81612bc6565b5f60c0828403128015613901575f5ffd5b5061390a612b24565b82518152602083015161391c81612ba4565b6020820152604083015161392f81612ba4565b6040820152606083015162ffffff81168114613949575f5ffd5b606082015261395a608084016138da565b608082015261396b60a084016138e5565b60a08201529392505050565b83518152602080850151818301526040808601516001600160a01b03908116828501526060808801516001600160401b03168186015260808089015115159086015260a08089015115159086015260c08089015190921691850191909152855160e0850152918501516101008401528401516101208301528301516101408201526101806101608201525f613a106101808301846130a7565b95945050505050565b855181526020808701519082015260408087015190820152606095860151958101959095526001600160a01b039390931660808501526001600160601b039190911660a084015261ffff1660c08301526001600160401b031660e08201526101000190565b845181526020808601519082015260408086015190820152606094850151948101949094526001600160a01b039290921660808401526001600160601b031660a083015261ffff1660c082015260e00190565b634e487b7160e01b5f52600160045260245ffd5b5f60208284031215613af5575f5ffd5b8151611732816131ef565b5f82613b0e57613b0e61357d565b500690565b5f60208284031215613b23575f5ffd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761146c5761146c613b2a565b8082018082111561146c5761146c613b2a565b80516020808301519190811015613b88575f198160200360031b1b821691505b5091905056fea26469706673582212207e4542707e1bd26337b310f97fd1eef74a365ef6ef6e0c012fd98c6193ab288b64736f6c634300081b0033
Loading...
Loading
Loading...
Loading
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.