Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
FaultDisputeGame
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 999999 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.15; import { FixedPointMathLib } from "solady/utils/FixedPointMathLib.sol"; import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol"; import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol"; import { IFaultDisputeGame } from "src/dispute/interfaces/IFaultDisputeGame.sol"; import { IInitializable } from "src/dispute/interfaces/IInitializable.sol"; import { IBigStepper, IPreimageOracle } from "src/dispute/interfaces/IBigStepper.sol"; import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistry.sol"; import { Clone } from "src/libraries/Clone.sol"; import { Types } from "src/libraries/Types.sol"; import { ISemver } from "src/universal/ISemver.sol"; import { LibClock } from "src/dispute/lib/LibUDT.sol"; import "src/libraries/DisputeTypes.sol"; import "src/libraries/DisputeErrors.sol"; /// @title FaultDisputeGame /// @notice An implementation of the `IFaultDisputeGame` interface. contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { //////////////////////////////////////////////////////////////// // State Vars // //////////////////////////////////////////////////////////////// /// @notice The absolute prestate of the instruction trace. This is a constant that is defined /// by the program that is being used to execute the trace. Claim internal immutable ABSOLUTE_PRESTATE; /// @notice The max depth of the game. uint256 internal immutable MAX_GAME_DEPTH; /// @notice The max depth of the output bisection portion of the position tree. Immediately beneath /// this depth, execution trace bisection begins. uint256 internal immutable SPLIT_DEPTH; /// @notice The duration of the game. Duration internal immutable GAME_DURATION; /// @notice An onchain VM that performs single instruction steps on a fault proof program trace. IBigStepper internal immutable VM; /// @notice The game type ID. GameType internal immutable GAME_TYPE; /// @notice WETH contract for holding ETH. IDelayedWETH internal immutable WETH; /// @notice The anchor state registry. IAnchorStateRegistry internal immutable ANCHOR_STATE_REGISTRY; /// @notice The chain ID of the L2 network this contract argues about. uint256 internal immutable L2_CHAIN_ID; /// @notice The global root claim's position is always at gindex 1. Position internal constant ROOT_POSITION = Position.wrap(1); /// @notice The flag set in the `bond` field of a `ClaimData` struct to indicate that the bond has been claimed. uint128 internal constant CLAIMED_BOND_FLAG = type(uint128).max; /// @notice The starting timestamp of the game Timestamp public createdAt; /// @notice The timestamp of the game's global resolution. Timestamp public resolvedAt; /// @inheritdoc IDisputeGame GameStatus public status; /// @notice An append-only array of all claims made during the dispute game. ClaimData[] public claimData; /// @notice Credited balances for winning participants. mapping(address => uint256) public credit; /// @notice An internal mapping to allow for constant-time lookups of existing claims. mapping(ClaimHash => bool) internal claims; /// @notice An internal mapping of subgames rooted at a claim index to other claim indices in the subgame. mapping(uint256 => uint256[]) internal subgames; /// @notice Indicates whether the subgame rooted at the root claim has been resolved. bool internal subgameAtRootResolved; /// @notice Flag for the `initialize` function to prevent re-initialization. bool internal initialized; /// @notice The latest finalized output root, serving as the anchor for output bisection. OutputRoot public startingOutputRoot; /// @notice Semantic version. /// @custom:semver 0.8.1 string public constant version = "0.8.1"; /// @param _gameType The type ID of the game. /// @param _absolutePrestate The absolute prestate of the instruction trace. /// @param _maxGameDepth The maximum depth of bisection. /// @param _splitDepth The final depth of the output bisection portion of the game. /// @param _gameDuration The duration of the game. /// @param _vm An onchain VM that performs single instruction steps on an FPP trace. /// @param _weth WETH contract for holding ETH. /// @param _anchorStateRegistry The contract that stores the anchor state for each game type. /// @param _l2ChainId Chain ID of the L2 network this contract argues about. constructor( GameType _gameType, Claim _absolutePrestate, uint256 _maxGameDepth, uint256 _splitDepth, Duration _gameDuration, IBigStepper _vm, IDelayedWETH _weth, IAnchorStateRegistry _anchorStateRegistry, uint256 _l2ChainId ) { // The split depth cannot be greater than or equal to the max game depth. if (_splitDepth >= _maxGameDepth) revert InvalidSplitDepth(); GAME_TYPE = _gameType; ABSOLUTE_PRESTATE = _absolutePrestate; MAX_GAME_DEPTH = _maxGameDepth; SPLIT_DEPTH = _splitDepth; GAME_DURATION = _gameDuration; VM = _vm; WETH = _weth; ANCHOR_STATE_REGISTRY = _anchorStateRegistry; L2_CHAIN_ID = _l2ChainId; } /// @notice Receive function to allow the contract to receive ETH. receive() external payable { } /// @notice Fallback function to allow the contract to receive ETH. fallback() external payable { } //////////////////////////////////////////////////////////////// // `IFaultDisputeGame` impl // //////////////////////////////////////////////////////////////// /// @inheritdoc IFaultDisputeGame function step( uint256 _claimIndex, bool _isAttack, bytes calldata _stateData, bytes calldata _proof ) public virtual { // INVARIANT: Steps cannot be made unless the game is currently in progress. if (status != GameStatus.IN_PROGRESS) revert GameNotInProgress(); // Get the parent. If it does not exist, the call will revert with OOB. ClaimData storage parent = claimData[_claimIndex]; // Pull the parent position out of storage. Position parentPos = parent.position; // Determine the position of the step. Position stepPos = parentPos.move(_isAttack); // INVARIANT: A step cannot be made unless the move position is 1 below the `MAX_GAME_DEPTH` if (stepPos.depth() != MAX_GAME_DEPTH + 1) revert InvalidParent(); // Determine the expected pre & post states of the step. Claim preStateClaim; ClaimData storage postState; if (_isAttack) { // If the step position's index at depth is 0, the prestate is the absolute // prestate. // If the step is an attack at a trace index > 0, the prestate exists elsewhere in // the game state. // NOTE: We localize the `indexAtDepth` for the current execution trace subgame by finding // the remainder of the index at depth divided by 2 ** (MAX_GAME_DEPTH - SPLIT_DEPTH), // which is the number of leaves in each execution trace subgame. This is so that we can // determine whether or not the step position is represents the `ABSOLUTE_PRESTATE`. preStateClaim = (stepPos.indexAtDepth() % (1 << (MAX_GAME_DEPTH - SPLIT_DEPTH))) == 0 ? ABSOLUTE_PRESTATE : _findTraceAncestor(Position.wrap(parentPos.raw() - 1), parent.parentIndex, false).claim; // For all attacks, the poststate is the parent claim. postState = parent; } else { // If the step is a defense, the poststate exists elsewhere in the game state, // and the parent claim is the expected pre-state. preStateClaim = parent.claim; postState = _findTraceAncestor(Position.wrap(parentPos.raw() + 1), parent.parentIndex, false); } // INVARIANT: The prestate is always invalid if the passed `_stateData` is not the // preimage of the prestate claim hash. // We ignore the highest order byte of the digest because it is used to // indicate the VM Status and is added after the digest is computed. if (keccak256(_stateData) << 8 != preStateClaim.raw() << 8) revert InvalidPrestate(); // Compute the local preimage context for the step. Hash uuid = _findLocalContext(_claimIndex); // INVARIANT: If a step is an attack, the poststate is valid if the step produces // the same poststate hash as the parent claim's value. // If a step is a defense: // 1. If the parent claim and the found post state agree with each other // (depth diff % 2 == 0), the step is valid if it produces the same // state hash as the post state's claim. // 2. If the parent claim and the found post state disagree with each other // (depth diff % 2 != 0), the parent cannot be countered unless the step // produces the same state hash as `postState.claim`. // SAFETY: While the `attack` path does not need an extra check for the post // state's depth in relation to the parent, we don't need another // branch because (n - n) % 2 == 0. bool validStep = VM.step(_stateData, _proof, uuid.raw()) == postState.claim.raw(); bool parentPostAgree = (parentPos.depth() - postState.position.depth()) % 2 == 0; if (parentPostAgree == validStep) revert ValidStep(); // INVARIANT: A step cannot be made against a claim for a second time. if (parent.counteredBy != address(0)) revert DuplicateStep(); // Set the parent claim as countered. We do not need to append a new claim to the game; // instead, we can just set the existing parent as countered. parent.counteredBy = msg.sender; } /// @notice Generic move function, used for both `attack` and `defend` moves. /// @param _challengeIndex The index of the claim being moved against. /// @param _claim The claim at the next logical position in the game. /// @param _isAttack Whether or not the move is an attack or defense. function move(uint256 _challengeIndex, Claim _claim, bool _isAttack) public payable virtual { // INVARIANT: Moves cannot be made unless the game is currently in progress. if (status != GameStatus.IN_PROGRESS) revert GameNotInProgress(); // Get the parent. If it does not exist, the call will revert with OOB. ClaimData memory parent = claimData[_challengeIndex]; // Compute the position that the claim commits to. Because the parent's position is already // known, we can compute the next position by moving left or right depending on whether // or not the move is an attack or defense. Position parentPos = parent.position; Position nextPosition = parentPos.move(_isAttack); uint256 nextPositionDepth = nextPosition.depth(); // INVARIANT: A defense can never be made against the root claim of either the output root game or any // of the execution trace bisection subgames. This is because the root claim commits to the // entire state. Therefore, the only valid defense is to do nothing if it is agreed with. if ((_challengeIndex == 0 || nextPositionDepth == SPLIT_DEPTH + 2) && !_isAttack) { revert CannotDefendRootClaim(); } // INVARIANT: A move can never surpass the `MAX_GAME_DEPTH`. The only option to counter a // claim at this depth is to perform a single instruction step on-chain via // the `step` function to prove that the state transition produces an unexpected // post-state. if (nextPositionDepth > MAX_GAME_DEPTH) revert GameDepthExceeded(); // When the next position surpasses the split depth (i.e., it is the root claim of an execution // trace bisection sub-game), we need to perform some extra verification steps. if (nextPositionDepth == SPLIT_DEPTH + 1) { _verifyExecBisectionRoot(_claim, _challengeIndex, parentPos, _isAttack); } // INVARIANT: The `msg.value` must be sufficient to cover the required bond. if (getRequiredBond(nextPosition) > msg.value) revert InsufficientBond(); // Fetch the grandparent clock, if it exists. // The grandparent clock should always exist unless the parent is the root claim. Clock grandparentClock; if (parent.parentIndex != type(uint32).max) { grandparentClock = claimData[parent.parentIndex].clock; } // Compute the duration of the next clock. This is done by adding the duration of the // grandparent claim to the difference between the current block timestamp and the // parent's clock timestamp. Duration nextDuration = Duration.wrap( uint64( // First, fetch the duration of the grandparent claim. grandparentClock.duration().raw() // Second, add the difference between the current block timestamp and the // parent's clock timestamp. + block.timestamp - parent.clock.timestamp().raw() ) ); // INVARIANT: A move can never be made once its clock has exceeded `GAME_DURATION / 2` // seconds of time. if (nextDuration.raw() > GAME_DURATION.raw() >> 1) revert ClockTimeExceeded(); // Construct the next clock with the new duration and the current block timestamp. Clock nextClock = LibClock.wrap(nextDuration, Timestamp.wrap(uint64(block.timestamp))); // INVARIANT: There cannot be multiple identical claims with identical moves on the same challengeIndex. Multiple // claims at the same position may dispute the same challengeIndex. However, they must have different // values. ClaimHash claimHash = _claim.hashClaimPos(nextPosition, _challengeIndex); if (claims[claimHash]) revert ClaimAlreadyExists(); claims[claimHash] = true; // Create the new claim. claimData.push( ClaimData({ parentIndex: uint32(_challengeIndex), // This is updated during subgame resolution counteredBy: address(0), claimant: msg.sender, bond: uint128(msg.value), claim: _claim, position: nextPosition, clock: nextClock }) ); // Update the subgame rooted at the parent claim. subgames[_challengeIndex].push(claimData.length - 1); // Deposit the bond. WETH.deposit{ value: msg.value }(); // Emit the appropriate event for the attack or defense. emit Move(_challengeIndex, _claim, msg.sender); } /// @inheritdoc IFaultDisputeGame function attack(uint256 _parentIndex, Claim _claim) external payable { move(_parentIndex, _claim, true); } /// @inheritdoc IFaultDisputeGame function defend(uint256 _parentIndex, Claim _claim) external payable { move(_parentIndex, _claim, false); } /// @inheritdoc IFaultDisputeGame function addLocalData(uint256 _ident, uint256 _execLeafIdx, uint256 _partOffset) external { // INVARIANT: Local data can only be added if the game is currently in progress. if (status != GameStatus.IN_PROGRESS) revert GameNotInProgress(); (Claim starting, Position startingPos, Claim disputed, Position disputedPos) = _findStartingAndDisputedOutputs(_execLeafIdx); Hash uuid = _computeLocalContext(starting, startingPos, disputed, disputedPos); IPreimageOracle oracle = VM.oracle(); if (_ident == LocalPreimageKey.L1_HEAD_HASH) { // Load the L1 head hash oracle.loadLocalData(_ident, uuid.raw(), l1Head().raw(), 32, _partOffset); } else if (_ident == LocalPreimageKey.STARTING_OUTPUT_ROOT) { // Load the starting proposal's output root. oracle.loadLocalData(_ident, uuid.raw(), starting.raw(), 32, _partOffset); } else if (_ident == LocalPreimageKey.DISPUTED_OUTPUT_ROOT) { // Load the disputed proposal's output root oracle.loadLocalData(_ident, uuid.raw(), disputed.raw(), 32, _partOffset); } else if (_ident == LocalPreimageKey.DISPUTED_L2_BLOCK_NUMBER) { // Load the disputed proposal's L2 block number as a big-endian uint64 in the // high order 8 bytes of the word. // We add the index at depth + 1 to the starting block number to get the disputed L2 // block number. uint256 l2Number = startingOutputRoot.l2BlockNumber + disputedPos.traceIndex(SPLIT_DEPTH) + 1; oracle.loadLocalData(_ident, uuid.raw(), bytes32(l2Number << 0xC0), 8, _partOffset); } else if (_ident == LocalPreimageKey.CHAIN_ID) { // Load the chain ID as a big-endian uint64 in the high order 8 bytes of the word. oracle.loadLocalData(_ident, uuid.raw(), bytes32(L2_CHAIN_ID << 0xC0), 8, _partOffset); } else { revert InvalidLocalIdent(); } } /// @inheritdoc IFaultDisputeGame function l1Head() public pure returns (Hash l1Head_) { l1Head_ = Hash.wrap(_getArgFixedBytes(0x20)); } /// @inheritdoc IFaultDisputeGame function l2BlockNumber() public pure returns (uint256 l2BlockNumber_) { l2BlockNumber_ = _getArgUint256(0x40); } //////////////////////////////////////////////////////////////// // `IDisputeGame` impl // //////////////////////////////////////////////////////////////// /// @inheritdoc IDisputeGame function gameType() public view override returns (GameType gameType_) { gameType_ = GAME_TYPE; } /// @inheritdoc IDisputeGame function resolve() external returns (GameStatus status_) { // INVARIANT: Resolution cannot occur unless the game is currently in progress. if (status != GameStatus.IN_PROGRESS) revert GameNotInProgress(); // INVARIANT: Resolution cannot occur unless the absolute root subgame has been resolved. if (!subgameAtRootResolved) revert OutOfOrderResolution(); // Update the global game status; The dispute has concluded. status_ = claimData[0].counteredBy == address(0) ? GameStatus.DEFENDER_WINS : GameStatus.CHALLENGER_WINS; resolvedAt = Timestamp.wrap(uint64(block.timestamp)); // Update the status and emit the resolved event, note that we're performing an assignment here. emit Resolved(status = status_); // Try to update the anchor state, this should not revert. ANCHOR_STATE_REGISTRY.tryUpdateAnchorState(); } /// @inheritdoc IFaultDisputeGame function resolveClaim(uint256 _claimIndex) external payable { // INVARIANT: Resolution cannot occur unless the game is currently in progress. if (status != GameStatus.IN_PROGRESS) revert GameNotInProgress(); ClaimData storage parent = claimData[_claimIndex]; // INVARIANT: Cannot resolve a subgame unless the clock of its root has expired uint64 parentClockDuration = parent.clock.duration().raw(); uint64 timeSinceParentMove = uint64(block.timestamp) - parent.clock.timestamp().raw(); if (parentClockDuration + timeSinceParentMove <= GAME_DURATION.raw() >> 1) { revert ClockNotExpired(); } uint256[] storage challengeIndices = subgames[_claimIndex]; uint256 challengeIndicesLen = challengeIndices.length; // INVARIANT: Cannot resolve subgames twice if (_claimIndex == 0 && subgameAtRootResolved) { revert ClaimAlreadyResolved(); } // Uncontested claims are resolved implicitly unless they are the root claim. Pay out the bond to the claimant // and return early. if (challengeIndicesLen == 0 && _claimIndex != 0) { // In the event that the parent claim is at the max depth, there will always be 0 subgames. If the // `counteredBy` field is set and there are no subgames, this implies that the parent claim was successfully // stepped against. In this case, we pay out the bond to the party that stepped against the parent claim. // Otherwise, the parent claim is uncontested, and the bond is returned to the claimant. address counteredBy = parent.counteredBy; address recipient = counteredBy == address(0) ? parent.claimant : counteredBy; _distributeBond(recipient, parent); return; } // Assume parent is honest until proven otherwise address countered = address(0); Position leftmostCounter = Position.wrap(type(uint128).max); for (uint256 i = 0; i < challengeIndicesLen; ++i) { uint256 challengeIndex = challengeIndices[i]; // INVARIANT: Cannot resolve a subgame containing an unresolved claim if (subgames[challengeIndex].length != 0) revert OutOfOrderResolution(); ClaimData storage claim = claimData[challengeIndex]; // If the child subgame is uncountered and further left than the current left-most counter, // update the parent subgame's `countered` address and the current `leftmostCounter`. // The left-most correct counter is preferred in bond payouts in order to discourage attackers // from countering invalid subgame roots via an invalid defense position. As such positions // cannot be correctly countered. // Note that correctly positioned defense, but invalid claimes can still be successfully countered. if (claim.counteredBy == address(0) && leftmostCounter.raw() > claim.position.raw()) { countered = claim.claimant; leftmostCounter = claim.position; } } // If the parent was not successfully countered, pay out the parent's bond to the claimant. // If the parent was successfully countered, pay out the parent's bond to the challenger. _distributeBond(countered == address(0) ? parent.claimant : countered, parent); // Once a subgame is resolved, we percolate the result up the DAG so subsequent calls to // resolveClaim will not need to traverse this subgame. parent.counteredBy = countered; // Resolved subgames have no entries delete subgames[_claimIndex]; // Indicate the game is ready to be resolved globally. if (_claimIndex == 0) { subgameAtRootResolved = true; } } /// @inheritdoc IDisputeGame function rootClaim() public pure returns (Claim rootClaim_) { rootClaim_ = Claim.wrap(_getArgFixedBytes(0x00)); } /// @inheritdoc IDisputeGame function extraData() public pure returns (bytes memory extraData_) { // The extra data starts at the second word within the cwia calldata and // is 32 bytes long. extraData_ = _getArgDynBytes(0x40, 0x20); } /// @inheritdoc IDisputeGame function gameData() external view returns (GameType gameType_, Claim rootClaim_, bytes memory extraData_) { gameType_ = gameType(); rootClaim_ = rootClaim(); extraData_ = extraData(); } /// @inheritdoc IFaultDisputeGame function startingBlockNumber() external view returns (uint256 startingBlockNumber_) { startingBlockNumber_ = startingOutputRoot.l2BlockNumber; } /// @inheritdoc IFaultDisputeGame function startingRootHash() external view returns (Hash startingRootHash_) { startingRootHash_ = startingOutputRoot.root; } //////////////////////////////////////////////////////////////// // MISC EXTERNAL // //////////////////////////////////////////////////////////////// /// @inheritdoc IInitializable function initialize() public payable virtual { // SAFETY: Any revert in this function will bubble up to the DisputeGameFactory and // prevent the game from being created. // // Implicit assumptions: // - The `gameStatus` state variable defaults to 0, which is `GameStatus.IN_PROGRESS` // - The dispute game factory will enforce the required bond to initialize the game. // // Explicit checks: // - The game must not have already been initialized. // - An output root cannot be proposed at or before the starting block number. // INVARIANT: The game must not have already been initialized. if (initialized) revert AlreadyInitialized(); // Grab the latest anchor root. (Hash root, uint256 rootBlockNumber) = ANCHOR_STATE_REGISTRY.anchors(GAME_TYPE); // Should only happen if this is a new game type that hasn't been set up yet. if (root.raw() == bytes32(0)) revert AnchorRootNotFound(); // Set the starting output root. startingOutputRoot = OutputRoot({ l2BlockNumber: rootBlockNumber, root: root }); // Do not allow the game to be initialized if the root claim corresponds to a block at or before the // configured starting block number. if (l2BlockNumber() <= rootBlockNumber) revert UnexpectedRootClaim(rootClaim()); // Revert if the calldata size is too large, which signals that the `extraData` contains more than expected. // This is to prevent adding extra bytes to the `extraData` that result in a different game UUID in the factory, // but are not used by the game, which would allow for multiple dispute games for the same output proposal to // be created. // Expected length: 0x66 (0x04 selector + 0x20 root claim + 0x20 l1 head + 0x20 extraData + 0x02 CWIA bytes) assembly { if gt(calldatasize(), 0x66) { // Store the selector for `ExtraDataTooLong()` & revert mstore(0x00, 0xc407e025) revert(0x1C, 0x04) } } // Set the root claim claimData.push( ClaimData({ parentIndex: type(uint32).max, counteredBy: address(0), claimant: tx.origin, bond: uint128(msg.value), claim: rootClaim(), position: ROOT_POSITION, clock: LibClock.wrap(Duration.wrap(0), Timestamp.wrap(uint64(block.timestamp))) }) ); // Deposit the bond. WETH.deposit{ value: msg.value }(); // Set the game's starting timestamp createdAt = Timestamp.wrap(uint64(block.timestamp)); // Set the game as initialized. initialized = true; } /// @notice Returns the length of the `claimData` array. function claimDataLen() external view returns (uint256 len_) { len_ = claimData.length; } /// @notice Returns the required bond for a given move kind. /// @param _position The position of the bonded interaction. /// @return requiredBond_ The required ETH bond for the given move, in wei. function getRequiredBond(Position _position) public view returns (uint256 requiredBond_) { uint256 depth = uint256(_position.depth()); if (depth > MAX_GAME_DEPTH) revert GameDepthExceeded(); // Values taken from Big Bonds v1.5 (TM) spec. uint256 assumedBaseFee = 200 gwei; uint256 baseGasCharged = 400_000; uint256 highGasCharged = 200_000_000; // Goal here is to compute the fixed multiplier that will be applied to the base gas // charged to get the required gas amount for the given depth. We apply this multiplier // some `n` times where `n` is the depth of the position. We are looking for some number // that, when multiplied by itself `MAX_GAME_DEPTH` times and then multiplied by the base // gas charged, will give us the maximum gas that we want to charge. // We want to solve for (highGasCharged/baseGasCharged) ** (1/MAX_GAME_DEPTH). // We know that a ** (b/c) is equal to e ** (ln(a) * (b/c)). // We can compute e ** (ln(a) * (b/c)) quite easily with FixedPointMathLib. // Set up a, b, and c. uint256 a = highGasCharged / baseGasCharged; uint256 b = FixedPointMathLib.WAD; uint256 c = MAX_GAME_DEPTH * FixedPointMathLib.WAD; // Compute ln(a). // slither-disable-next-line divide-before-multiply uint256 lnA = uint256(FixedPointMathLib.lnWad(int256(a * FixedPointMathLib.WAD))); // Computes (b / c) with full precision using WAD = 1e18. uint256 bOverC = FixedPointMathLib.divWad(b, c); // Compute e ** (ln(a) * (b/c)) // sMulWad can be used here since WAD = 1e18 maintains the same precision. uint256 numerator = FixedPointMathLib.mulWad(lnA, bOverC); int256 base = FixedPointMathLib.expWad(int256(numerator)); // Compute the required gas amount. int256 rawGas = FixedPointMathLib.powWad(base, int256(depth * FixedPointMathLib.WAD)); uint256 requiredGas = FixedPointMathLib.mulWad(baseGasCharged, uint256(rawGas)); // Compute the required bond. requiredBond_ = assumedBaseFee * requiredGas; } /// @notice Claim the credit belonging to the recipient address. /// @param _recipient The owner and recipient of the credit. function claimCredit(address _recipient) external { // Remove the credit from the recipient prior to performing the external call. uint256 recipientCredit = credit[_recipient]; credit[_recipient] = 0; // Revert if the recipient has no credit to claim. if (recipientCredit == 0) { revert NoCreditToClaim(); } // Try to withdraw the WETH amount so it can be used here. WETH.withdraw(_recipient, recipientCredit); // Transfer the credit to the recipient. (bool success,) = _recipient.call{ value: recipientCredit }(hex""); if (!success) revert BondTransferFailed(); } /// @notice Returns the flag set in the `bond` field of a `ClaimData` struct to indicate that the bond has been /// claimed. function claimedBondFlag() external pure returns (uint128 claimedBondFlag_) { claimedBondFlag_ = CLAIMED_BOND_FLAG; } //////////////////////////////////////////////////////////////// // IMMUTABLE GETTERS // //////////////////////////////////////////////////////////////// /// @notice Returns the absolute prestate of the instruction trace. function absolutePrestate() external view returns (Claim absolutePrestate_) { absolutePrestate_ = ABSOLUTE_PRESTATE; } /// @notice Returns the max game depth. function maxGameDepth() external view returns (uint256 maxGameDepth_) { maxGameDepth_ = MAX_GAME_DEPTH; } /// @notice Returns the split depth. function splitDepth() external view returns (uint256 splitDepth_) { splitDepth_ = SPLIT_DEPTH; } /// @notice Returns the game duration. function gameDuration() external view returns (Duration gameDuration_) { gameDuration_ = GAME_DURATION; } /// @notice Returns the address of the VM. function vm() external view returns (IBigStepper vm_) { vm_ = VM; } /// @notice Returns the WETH contract for holding ETH. function weth() external view returns (IDelayedWETH weth_) { weth_ = WETH; } /// @notice Returns the chain ID of the L2 network this contract argues about. function l2ChainId() external view returns (uint256 l2ChainId_) { l2ChainId_ = L2_CHAIN_ID; } //////////////////////////////////////////////////////////////// // HELPERS // //////////////////////////////////////////////////////////////// /// @notice Pays out the bond of a claim to a given recipient. /// @param _recipient The recipient of the bond. /// @param _bonded The claim to pay out the bond of. function _distributeBond(address _recipient, ClaimData storage _bonded) internal { // Set all bits in the bond value to indicate that the bond has been paid out. uint256 bond = _bonded.bond; if (bond == CLAIMED_BOND_FLAG) revert ClaimAlreadyResolved(); _bonded.bond = CLAIMED_BOND_FLAG; // Increase the recipient's credit. credit[_recipient] += bond; // Unlock the bond. WETH.unlock(_recipient, bond); } /// @notice Verifies the integrity of an execution bisection subgame's root claim. Reverts if the claim /// is invalid. /// @param _rootClaim The root claim of the execution bisection subgame. function _verifyExecBisectionRoot( Claim _rootClaim, uint256 _parentIdx, Position _parentPos, bool _isAttack ) internal view { // The root claim of an execution trace bisection sub-game must: // 1. Signal that the VM panicked or resulted in an invalid transition if the disputed output root // was made by the opposing party. // 2. Signal that the VM resulted in a valid transition if the disputed output root was made by the same party. // If the move is a defense, the disputed output could have been made by either party. In this case, we // need to search for the parent output to determine what the expected status byte should be. Position disputedLeafPos = Position.wrap(_parentPos.raw() + 1); ClaimData storage disputed = _findTraceAncestor({ _pos: disputedLeafPos, _start: _parentIdx, _global: true }); uint8 vmStatus = uint8(_rootClaim.raw()[0]); if (_isAttack || disputed.position.depth() % 2 == SPLIT_DEPTH % 2) { // If the move is an attack, the parent output is always deemed to be disputed. In this case, we only need // to check that the root claim signals that the VM panicked or resulted in an invalid transition. // If the move is a defense, and the disputed output and creator of the execution trace subgame disagree, // the root claim should also signal that the VM panicked or resulted in an invalid transition. if (!(vmStatus == VMStatuses.INVALID.raw() || vmStatus == VMStatuses.PANIC.raw())) { revert UnexpectedRootClaim(_rootClaim); } } else if (vmStatus != VMStatuses.VALID.raw()) { // The disputed output and the creator of the execution trace subgame agree. The status byte should // have signaled that the VM succeeded. revert UnexpectedRootClaim(_rootClaim); } } /// @notice Finds the trace ancestor of a given position within the DAG. /// @param _pos The position to find the trace ancestor claim of. /// @param _start The index to start searching from. /// @param _global Whether or not to search the entire dag or just within an execution trace subgame. If set to /// `true`, and `_pos` is at or above the split depth, this function will revert. /// @return ancestor_ The ancestor claim that commits to the same trace index as `_pos`. function _findTraceAncestor( Position _pos, uint256 _start, bool _global ) internal view returns (ClaimData storage ancestor_) { // Grab the trace ancestor's expected position. Position traceAncestorPos = _global ? _pos.traceAncestor() : _pos.traceAncestorBounded(SPLIT_DEPTH); // Walk up the DAG to find a claim that commits to the same trace index as `_pos`. It is // guaranteed that such a claim exists. ancestor_ = claimData[_start]; while (ancestor_.position.raw() != traceAncestorPos.raw()) { ancestor_ = claimData[ancestor_.parentIndex]; } } /// @notice Finds the starting and disputed output root for a given `ClaimData` within the DAG. This /// `ClaimData` must be below the `SPLIT_DEPTH`. /// @param _start The index within `claimData` of the claim to start searching from. /// @return startingClaim_ The starting output root claim. /// @return startingPos_ The starting output root position. /// @return disputedClaim_ The disputed output root claim. /// @return disputedPos_ The disputed output root position. function _findStartingAndDisputedOutputs(uint256 _start) internal view returns (Claim startingClaim_, Position startingPos_, Claim disputedClaim_, Position disputedPos_) { // Fatch the starting claim. uint256 claimIdx = _start; ClaimData storage claim = claimData[claimIdx]; // If the starting claim's depth is less than or equal to the split depth, we revert as this is UB. if (claim.position.depth() <= SPLIT_DEPTH) revert ClaimAboveSplit(); // We want to: // 1. Find the first claim at the split depth. // 2. Determine whether it was the starting or disputed output for the exec game. // 3. Find the complimentary claim depending on the info from #2 (pre or post). // Walk up the DAG until the ancestor's depth is equal to the split depth. uint256 currentDepth; ClaimData storage execRootClaim = claim; while ((currentDepth = claim.position.depth()) > SPLIT_DEPTH) { uint256 parentIndex = claim.parentIndex; // If we're currently at the split depth + 1, we're at the root of the execution sub-game. // We need to keep track of the root claim here to determine whether the execution sub-game was // started with an attack or defense against the output leaf claim. if (currentDepth == SPLIT_DEPTH + 1) execRootClaim = claim; claim = claimData[parentIndex]; claimIdx = parentIndex; } // Determine whether the start of the execution sub-game was an attack or defense to the output root // above. This is important because it determines which claim is the starting output root and which // is the disputed output root. (Position execRootPos, Position outputPos) = (execRootClaim.position, claim.position); bool wasAttack = execRootPos.parent().raw() == outputPos.raw(); // Determine the starting and disputed output root indices. // 1. If it was an attack, the disputed output root is `claim`, and the starting output root is // elsewhere in the DAG (it must commit to the block # index at depth of `outputPos - 1`). // 2. If it was a defense, the starting output root is `claim`, and the disputed output root is // elsewhere in the DAG (it must commit to the block # index at depth of `outputPos + 1`). if (wasAttack) { // If this is an attack on the first output root (the block directly after the starting // block number), the starting claim nor position exists in the tree. We leave these as // 0, which can be easily identified due to 0 being an invalid Gindex. if (outputPos.indexAtDepth() > 0) { ClaimData storage starting = _findTraceAncestor(Position.wrap(outputPos.raw() - 1), claimIdx, true); (startingClaim_, startingPos_) = (starting.claim, starting.position); } else { startingClaim_ = Claim.wrap(startingOutputRoot.root.raw()); } (disputedClaim_, disputedPos_) = (claim.claim, claim.position); } else { ClaimData storage disputed = _findTraceAncestor(Position.wrap(outputPos.raw() + 1), claimIdx, true); (startingClaim_, startingPos_) = (claim.claim, claim.position); (disputedClaim_, disputedPos_) = (disputed.claim, disputed.position); } } /// @notice Finds the local context hash for a given claim index that is present in an execution trace subgame. /// @param _claimIndex The index of the claim to find the local context hash for. /// @return uuid_ The local context hash. function _findLocalContext(uint256 _claimIndex) internal view returns (Hash uuid_) { (Claim starting, Position startingPos, Claim disputed, Position disputedPos) = _findStartingAndDisputedOutputs(_claimIndex); uuid_ = _computeLocalContext(starting, startingPos, disputed, disputedPos); } /// @notice Computes the local context hash for a set of starting/disputed claim values and positions. /// @param _starting The starting claim. /// @param _startingPos The starting claim's position. /// @param _disputed The disputed claim. /// @param _disputedPos The disputed claim's position. /// @return uuid_ The local context hash. function _computeLocalContext( Claim _starting, Position _startingPos, Claim _disputed, Position _disputedPos ) internal pure returns (Hash uuid_) { // A position of 0 indicates that the starting claim is the absolute prestate. In this special case, // we do not include the starting claim within the local context hash. if (_startingPos.raw() == 0) { uuid_ = Hash.wrap(keccak256(abi.encode(_disputed, _disputedPos))); } else { uuid_ = Hash.wrap(keccak256(abi.encode(_starting, _startingPos, _disputed, _disputedPos))); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) library FixedPointMathLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The operation failed, as the output exceeds the maximum value of uint256. error ExpOverflow(); /// @dev The operation failed, as the output exceeds the maximum value of uint256. error FactorialOverflow(); /// @dev The operation failed, due to an overflow. error RPowOverflow(); /// @dev The mantissa is too big to fit. error MantissaOverflow(); /// @dev The operation failed, due to an multiplication overflow. error MulWadFailed(); /// @dev The operation failed, due to an multiplication overflow. error SMulWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error DivWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error SDivWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error MulDivFailed(); /// @dev The division failed, as the denominator is zero. error DivFailed(); /// @dev The full precision multiply-divide operation failed, either due /// to the result being larger than 256 bits, or a division by a zero. error FullMulDivFailed(); /// @dev The output is undefined, as the input is less-than-or-equal to zero. error LnWadUndefined(); /// @dev The input outside the acceptable domain. error OutOfDomain(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The scalar of ETH and most ERC20s. uint256 internal constant WAD = 1e18; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SIMPLIFIED FIXED POINT OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `(x * y) / WAD` rounded down. function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if mul(y, gt(x, div(not(0), y))) { mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. revert(0x1c, 0x04) } z := div(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down. function sMulWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`. if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) { mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`. revert(0x1c, 0x04) } z := sdiv(z, WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks. function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks. function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded up. function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if mul(y, gt(x, div(not(0), y))) { mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD)) } } /// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks. function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD)) } } /// @dev Equivalent to `(x * WAD) / y` rounded down. function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`. if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) { mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. revert(0x1c, 0x04) } z := div(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down. function sDivWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, WAD) // Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`. if iszero(and(iszero(iszero(y)), eq(sdiv(z, WAD), x))) { mstore(0x00, 0x5c43740d) // `SDivWadFailed()`. revert(0x1c, 0x04) } z := sdiv(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks. function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks. function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded up. function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`. if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) { mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y)) } } /// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks. function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y)) } } /// @dev Equivalent to `x` to the power of `y`. /// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`. function powWad(int256 x, int256 y) internal pure returns (int256) { // Using `ln(x)` means `x` must be greater than 0. return expWad((lnWad(x) * y) / int256(WAD)); } /// @dev Returns `exp(x)`, denominated in `WAD`. /// Credit to Remco Bloemen under MIT license: https://2π.com/21/exp-ln function expWad(int256 x) internal pure returns (int256 r) { unchecked { // When the result is less than 0.5 we return zero. // This happens when `x <= floor(log(0.5e18) * 1e18) ≈ -42e18`. if (x <= -41446531673892822313) return r; /// @solidity memory-safe-assembly assembly { // When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as // an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`. if iszero(slt(x, 135305999368893231589)) { mstore(0x00, 0xa37bfec9) // `ExpOverflow()`. revert(0x1c, 0x04) } } // `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96` // for more intermediate precision and a binary basis. This base conversion // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. x = (x << 78) / 5 ** 18; // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers // of two such that exp(x) = exp(x') * 2**k, where k is an integer. // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96; x = x - k * 54916777467707473351141471128; // `k` is in the range `[-61, 195]`. // Evaluate using a (6, 7)-term rational approximation. // `p` is made monic, we'll multiply by a scale factor later. int256 y = x + 1346386616545796478920950773328; y = ((y * x) >> 96) + 57155421227552351082224309758442; int256 p = y + x - 94201549194550492254356042504812; p = ((p * y) >> 96) + 28719021644029726153956944680412240; p = p * x + (4385272521454847904659076985693276 << 96); // We leave `p` in `2**192` basis so we don't need to scale it back up for the division. int256 q = x - 2855989394907223263936484059900; q = ((q * x) >> 96) + 50020603652535783019961831881945; q = ((q * x) >> 96) - 533845033583426703283633433725380; q = ((q * x) >> 96) + 3604857256930695427073651918091429; q = ((q * x) >> 96) - 14423608567350463180887372962807573; q = ((q * x) >> 96) + 26449188498355588339934803723976023; /// @solidity memory-safe-assembly assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial won't have zeros in the domain as all its roots are complex. // No scaling is necessary because p is already `2**96` too large. r := sdiv(p, q) } // r should be in the range `(0.09, 0.25) * 2**96`. // We now need to multiply r by: // - The scale factor `s ≈ 6.031367120`. // - The `2**k` factor from the range reduction. // - The `1e18 / 2**96` factor for base conversion. // We do this all at once, with an intermediate result in `2**213` // basis, so the final right shift is always by a positive amount. r = int256( (uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k) ); } } /// @dev Returns `ln(x)`, denominated in `WAD`. /// Credit to Remco Bloemen under MIT license: https://2π.com/21/exp-ln function lnWad(int256 x) internal pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // We want to convert `x` from `10**18` fixed point to `2**96` fixed point. // We do this by multiplying by `2**96 / 10**18`. But since // `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here // and add `ln(2**96 / 10**18)` at the end. // Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`. r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // We place the check here for more optimal stack operations. if iszero(sgt(x, 0)) { mstore(0x00, 0x1615e638) // `LnWadUndefined()`. revert(0x1c, 0x04) } // forgefmt: disable-next-item r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)) // Reduce range of x to (1, 2) * 2**96 // ln(2^k * x) = k * ln(2) + ln(x) x := shr(159, shl(r, x)) // Evaluate using a (8, 8)-term rational approximation. // `p` is made monic, we will multiply by a scale factor later. // forgefmt: disable-next-item let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir. sar(96, mul(add(43456485725739037958740375743393, sar(96, mul(add(24828157081833163892658089445524, sar(96, mul(add(3273285459638523848632254066296, x), x))), x))), x)), 11111509109440967052023855526967) p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857) p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526) p := sub(mul(p, x), shl(96, 795164235651350426258249787498)) // We leave `p` in `2**192` basis so we don't need to scale it back up for the division. // `q` is monic by convention. let q := add(5573035233440673466300451813936, x) q := add(71694874799317883764090561454958, sar(96, mul(x, q))) q := add(283447036172924575727196451306956, sar(96, mul(x, q))) q := add(401686690394027663651624208769553, sar(96, mul(x, q))) q := add(204048457590392012362485061816622, sar(96, mul(x, q))) q := add(31853899698501571402653359427138, sar(96, mul(x, q))) q := add(909429971244387300277376558375, sar(96, mul(x, q))) // `p / q` is in the range `(0, 0.125) * 2**96`. // Finalization, we need to: // - Multiply by the scale factor `s = 5.549…`. // - Add `ln(2**96 / 10**18)`. // - Add `k * ln(2)`. // - Multiply by `10**18 / 2**96 = 5**18 >> 78`. // The q polynomial is known not to have zeros in the domain. // No scaling required because p is already `2**96` too large. p := sdiv(p, q) // Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`. p := mul(1677202110996718588342820967067443963516166, p) // Add `ln(2) * k * 5**18 * 2**192`. // forgefmt: disable-next-item p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p) // Add `ln(2**96 / 10**18) * 5**18 * 2**192`. p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p) // Base conversion: mul `2**18 / 2**192`. r := sar(174, p) } } /// @dev Returns `W_0(x)`, denominated in `WAD`. /// See: https://en.wikipedia.org/wiki/Lambert_W_function /// a.k.a. Product log function. This is an approximation of the principal branch. function lambertW0Wad(int256 x) internal pure returns (int256 w) { // forgefmt: disable-next-item unchecked { if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`. int256 wad = int256(WAD); int256 p = x; uint256 c; // Whether we need to avoid catastrophic cancellation. uint256 i = 4; // Number of iterations. if (w <= 0x1ffffffffffff) { if (-0x4000000000000 <= w) { i = 1; // Inputs near zero only take one step to converge. } else if (w <= -0x3ffffffffffffff) { i = 32; // Inputs near `-1/e` take very long to converge. } } else if (w >> 63 == 0) { /// @solidity memory-safe-assembly assembly { // Inline log2 for more performance, since the range is small. let v := shr(49, w) let l := shl(3, lt(0xff, v)) l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)), 49) w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13)) c := gt(l, 60) i := add(2, add(gt(l, 53), c)) } } else { int256 ll = lnWad(w = lnWad(w)); /// @solidity memory-safe-assembly assembly { // `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`. w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll)) i := add(3, iszero(shr(68, x))) c := iszero(shr(143, x)) } if (c == 0) { do { // If `x` is big, use Newton's so that intermediate values won't overflow. int256 e = expWad(w); /// @solidity memory-safe-assembly assembly { let t := mul(w, div(e, wad)) w := sub(w, sdiv(sub(t, x), div(add(e, t), wad))) } if (p <= w) break; p = w; } while (--i != 0); /// @solidity memory-safe-assembly assembly { w := sub(w, sgt(w, 2)) } return w; } } do { // Otherwise, use Halley's for faster convergence. int256 e = expWad(w); /// @solidity memory-safe-assembly assembly { let t := add(w, wad) let s := sub(mul(w, e), mul(x, wad)) w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t))))) } if (p <= w) break; p = w; } while (--i != c); /// @solidity memory-safe-assembly assembly { w := sub(w, sgt(w, 2)) } // For certain ranges of `x`, we'll use the quadratic-rate recursive formula of // R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation. if (c != 0) { int256 t = w | 1; /// @solidity memory-safe-assembly assembly { x := sdiv(mul(x, wad), t) } x = (t * (wad + lnWad(x))); /// @solidity memory-safe-assembly assembly { w := sdiv(x, add(wad, t)) } } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* GENERAL NUMBER UTILITIES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Calculates `floor(a * b / d)` with full precision. /// Throws if result overflows a uint256 or when `d` is zero. /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { // 512-bit multiply `[p1 p0] = x * y`. // Compute the product mod `2**256` and mod `2**256 - 1` // then use the Chinese Remainder Theorem to reconstruct // the 512 bit result. The result is stored in two 256 // variables such that `product = p1 * 2**256 + p0`. // Least significant 256 bits of the product. result := mul(x, y) // Temporarily use `result` as `p0` to save gas. let mm := mulmod(x, y, not(0)) // Most significant 256 bits of the product. let p1 := sub(mm, add(result, lt(mm, result))) // Handle non-overflow cases, 256 by 256 division. if iszero(p1) { if iszero(d) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } result := div(result, d) break } // Make sure the result is less than `2**256`. Also prevents `d == 0`. if iszero(gt(d, p1)) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } /*------------------- 512 by 256 division --------------------*/ // Make division exact by subtracting the remainder from `[p1 p0]`. // Compute remainder using mulmod. let r := mulmod(x, y, d) // `t` is the least significant bit of `d`. // Always greater or equal to 1. let t := and(d, sub(0, d)) // Divide `d` by `t`, which is a power of two. d := div(d, t) // Invert `d mod 2**256` // Now that `d` is an odd number, it has an inverse // modulo `2**256` such that `d * inv = 1 mod 2**256`. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, `d * inv = 1 mod 2**4`. let inv := xor(2, mul(3, d)) // Now use Newton-Raphson iteration to improve the precision. // Thanks to Hensel's lifting lemma, this also works in modular // arithmetic, doubling the correct bits in each step. inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128 result := mul( // Divide [p1 p0] by the factors of two. // Shift in bits from `p1` into `p0`. For this we need // to flip `t` such that it is `2**256 / t`. or( mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)), div(sub(result, r), t) ), // inverse mod 2**256 mul(inv, sub(2, mul(d, inv))) ) break } } } /// @dev Calculates `floor(x * y / d)` with full precision, rounded up. /// Throws if result overflows a uint256 or when `d` is zero. /// Credit to Uniswap-v3-core under MIT license: /// https://github.com/Uniswap/v3-core/blob/contracts/libraries/FullMath.sol function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) { result = fullMulDiv(x, y, d); /// @solidity memory-safe-assembly assembly { if mulmod(x, y, d) { result := add(result, 1) if iszero(result) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } } } } /// @dev Returns `floor(x * y / d)`. /// Reverts if `x * y` overflows, or `d` is zero. function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) { mstore(0x00, 0xad251c27) // `MulDivFailed()`. revert(0x1c, 0x04) } z := div(mul(x, y), d) } } /// @dev Returns `ceil(x * y / d)`. /// Reverts if `x * y` overflows, or `d` is zero. function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) { mstore(0x00, 0xad251c27) // `MulDivFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, y), d))), div(mul(x, y), d)) } } /// @dev Returns `ceil(x / d)`. /// Reverts if `d` is zero. function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { if iszero(d) { mstore(0x00, 0x65244e4e) // `DivFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(x, d))), div(x, d)) } } /// @dev Returns `max(0, x - y)`. function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(gt(x, y), sub(x, y)) } } /// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`. /// Reverts if the computation overflows. function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`. if x { z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x` let half := shr(1, b) // Divide `b` by 2. // Divide `y` by 2 every iteration. for { y := shr(1, y) } y { y := shr(1, y) } { let xx := mul(x, x) // Store x squared. let xxRound := add(xx, half) // Round to the nearest number. // Revert if `xx + half` overflowed, or if `x ** 2` overflows. if or(lt(xxRound, xx), shr(128, x)) { mstore(0x00, 0x49f7642b) // `RPowOverflow()`. revert(0x1c, 0x04) } x := div(xxRound, b) // Set `x` to scaled `xxRound`. // If `y` is odd: if and(y, 1) { let zx := mul(z, x) // Compute `z * x`. let zxRound := add(zx, half) // Round to the nearest number. // If `z * x` overflowed or `zx + half` overflowed: if or(xor(div(zx, x), z), lt(zxRound, zx)) { // Revert if `x` is non-zero. if iszero(iszero(x)) { mstore(0x00, 0x49f7642b) // `RPowOverflow()`. revert(0x1c, 0x04) } } z := div(zxRound, b) // Return properly scaled `zxRound`. } } } } } /// @dev Returns the square root of `x`. function sqrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // Let `y = x / 2**r`. We check `y >= 2**(k + 8)` // but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`. let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffffff, shr(r, x)))) z := shl(shr(1, r), z) // Goal was to get `z*z*y` within a small factor of `x`. More iterations could // get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`. // We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small. // That's not possible if `x < 256` but we can just verify those cases exhaustively. // Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`. // Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`. // Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps. // For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)` // is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`, // with largest error when `s = 1` and when `s = 256` or `1/256`. // Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`. // Then we can estimate `sqrt(y)` using // `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`. // There is no overflow risk here since `y < 2**136` after the first branch above. z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If `x+1` is a perfect square, the Babylonian method cycles between // `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division z := sub(z, lt(div(x, z), z)) } } /// @dev Returns the cube root of `x`. /// Credit to bout3fiddy and pcaversaccio under AGPLv3 license: /// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy function cbrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3))) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := sub(z, lt(div(x, mul(z, z)), z)) } } /// @dev Returns the square root of `x`, denominated in `WAD`. function sqrtWad(uint256 x) internal pure returns (uint256 z) { unchecked { z = 10 ** 9; if (x <= type(uint256).max / 10 ** 36 - 1) { x *= 10 ** 18; z = 1; } z *= sqrt(x); } } /// @dev Returns the cube root of `x`, denominated in `WAD`. function cbrtWad(uint256 x) internal pure returns (uint256 z) { unchecked { z = 10 ** 12; if (x <= (type(uint256).max / 10 ** 36) * 10 ** 18 - 1) { if (x >= type(uint256).max / 10 ** 36) { x *= 10 ** 18; z = 10 ** 6; } else { x *= 10 ** 36; z = 1; } } z *= cbrt(x); } } /// @dev Returns the factorial of `x`. function factorial(uint256 x) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if iszero(lt(x, 58)) { mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`. revert(0x1c, 0x04) } for { result := 1 } x { x := sub(x, 1) } { result := mul(result, x) } } } /// @dev Returns the log2 of `x`. /// Equivalent to computing the index of the most significant bit (MSB) of `x`. /// Returns 0 if `x` is zero. function log2(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)) } } /// @dev Returns the log2 of `x`, rounded up. /// Returns 0 if `x` is zero. function log2Up(uint256 x) internal pure returns (uint256 r) { r = log2(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(shl(r, 1), x)) } } /// @dev Returns the log10 of `x`. /// Returns 0 if `x` is zero. function log10(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { if iszero(lt(x, 100000000000000000000000000000000000000)) { x := div(x, 100000000000000000000000000000000000000) r := 38 } if iszero(lt(x, 100000000000000000000)) { x := div(x, 100000000000000000000) r := add(r, 20) } if iszero(lt(x, 10000000000)) { x := div(x, 10000000000) r := add(r, 10) } if iszero(lt(x, 100000)) { x := div(x, 100000) r := add(r, 5) } r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999))))) } } /// @dev Returns the log10 of `x`, rounded up. /// Returns 0 if `x` is zero. function log10Up(uint256 x) internal pure returns (uint256 r) { r = log10(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(exp(10, r), x)) } } /// @dev Returns the log256 of `x`. /// Returns 0 if `x` is zero. function log256(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(shr(3, r), lt(0xff, shr(r, x))) } } /// @dev Returns the log256 of `x`, rounded up. /// Returns 0 if `x` is zero. function log256Up(uint256 x) internal pure returns (uint256 r) { r = log256(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(shl(shl(3, r), 1), x)) } } /// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`. /// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent). function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) { /// @solidity memory-safe-assembly assembly { mantissa := x if mantissa { if iszero(mod(mantissa, 1000000000000000000000000000000000)) { mantissa := div(mantissa, 1000000000000000000000000000000000) exponent := 33 } if iszero(mod(mantissa, 10000000000000000000)) { mantissa := div(mantissa, 10000000000000000000) exponent := add(exponent, 19) } if iszero(mod(mantissa, 1000000000000)) { mantissa := div(mantissa, 1000000000000) exponent := add(exponent, 12) } if iszero(mod(mantissa, 1000000)) { mantissa := div(mantissa, 1000000) exponent := add(exponent, 6) } if iszero(mod(mantissa, 10000)) { mantissa := div(mantissa, 10000) exponent := add(exponent, 4) } if iszero(mod(mantissa, 100)) { mantissa := div(mantissa, 100) exponent := add(exponent, 2) } if iszero(mod(mantissa, 10)) { mantissa := div(mantissa, 10) exponent := add(exponent, 1) } } } } /// @dev Convenience function for packing `x` into a smaller number using `sci`. /// The `mantissa` will be in bits [7..255] (the upper 249 bits). /// The `exponent` will be in bits [0..6] (the lower 7 bits). /// Use `SafeCastLib` to safely ensure that the `packed` number is small /// enough to fit in the desired unsigned integer type: /// ``` /// uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether)); /// ``` function packSci(uint256 x) internal pure returns (uint256 packed) { (x, packed) = sci(x); // Reuse for `mantissa` and `exponent`. /// @solidity memory-safe-assembly assembly { if shr(249, x) { mstore(0x00, 0xce30380c) // `MantissaOverflow()`. revert(0x1c, 0x04) } packed := or(shl(7, x), packed) } } /// @dev Convenience function for unpacking a packed number from `packSci`. function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) { unchecked { unpacked = (packed >> 7) * 10 ** (packed & 0x7f); } } /// @dev Returns the average of `x` and `y`. function avg(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = (x & y) + ((x ^ y) >> 1); } } /// @dev Returns the average of `x` and `y`. function avg(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = (x >> 1) + (y >> 1) + (((x & 1) + (y & 1)) >> 1); } } /// @dev Returns the absolute value of `x`. function abs(int256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(sub(0, shr(255, x)), add(sub(0, shr(255, x)), x)) } } /// @dev Returns the absolute distance between `x` and `y`. function dist(int256 x, int256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(mul(xor(sub(y, x), sub(x, y)), sgt(x, y)), sub(y, x)) } } /// @dev Returns the minimum of `x` and `y`. function min(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), lt(y, x))) } } /// @dev Returns the minimum of `x` and `y`. function min(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), slt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), gt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), sgt(y, x))) } } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp(uint256 x, uint256 minValue, uint256 maxValue) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, minValue), gt(minValue, x))) z := xor(z, mul(xor(z, maxValue), lt(maxValue, z))) } } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, minValue), sgt(minValue, x))) z := xor(z, mul(xor(z, maxValue), slt(maxValue, z))) } } /// @dev Returns greatest common divisor of `x` and `y`. function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { for { z := x } y {} { let t := y y := mod(z, y) z := t } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RAW NUMBER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `x + y`, without checking for overflow. function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x + y; } } /// @dev Returns `x + y`, without checking for overflow. function rawAdd(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x + y; } } /// @dev Returns `x - y`, without checking for underflow. function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x - y; } } /// @dev Returns `x - y`, without checking for underflow. function rawSub(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x - y; } } /// @dev Returns `x * y`, without checking for overflow. function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x * y; } } /// @dev Returns `x * y`, without checking for overflow. function rawMul(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x * y; } } /// @dev Returns `x / y`, returning 0 if `y` is zero. function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(x, y) } } /// @dev Returns `x / y`, returning 0 if `y` is zero. function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mod(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function rawSMod(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := smod(x, y) } } /// @dev Returns `(x + y) % d`, return 0 if `d` if zero. function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := addmod(x, y, d) } } /// @dev Returns `(x * y) % d`, return 0 if `d` if zero. function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mulmod(x, y, d) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IWETH } from "src/dispute/interfaces/IWETH.sol"; /// @title IDelayedWETH /// @notice Interface for the DelayedWETH contract. interface IDelayedWETH is IWETH { /// @notice Represents a withdrawal request. struct WithdrawalRequest { uint256 amount; uint256 timestamp; } /// @notice Emitted when an unwrap is started. /// @param src The address that started the unwrap. /// @param wad The amount of WETH that was unwrapped. event Unwrap(address indexed src, uint256 wad); /// @notice Returns the withdrawal delay in seconds. /// @return The withdrawal delay in seconds. function delay() external view returns (uint256); /// @notice Returns a withdrawal request for the given address. /// @param _owner The address to query the withdrawal request of. /// @param _guy Sub-account to query the withdrawal request of. /// @return The withdrawal request for the given address-subaccount pair. function withdrawals(address _owner, address _guy) external view returns (uint256, uint256); /// @notice Unlocks withdrawals for the sender's account, after a time delay. /// @param _guy Sub-account to unlock. /// @param _wad The amount of WETH to unlock. function unlock(address _guy, uint256 _wad) external; /// @notice Extension to withdrawal, must provide a sub-account to withdraw from. /// @param _guy Sub-account to withdraw from. /// @param _wad The amount of WETH to withdraw. function withdraw(address _guy, uint256 _wad) external; /// @notice Allows the owner to recover from error cases by pulling ETH out of the contract. /// @param _wad The amount of WETH to recover. function recover(uint256 _wad) external; /// @notice Allows the owner to recover from error cases by pulling ETH from a specific owner. /// @param _guy The address to recover the WETH from. /// @param _wad The amount of WETH to recover. function hold(address _guy, uint256 _wad) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IInitializable } from "src/dispute/interfaces/IInitializable.sol"; import "src/libraries/DisputeTypes.sol"; /// @title IDisputeGame /// @notice The generic interface for a DisputeGame contract. interface IDisputeGame is IInitializable { /// @notice Emitted when the game is resolved. /// @param status The status of the game after resolution. event Resolved(GameStatus indexed status); /// @notice Returns the timestamp that the DisputeGame contract was created at. /// @return createdAt_ The timestamp that the DisputeGame contract was created at. function createdAt() external view returns (Timestamp createdAt_); /// @notice Returns the timestamp that the DisputeGame contract was resolved at. /// @return resolvedAt_ The timestamp that the DisputeGame contract was resolved at. function resolvedAt() external view returns (Timestamp resolvedAt_); /// @notice Returns the current status of the game. /// @return status_ The current status of the game. function status() external view returns (GameStatus status_); /// @notice Getter for the game type. /// @dev The reference impl should be entirely different depending on the type (fault, validity) /// i.e. The game type should indicate the security model. /// @return gameType_ The type of proof system being used. function gameType() external view returns (GameType gameType_); /// @notice Getter for the root claim. /// @dev `clones-with-immutable-args` argument #1 /// @return rootClaim_ The root claim of the DisputeGame. function rootClaim() external pure returns (Claim rootClaim_); /// @notice Getter for the extra data. /// @dev `clones-with-immutable-args` argument #2 /// @return extraData_ Any extra data supplied to the dispute game contract by the creator. function extraData() external pure returns (bytes memory extraData_); /// @notice If all necessary information has been gathered, this function should mark the game /// status as either `CHALLENGER_WINS` or `DEFENDER_WINS` and return the status of /// the resolved game. It is at this stage that the bonds should be awarded to the /// necessary parties. /// @dev May only be called if the `status` is `IN_PROGRESS`. /// @return status_ The status of the game after resolution. function resolve() external returns (GameStatus status_); /// @notice A compliant implementation of this interface should return the components of the /// game UUID's preimage provided in the cwia payload. The preimage of the UUID is /// constructed as `keccak256(gameType . rootClaim . extraData)` where `.` denotes /// concatenation. /// @return gameType_ The type of proof system being used. /// @return rootClaim_ The root claim of the DisputeGame. /// @return extraData_ Any extra data supplied to the dispute game contract by the creator. function gameData() external view returns (GameType gameType_, Claim rootClaim_, bytes memory extraData_); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IDisputeGame } from "./IDisputeGame.sol"; import "src/libraries/DisputeTypes.sol"; /// @title IFaultDisputeGame /// @notice The interface for a fault proof backed dispute game. interface IFaultDisputeGame is IDisputeGame { /// @notice The `ClaimData` struct represents the data associated with a Claim. struct ClaimData { uint32 parentIndex; address counteredBy; address claimant; uint128 bond; Claim claim; Position position; Clock clock; } /// @notice Emitted when a new claim is added to the DAG by `claimant` /// @param parentIndex The index within the `claimData` array of the parent claim /// @param claim The claim being added /// @param claimant The address of the claimant event Move(uint256 indexed parentIndex, Claim indexed claim, address indexed claimant); /// @notice Attack a disagreed upon `Claim`. /// @param _parentIndex Index of the `Claim` to attack in the `claimData` array. /// @param _claim The `Claim` at the relative attack position. function attack(uint256 _parentIndex, Claim _claim) external payable; /// @notice Defend an agreed upon `Claim`. /// @param _parentIndex Index of the claim to defend in the `claimData` array. /// @param _claim The `Claim` at the relative defense position. function defend(uint256 _parentIndex, Claim _claim) external payable; /// @notice Perform an instruction step via an on-chain fault proof processor. /// @dev This function should point to a fault proof processor in order to execute /// a step in the fault proof program on-chain. The interface of the fault proof /// processor contract should adhere to the `IBigStepper` interface. /// @param _claimIndex The index of the challenged claim within `claimData`. /// @param _isAttack Whether or not the step is an attack or a defense. /// @param _stateData The stateData of the step is the preimage of the claim at the given /// prestate, which is at `_stateIndex` if the move is an attack and `_claimIndex` if /// the move is a defense. If the step is an attack on the first instruction, it is /// the absolute prestate of the fault proof VM. /// @param _proof Proof to access memory nodes in the VM's merkle state tree. function step(uint256 _claimIndex, bool _isAttack, bytes calldata _stateData, bytes calldata _proof) external; /// @notice Posts the requested local data to the VM's `PreimageOralce`. /// @param _ident The local identifier of the data to post. /// @param _execLeafIdx The index of the leaf claim in an execution subgame that requires the local data for a step. /// @param _partOffset The offset of the data to post. function addLocalData(uint256 _ident, uint256 _execLeafIdx, uint256 _partOffset) external; /// @notice Resolves the subgame rooted at the given claim index. /// @dev This function must be called bottom-up in the DAG /// A subgame is a tree of claims that has a maximum depth of 1. /// A subgame root claims is valid if, and only if, all of its child claims are invalid. /// At the deepest level in the DAG, a claim is invalid if there's a successful step against it. /// @param _claimIndex The index of the subgame root claim to resolve. function resolveClaim(uint256 _claimIndex) external payable; /// @notice A block hash on the L1 that contains the disputed output root. function l1Head() external view returns (Hash l1Head_); /// @notice The l2BlockNumber of the disputed output root in the `L2OutputOracle`. function l2BlockNumber() external view returns (uint256 l2BlockNumber_); /// @notice Starting output root and block number of the game. function startingOutputRoot() external view returns (Hash startingRoot_, uint256 l2BlockNumber_); /// @notice Only the starting block number of the game. function startingBlockNumber() external view returns (uint256 startingBlockNumber_); /// @notice Only the starting output root of the game. function startingRootHash() external view returns (Hash startingRootHash_); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title IInitializable /// @notice An interface for initializable contracts. interface IInitializable { /// @notice Initializes the contract. /// @dev This function may only be called once. function initialize() external payable; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IPreimageOracle } from "src/cannon/interfaces/IPreimageOracle.sol"; /// @title IBigStepper /// @notice Describes a state machine that can perform a single instruction step, provided a prestate and an optional /// proof. /// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ /// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣼⠶⢅⠒⢄⢔⣶⡦⣤⡤⠄⣀⠀⠀⠀⠀⠀⠀⠀ /// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠨⡏⠀⠀⠈⠢⣙⢯⣄⠀⢨⠯⡺⡘⢄⠀⠀⠀⠀⠀ /// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣶⡆⠀⠀⠀⠀⠈⠓⠬⡒⠡⣀⢙⡜⡀⠓⠄⠀⠀⠀ /// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡷⠿⣧⣀⡀⠀⠀⠀⠀⠀⠀⠉⠣⣞⠩⠥⠀⠼⢄⠀⠀ /// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠉⢹⣶⠒⠒⠂⠈⠉⠁⠘⡆⠀⣿⣿⠫⡄⠀ /// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⢶⣤⣀⡀⠀⠀⢸⡿⠀⠀⠀⠀⠀⢀⠞⠀⠀⢡⢨⢀⡄⠀ /// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⡒⣿⢿⡤⠝⡣⠉⠁⠚⠛⠀⠤⠤⣄⡰⠁⠀⠀⠀⠉⠙⢸⠀⠀ /// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡤⢯⡌⡿⡇⠘⡷⠀⠁⠀⠀⢀⣰⠢⠲⠛⣈⣸⠦⠤⠶⠴⢬⣐⣊⡂⠀ /// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⡪⡗⢫⠞⠀⠆⣀⠻⠤⠴⠐⠚⣉⢀⠦⠂⠋⠁⠀⠁⠀⠀⠀⠀⢋⠉⠇⠀ /// ⠀⠀⠀⠀⣀⡤⠐⠒⠘⡹⠉⢸⠇⠸⠀⠀⠀⠀⣀⣤⠴⠚⠉⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠼⠀⣾⠀ /// ⠀⠀⠀⡰⠀⠉⠉⠀⠁⠀⠀⠈⢇⠈⠒⠒⠘⠈⢀⢡⡂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠀⢸⡄ /// ⠀⠀⠸⣿⣆⠤⢀⡀⠀⠀⠀⠀⢘⡌⠀⠀⣀⣀⣀⡈⣤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⢸⡇ /// ⠀⠀⢸⣀⠀⠉⠒⠐⠛⠋⠭⠭⠍⠉⠛⠒⠒⠒⠀⠒⠚⠛⠛⠛⠩⠭⠭⠭⠭⠤⠤⠤⠤⠤⠭⠭⠉⠓⡆ /// ⠀⠀⠘⠿⣷⣶⣤⣤⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣤⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇ /// ⠀⠀⠀⠀⠀⠉⠙⠛⠛⠻⠿⢿⣿⣿⣷⣶⣶⣶⣤⣤⣀⣁⣛⣃⣒⠿⠿⠿⠤⠠⠄⠤⠤⢤⣛⣓⣂⣻⡇ /// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠙⠛⠻⠿⠿⠿⢿⣿⣿⣿⣷⣶⣶⣾⣿⣿⣿⣿⠿⠟⠁ /// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠈⠉⠉⠉⠉⠁⠀⠀⠀⠀⠀ interface IBigStepper { /// @notice Performs the state transition from a given prestate and returns the hash of the post state witness. /// @param _stateData The raw opaque prestate data. /// @param _proof Opaque proof data, can be used to prove things about the prestate in relation to the state of the /// interface's implementation. /// @param _localContext The local key context for the preimage oracle. Optional, can be set as a constant if the /// implementation only requires one set of local keys. /// @return postState_ The hash of the post state witness after the state transition. function step( bytes calldata _stateData, bytes calldata _proof, bytes32 _localContext ) external returns (bytes32 postState_); /// @notice Returns the preimage oracle used by the state machine. function oracle() external view returns (IPreimageOracle oracle_); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IDisputeGameFactory } from "src/dispute/interfaces/IDisputeGameFactory.sol"; import "src/libraries/DisputeTypes.sol"; /// @title IAnchorStateRegistry /// @notice Describes a contract that stores the anchor state for each game type. interface IAnchorStateRegistry { /// @notice Returns the anchor state for the given game type. /// @param _gameType The game type to get the anchor state for. /// @return The anchor state for the given game type. function anchors(GameType _gameType) external view returns (Hash, uint256); /// @notice Returns the DisputeGameFactory address. /// @return DisputeGameFactory address. function disputeGameFactory() external view returns (IDisputeGameFactory); /// @notice Callable by FaultDisputeGame contracts to update the anchor state. Pulls the anchor /// state directly from the FaultDisputeGame contract and stores it in the registry if /// the new anchor state is valid and the state is newer than the current anchor state. function tryUpdateAnchorState() external; }
// SPDX-License-Identifier: BSD pragma solidity ^0.8.15; /// @title Clone /// @author zefram.eth, Saw-mon & Natalie, clabby /// @notice Provides helper functions for reading immutable args from calldata /// @dev Original: /// https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args/ /// blob/105efee1b9127ed7f6fedf139e1fc796ce8791f2/src/Clone.sol /// @dev MODIFICATIONS: /// - Added `_getArgDynBytes` function. contract Clone { uint256 private constant ONE_WORD = 0x20; /// @notice Reads an immutable arg with type address /// @param argOffset The offset of the arg in the packed data /// @return arg The arg value function _getArgAddress(uint256 argOffset) internal pure returns (address arg) { uint256 offset = _getImmutableArgsOffset(); assembly { arg := shr(0x60, calldataload(add(offset, argOffset))) } } /// @notice Reads an immutable arg with type uint256 /// @param argOffset The offset of the arg in the packed data /// @return arg The arg value function _getArgUint256(uint256 argOffset) internal pure returns (uint256 arg) { uint256 offset = _getImmutableArgsOffset(); assembly { arg := calldataload(add(offset, argOffset)) } } /// @notice Reads an immutable arg with type bytes32 /// @param argOffset The offset of the arg in the packed data /// @return arg The arg value function _getArgFixedBytes(uint256 argOffset) internal pure returns (bytes32 arg) { uint256 offset = _getImmutableArgsOffset(); assembly { arg := calldataload(add(offset, argOffset)) } } /// @notice Reads a uint256 array stored in the immutable args. /// @param argOffset The offset of the arg in the packed data /// @param arrLen Number of elements in the array /// @return arr The array function _getArgUint256Array(uint256 argOffset, uint64 arrLen) internal pure returns (uint256[] memory arr) { uint256 offset = _getImmutableArgsOffset() + argOffset; arr = new uint256[](arrLen); assembly { calldatacopy(add(arr, ONE_WORD), offset, shl(5, arrLen)) } } /// @notice Reads a dynamic bytes array stored in the immutable args. /// @param argOffset The offset of the arg in the packed data /// @param arrLen Number of elements in the array /// @return arr The array function _getArgDynBytes(uint256 argOffset, uint64 arrLen) internal pure returns (bytes memory arr) { uint256 offset = _getImmutableArgsOffset() + argOffset; arr = new bytes(arrLen); assembly { calldatacopy(add(arr, ONE_WORD), offset, arrLen) } } /// @notice Reads an immutable arg with type uint64 /// @param argOffset The offset of the arg in the packed data /// @return arg The arg value function _getArgUint64(uint256 argOffset) internal pure returns (uint64 arg) { uint256 offset = _getImmutableArgsOffset(); assembly { arg := shr(0xc0, calldataload(add(offset, argOffset))) } } /// @notice Reads an immutable arg with type uint8 /// @param argOffset The offset of the arg in the packed data /// @return arg The arg value function _getArgUint8(uint256 argOffset) internal pure returns (uint8 arg) { uint256 offset = _getImmutableArgsOffset(); assembly { arg := shr(0xf8, calldataload(add(offset, argOffset))) } } /// @return offset The offset of the packed immutable args in calldata function _getImmutableArgsOffset() internal pure returns (uint256 offset) { assembly { offset := sub(calldatasize(), shr(0xf0, calldataload(sub(calldatasize(), 2)))) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title Types /// @notice Contains various types used throughout the Optimism contract system. library Types { /// @notice OutputProposal represents a commitment to the L2 state. The timestamp is the L1 /// timestamp that the output root is posted. This timestamp is used to verify that the /// finalization period has passed since the output root was submitted. /// @custom:field outputRoot Hash of the L2 output. /// @custom:field timestamp Timestamp of the L1 block that the output root was submitted in. /// @custom:field l2BlockNumber L2 block number that the output corresponds to. struct OutputProposal { bytes32 outputRoot; uint128 timestamp; uint128 l2BlockNumber; } /// @notice Struct representing the elements that are hashed together to generate an output root /// which itself represents a snapshot of the L2 state. /// @custom:field version Version of the output root. /// @custom:field stateRoot Root of the state trie at the block of this output. /// @custom:field messagePasserStorageRoot Root of the message passer storage trie. /// @custom:field latestBlockhash Hash of the block this output was generated from. struct OutputRootProof { bytes32 version; bytes32 stateRoot; bytes32 messagePasserStorageRoot; bytes32 latestBlockhash; } /// @notice Struct representing a deposit transaction (L1 => L2 transaction) created by an end /// user (as opposed to a system deposit transaction generated by the system). /// @custom:field from Address of the sender of the transaction. /// @custom:field to Address of the recipient of the transaction. /// @custom:field isCreation True if the transaction is a contract creation. /// @custom:field value Value to send to the recipient. /// @custom:field mint Amount of ETH to mint. /// @custom:field gasLimit Gas limit of the transaction. /// @custom:field data Data of the transaction. /// @custom:field l1BlockHash Hash of the block the transaction was submitted in. /// @custom:field logIndex Index of the log in the block the transaction was submitted in. struct UserDepositTransaction { address from; address to; bool isCreation; uint256 value; uint256 mint; uint64 gasLimit; bytes data; bytes32 l1BlockHash; uint256 logIndex; } /// @notice Struct representing a withdrawal transaction. /// @custom:field nonce Nonce of the withdrawal transaction /// @custom:field sender Address of the sender of the transaction. /// @custom:field target Address of the recipient of the transaction. /// @custom:field value Value to send to the recipient. /// @custom:field gasLimit Gas limit of the transaction. /// @custom:field data Data of the transaction. struct WithdrawalTransaction { uint256 nonce; address sender; address target; uint256 value; uint256 gasLimit; bytes data; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title ISemver /// @notice ISemver is a simple contract for ensuring that contracts are /// versioned using semantic versioning. interface ISemver { /// @notice Getter for the semantic version of the contract. This is not /// meant to be used onchain but instead meant to be used by offchain /// tooling. /// @return Semver contract version as a string. function version() external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.15; import "src/libraries/DisputeTypes.sol"; /// @title LibClock /// @notice This library contains helper functions for working with the `Clock` type. library LibClock { /// @notice Packs a `Duration` and `Timestamp` into a `Clock` type. /// @param _duration The `Duration` to pack into the `Clock` type. /// @param _timestamp The `Timestamp` to pack into the `Clock` type. /// @return clock_ The `Clock` containing the `_duration` and `_timestamp`. function wrap(Duration _duration, Timestamp _timestamp) internal pure returns (Clock clock_) { assembly { clock_ := or(shl(0x40, _duration), _timestamp) } } /// @notice Pull the `Duration` out of a `Clock` type. /// @param _clock The `Clock` type to pull the `Duration` out of. /// @return duration_ The `Duration` pulled out of `_clock`. function duration(Clock _clock) internal pure returns (Duration duration_) { // Shift the high-order 64 bits into the low-order 64 bits, leaving only the `duration`. assembly { duration_ := shr(0x40, _clock) } } /// @notice Pull the `Timestamp` out of a `Clock` type. /// @param _clock The `Clock` type to pull the `Timestamp` out of. /// @return timestamp_ The `Timestamp` pulled out of `_clock`. function timestamp(Clock _clock) internal pure returns (Timestamp timestamp_) { // Clean the high-order 192 bits by shifting the clock left and then right again, leaving // only the `timestamp`. assembly { timestamp_ := shr(0xC0, shl(0xC0, _clock)) } } /// @notice Get the value of a `Clock` type in the form of the underlying uint128. /// @param _clock The `Clock` type to get the value of. /// @return clock_ The value of the `Clock` type as a uint128 type. function raw(Clock _clock) internal pure returns (uint128 clock_) { assembly { clock_ := _clock } } } /// @title LibClaim /// @notice This library contains helper functions for working with the `Claim` type. library LibClaim { /// @notice Get the value of a `Claim` type in the form of the underlying bytes32. /// @param _claim The `Claim` type to get the value of. /// @return claim_ The value of the `Claim` type as a bytes32 type. function raw(Claim _claim) internal pure returns (bytes32 claim_) { assembly { claim_ := _claim } } } /// @title LibDuration /// @notice This library contains helper functions for working with the `Duration` type. library LibDuration { /// @notice Get the value of a `Duration` type in the form of the underlying uint64. /// @param _duration The `Duration` type to get the value of. /// @return duration_ The value of the `Duration` type as a uint64 type. function raw(Duration _duration) internal pure returns (uint64 duration_) { assembly { duration_ := _duration } } } /// @title LibHash /// @notice This library contains helper functions for working with the `Hash` type. library LibHash { /// @notice Get the value of a `Hash` type in the form of the underlying bytes32. /// @param _hash The `Hash` type to get the value of. /// @return hash_ The value of the `Hash` type as a bytes32 type. function raw(Hash _hash) internal pure returns (bytes32 hash_) { assembly { hash_ := _hash } } } /// @title LibTimestamp /// @notice This library contains helper functions for working with the `Timestamp` type. library LibTimestamp { /// @notice Get the value of a `Timestamp` type in the form of the underlying uint64. /// @param _timestamp The `Timestamp` type to get the value of. /// @return timestamp_ The value of the `Timestamp` type as a uint64 type. function raw(Timestamp _timestamp) internal pure returns (uint64 timestamp_) { assembly { timestamp_ := _timestamp } } } /// @title LibVMStatus /// @notice This library contains helper functions for working with the `VMStatus` type. library LibVMStatus { /// @notice Get the value of a `VMStatus` type in the form of the underlying uint8. /// @param _vmstatus The `VMStatus` type to get the value of. /// @return vmstatus_ The value of the `VMStatus` type as a uint8 type. function raw(VMStatus _vmstatus) internal pure returns (uint8 vmstatus_) { assembly { vmstatus_ := _vmstatus } } } /// @title LibGameType /// @notice This library contains helper functions for working with the `GameType` type. library LibGameType { /// @notice Get the value of a `GameType` type in the form of the underlying uint8. /// @param _gametype The `GameType` type to get the value of. /// @return gametype_ The value of the `GameType` type as a uint8 type. function raw(GameType _gametype) internal pure returns (uint8 gametype_) { assembly { gametype_ := _gametype } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.15; import { LibHashing } from "src/dispute/lib/LibHashing.sol"; import { LibClaim, LibHash, LibDuration, LibClock, LibTimestamp, LibVMStatus, LibGameType } from "src/dispute/lib/LibUDT.sol"; import { LibPosition } from "src/dispute/lib/LibPosition.sol"; import { LibGameId } from "src/dispute/lib/LibGameId.sol"; using LibClaim for Claim global; using LibHashing for Claim global; using LibHash for Hash global; using LibPosition for Position global; using LibDuration for Duration global; using LibClock for Clock global; using LibGameId for GameId global; using LibTimestamp for Timestamp global; using LibVMStatus for VMStatus global; using LibGameType for GameType global; /// @notice A custom type for a generic hash. type Hash is bytes32; /// @notice A claim represents an MPT root representing the state of the fault proof program. type Claim is bytes32; /// @notice A claim hash represents a hash of a claim and a position within the game tree. /// @dev Keccak hash of abi.encodePacked(Claim, Position); type ClaimHash is bytes32; /// @notice A bondamount represents the amount of collateral that a user has locked up in a claim. type BondAmount is uint256; /// @notice A dedicated timestamp type. type Timestamp is uint64; /// @notice A dedicated duration type. /// @dev Unit: seconds type Duration is uint64; /// @notice A `GameId` represents a packed 1 byte game ID, an 11 byte timestamp, and a 20 byte address. /// @dev The packed layout of this type is as follows: /// ┌───────────┬───────────┐ /// │ Bits │ Value │ /// ├───────────┼───────────┤ /// │ [0, 8) │ Game Type │ /// │ [8, 96) │ Timestamp │ /// │ [96, 256) │ Address │ /// └───────────┴───────────┘ type GameId is bytes32; /// @notice A `Clock` represents a packed `Duration` and `Timestamp` /// @dev The packed layout of this type is as follows: /// ┌────────────┬────────────────┐ /// │ Bits │ Value │ /// ├────────────┼────────────────┤ /// │ [0, 64) │ Duration │ /// │ [64, 128) │ Timestamp │ /// └────────────┴────────────────┘ type Clock is uint128; /// @notice A `Position` represents a position of a claim within the game tree. /// @dev This is represented as a "generalized index" where the high-order bit /// is the level in the tree and the remaining bits is a unique bit pattern, allowing /// a unique identifier for each node in the tree. Mathematically, it is calculated /// as 2^{depth} + indexAtDepth. type Position is uint128; /// @notice A `GameType` represents the type of game being played. type GameType is uint32; /// @notice A `VMStatus` represents the status of a VM execution. type VMStatus is uint8; /// @notice The current status of the dispute game. enum GameStatus { // The game is currently in progress, and has not been resolved. IN_PROGRESS, // The game has concluded, and the `rootClaim` was challenged successfully. CHALLENGER_WINS, // The game has concluded, and the `rootClaim` could not be contested. DEFENDER_WINS } /// @notice Represents an L2 output root and the L2 block number at which it was generated. /// @custom:field root The output root. /// @custom:field l2BlockNumber The L2 block number at which the output root was generated. struct OutputRoot { Hash root; uint256 l2BlockNumber; } /// @title GameTypes /// @notice A library that defines the IDs of games that can be played. library GameTypes { /// @dev A dispute game type the uses the cannon vm. GameType internal constant CANNON = GameType.wrap(0); /// @dev A permissioned dispute game type the uses the cannon vm. GameType internal constant PERMISSIONED_CANNON = GameType.wrap(1); /// @notice A dispute game type that uses an alphabet vm. /// Not intended for production use. GameType internal constant ALPHABET = GameType.wrap(255); } /// @title VMStatuses /// @notice Named type aliases for the various valid VM status bytes. library VMStatuses { /// @notice The VM has executed successfully and the outcome is valid. VMStatus internal constant VALID = VMStatus.wrap(0); /// @notice The VM has executed successfully and the outcome is invalid. VMStatus internal constant INVALID = VMStatus.wrap(1); /// @notice The VM has paniced. VMStatus internal constant PANIC = VMStatus.wrap(2); /// @notice The VM execution is still in progress. VMStatus internal constant UNFINISHED = VMStatus.wrap(3); } /// @title LocalPreimageKey /// @notice Named type aliases for local `PreimageOracle` key identifiers. library LocalPreimageKey { /// @notice The identifier for the L1 head hash. uint256 internal constant L1_HEAD_HASH = 0x01; /// @notice The identifier for the starting output root. uint256 internal constant STARTING_OUTPUT_ROOT = 0x02; /// @notice The identifier for the disputed output root. uint256 internal constant DISPUTED_OUTPUT_ROOT = 0x03; /// @notice The identifier for the disputed L2 block number. uint256 internal constant DISPUTED_L2_BLOCK_NUMBER = 0x04; /// @notice The identifier for the chain ID. uint256 internal constant CHAIN_ID = 0x05; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.15; import "src/libraries/DisputeTypes.sol"; //////////////////////////////////////////////////////////////// // `DisputeGameFactory` Errors // //////////////////////////////////////////////////////////////// /// @notice Thrown when a dispute game is attempted to be created with an unsupported game type. /// @param gameType The unsupported game type. error NoImplementation(GameType gameType); /// @notice Thrown when a dispute game that already exists is attempted to be created. /// @param uuid The UUID of the dispute game that already exists. error GameAlreadyExists(Hash uuid); /// @notice Thrown when the root claim has an unexpected VM status. /// Some games can only start with a root-claim with a specific status. /// @param rootClaim is the claim that was unexpected. error UnexpectedRootClaim(Claim rootClaim); //////////////////////////////////////////////////////////////// // `FaultDisputeGame` Errors // //////////////////////////////////////////////////////////////// /// @notice Thrown when a dispute game has already been initialized. error AlreadyInitialized(); /// @notice Thrown when a supplied bond is too low to cover the cost of the interaction. error InsufficientBond(); /// @notice Thrown when a credit claim is attempted for a value of 0. error NoCreditToClaim(); /// @notice Thrown when the transfer of credit to a recipient account reverts. error BondTransferFailed(); /// @notice Thrown when the `extraData` passed to the CWIA proxy is too long for the `FaultDisputeGame`. error ExtraDataTooLong(); /// @notice Thrown when a defense against the root claim is attempted. error CannotDefendRootClaim(); /// @notice Thrown when a claim is attempting to be made that already exists. error ClaimAlreadyExists(); /// @notice Thrown when a given claim is invalid (0). error InvalidClaim(); /// @notice Thrown when an action that requires the game to be `IN_PROGRESS` is invoked when /// the game is not in progress. error GameNotInProgress(); /// @notice Thrown when a move is attempted to be made after the clock has timed out. error ClockTimeExceeded(); /// @notice Thrown when the game is attempted to be resolved too early. error ClockNotExpired(); /// @notice Thrown when a move is attempted to be made at or greater than the max depth of the game. error GameDepthExceeded(); /// @notice Thrown when a step is attempted above the maximum game depth. error InvalidParent(); /// @notice Thrown when an invalid prestate is supplied to `step`. error InvalidPrestate(); /// @notice Thrown when a step is made that computes the expected post state correctly. error ValidStep(); /// @notice Thrown when a game is attempted to be initialized with an L1 head that does /// not contain the disputed output root. error L1HeadTooOld(); /// @notice Thrown when an invalid local identifier is passed to the `addLocalData` function. error InvalidLocalIdent(); /// @notice Thrown when resolving claims out of order. error OutOfOrderResolution(); /// @notice Thrown when resolving a claim that has already been resolved. error ClaimAlreadyResolved(); /// @notice Thrown when a parent output root is attempted to be found on a claim that is in /// the output root portion of the tree. error ClaimAboveSplit(); /// @notice Thrown on deployment if the split depth is greater than or equal to the max /// depth of the game. error InvalidSplitDepth(); /// @notice Thrown when trying to step against a claim for a second time, after it has already been countered with /// an instruction step. error DuplicateStep(); /// @notice Thrown when an anchor root is not found for a given game type. error AnchorRootNotFound(); //////////////////////////////////////////////////////////////// // `PermissionedDisputeGame` Errors // //////////////////////////////////////////////////////////////// /// @notice Thrown when an unauthorized address attempts to interact with the game. error BadAuth();
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title IWETH /// @notice Interface for WETH9. interface IWETH { /// @notice Emitted when an approval is made. /// @param src The address that approved the transfer. /// @param guy The address that was approved to transfer. /// @param wad The amount that was approved to transfer. event Approval(address indexed src, address indexed guy, uint256 wad); /// @notice Emitted when a transfer is made. /// @param src The address that transferred the WETH. /// @param dst The address that received the WETH. /// @param wad The amount of WETH that was transferred. event Transfer(address indexed src, address indexed dst, uint256 wad); /// @notice Emitted when a deposit is made. /// @param dst The address that deposited the WETH. /// @param wad The amount of WETH that was deposited. event Deposit(address indexed dst, uint256 wad); /// @notice Emitted when a withdrawal is made. /// @param src The address that withdrew the WETH. /// @param wad The amount of WETH that was withdrawn. event Withdrawal(address indexed src, uint256 wad); /// @notice Returns the name of the token. /// @return The name of the token. function name() external pure returns (string memory); /// @notice Returns the symbol of the token. /// @return The symbol of the token. function symbol() external pure returns (string memory); /// @notice Returns the number of decimals the token uses. /// @return The number of decimals the token uses. function decimals() external pure returns (uint8); /// @notice Returns the balance of the given address. /// @param owner The address to query the balance of. /// @return The balance of the given address. function balanceOf(address owner) external view returns (uint256); /// @notice Returns the amount of WETH that the spender can transfer on behalf of the owner. /// @param owner The address that owns the WETH. /// @param spender The address that is approved to transfer the WETH. /// @return The amount of WETH that the spender can transfer on behalf of the owner. function allowance(address owner, address spender) external view returns (uint256); /// @notice Allows WETH to be deposited by sending ether to the contract. function deposit() external payable; /// @notice Withdraws an amount of ETH. /// @param wad The amount of ETH to withdraw. function withdraw(uint256 wad) external; /// @notice Returns the total supply of WETH. /// @return The total supply of WETH. function totalSupply() external view returns (uint256); /// @notice Approves the given address to transfer the WETH on behalf of the caller. /// @param guy The address that is approved to transfer the WETH. /// @param wad The amount that is approved to transfer. /// @return True if the approval was successful. function approve(address guy, uint256 wad) external returns (bool); /// @notice Transfers the given amount of WETH to the given address. /// @param dst The address to transfer the WETH to. /// @param wad The amount of WETH to transfer. /// @return True if the transfer was successful. function transfer(address dst, uint256 wad) external returns (bool); /// @notice Transfers the given amount of WETH from the given address to the given address. /// @param src The address to transfer the WETH from. /// @param dst The address to transfer the WETH to. /// @param wad The amount of WETH to transfer. /// @return True if the transfer was successful. function transferFrom(address src, address dst, uint256 wad) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.15; /// @title IPreimageOracle /// @notice Interface for a preimage oracle. interface IPreimageOracle { /// @notice Reads a preimage from the oracle. /// @param _key The key of the preimage to read. /// @param _offset The offset of the preimage to read. /// @return dat_ The preimage data. /// @return datLen_ The length of the preimage data. function readPreimage(bytes32 _key, uint256 _offset) external view returns (bytes32 dat_, uint256 datLen_); /// @notice Loads of local data part into the preimage oracle. /// @param _ident The identifier of the local data. /// @param _localContext The local key context for the preimage oracle. Optionally, can be set as a constant /// if the caller only requires one set of local keys. /// @param _word The local data word. /// @param _size The number of bytes in `_word` to load. /// @param _partOffset The offset of the local data part to write to the oracle. /// @dev The local data parts are loaded into the preimage oracle under the context /// of the caller - no other account can write to the caller's context /// specific data. /// /// There are 5 local data identifiers: /// ┌────────────┬────────────────────────┐ /// │ Identifier │ Data │ /// ├────────────┼────────────────────────┤ /// │ 1 │ L1 Head Hash (bytes32) │ /// │ 2 │ Output Root (bytes32) │ /// │ 3 │ Root Claim (bytes32) │ /// │ 4 │ L2 Block Number (u64) │ /// │ 5 │ Chain ID (u64) │ /// └────────────┴────────────────────────┘ function loadLocalData( uint256 _ident, bytes32 _localContext, bytes32 _word, uint256 _size, uint256 _partOffset ) external returns (bytes32 key_); /// @notice Prepares a preimage to be read by keccak256 key, starting at the given offset and up to 32 bytes /// (clipped at preimage length, if out of data). /// @param _partOffset The offset of the preimage to read. /// @param _preimage The preimage data. function loadKeccak256PreimagePart(uint256 _partOffset, bytes calldata _preimage) external; /// @notice Prepares a preimage to be read by sha256 key, starting at the given offset and up to 32 bytes /// (clipped at preimage length, if out of data). /// @param _partOffset The offset of the preimage to read. /// @param _preimage The preimage data. function loadSha256PreimagePart(uint256 _partOffset, bytes calldata _preimage) external; /// @notice Verifies that `p(_z) = _y` given `_commitment` that corresponds to the polynomial `p(x)` and a KZG // proof. The value `y` is the pre-image, and the preimage key is `5 ++ keccak256(_commitment ++ z)[1:]`. /// @param _z Big endian point value. Part of the preimage key. /// @param _y Big endian point value. The preimage for the key. /// @param _commitment The commitment to the polynomial. 48 bytes, part of the preimage key. /// @param _proof The KZG proof, part of the preimage key. /// @param _partOffset The offset of the preimage to store. function loadBlobPreimagePart( uint256 _z, uint256 _y, bytes calldata _commitment, bytes calldata _proof, uint256 _partOffset ) external; /// @notice Prepares a precompile result to be read by a precompile key for the specified offset. /// The precompile result data is a concatenation of the precompile call status byte and its return data. /// The preimage key is `6 ++ keccak256(precompile ++ input)[1:]`. /// @param _partOffset The offset of the precompile result being loaded. /// @param _precompile The precompile address /// @param _input The input to the precompile call. function loadPrecompilePreimagePart(uint256 _partOffset, address _precompile, bytes calldata _input) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IDisputeGame } from "./IDisputeGame.sol"; import "src/libraries/DisputeTypes.sol"; /// @title IDisputeGameFactory /// @notice The interface for a DisputeGameFactory contract. interface IDisputeGameFactory { /// @notice Emitted when a new dispute game is created /// @param disputeProxy The address of the dispute game proxy /// @param gameType The type of the dispute game proxy's implementation /// @param rootClaim The root claim of the dispute game event DisputeGameCreated(address indexed disputeProxy, GameType indexed gameType, Claim indexed rootClaim); /// @notice Emitted when a new game implementation added to the factory /// @param impl The implementation contract for the given `GameType`. /// @param gameType The type of the DisputeGame. event ImplementationSet(address indexed impl, GameType indexed gameType); /// @notice Emitted when a game type's initialization bond is updated /// @param gameType The type of the DisputeGame. /// @param newBond The new bond (in wei) for initializing the game type. event InitBondUpdated(GameType indexed gameType, uint256 indexed newBond); /// @notice Information about a dispute game found in a `findLatestGames` search. struct GameSearchResult { uint256 index; GameId metadata; Timestamp timestamp; Claim rootClaim; bytes extraData; } /// @notice The total number of dispute games created by this factory. /// @return gameCount_ The total number of dispute games created by this factory. function gameCount() external view returns (uint256 gameCount_); /// @notice `games` queries an internal mapping that maps the hash of /// `gameType ++ rootClaim ++ extraData` to the deployed `DisputeGame` clone. /// @dev `++` equates to concatenation. /// @param _gameType The type of the DisputeGame - used to decide the proxy implementation /// @param _rootClaim The root claim of the DisputeGame. /// @param _extraData Any extra data that should be provided to the created dispute game. /// @return proxy_ The clone of the `DisputeGame` created with the given parameters. /// Returns `address(0)` if nonexistent. /// @return timestamp_ The timestamp of the creation of the dispute game. function games( GameType _gameType, Claim _rootClaim, bytes calldata _extraData ) external view returns (IDisputeGame proxy_, Timestamp timestamp_); /// @notice `gameAtIndex` returns the dispute game contract address and its creation timestamp /// at the given index. Each created dispute game increments the underlying index. /// @param _index The index of the dispute game. /// @return gameType_ The type of the DisputeGame - used to decide the proxy implementation. /// @return timestamp_ The timestamp of the creation of the dispute game. /// @return proxy_ The clone of the `DisputeGame` created with the given parameters. /// Returns `address(0)` if nonexistent. function gameAtIndex(uint256 _index) external view returns (GameType gameType_, Timestamp timestamp_, IDisputeGame proxy_); /// @notice `gameImpls` is a mapping that maps `GameType`s to their respective /// `IDisputeGame` implementations. /// @param _gameType The type of the dispute game. /// @return impl_ The address of the implementation of the game type. /// Will be cloned on creation of a new dispute game with the given `gameType`. function gameImpls(GameType _gameType) external view returns (IDisputeGame impl_); /// @notice Returns the required bonds for initializing a dispute game of the given type. /// @param _gameType The type of the dispute game. /// @return bond_ The required bond for initializing a dispute game of the given type. function initBonds(GameType _gameType) external view returns (uint256 bond_); /// @notice Creates a new DisputeGame proxy contract. /// @param _gameType The type of the DisputeGame - used to decide the proxy implementation. /// @param _rootClaim The root claim of the DisputeGame. /// @param _extraData Any extra data that should be provided to the created dispute game. /// @return proxy_ The address of the created DisputeGame proxy. function create( GameType _gameType, Claim _rootClaim, bytes calldata _extraData ) external payable returns (IDisputeGame proxy_); /// @notice Sets the implementation contract for a specific `GameType`. /// @dev May only be called by the `owner`. /// @param _gameType The type of the DisputeGame. /// @param _impl The implementation contract for the given `GameType`. function setImplementation(GameType _gameType, IDisputeGame _impl) external; /// @notice Sets the bond (in wei) for initializing a game type. /// @dev May only be called by the `owner`. /// @param _gameType The type of the DisputeGame. /// @param _initBond The bond (in wei) for initializing a game type. function setInitBond(GameType _gameType, uint256 _initBond) external; /// @notice Returns a unique identifier for the given dispute game parameters. /// @dev Hashes the concatenation of `gameType . rootClaim . extraData` /// without expanding memory. /// @param _gameType The type of the DisputeGame. /// @param _rootClaim The root claim of the DisputeGame. /// @param _extraData Any extra data that should be provided to the created dispute game. /// @return uuid_ The unique identifier for the given dispute game parameters. function getGameUUID( GameType _gameType, Claim _rootClaim, bytes memory _extraData ) external pure returns (Hash uuid_); /// @notice Finds the `_n` most recent `GameId`'s of type `_gameType` starting at `_start`. If there are less than /// `_n` games of type `_gameType` starting at `_start`, then the returned array will be shorter than `_n`. /// @param _gameType The type of game to find. /// @param _start The index to start the reverse search from. /// @param _n The number of games to find. function findLatestGames( GameType _gameType, uint256 _start, uint256 _n ) external view returns (GameSearchResult[] memory games_); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.15; import "src/libraries/DisputeTypes.sol"; /// @title Hashing /// @notice This library contains all of the hashing utilities used in the Cannon contracts. library LibHashing { /// @notice Hashes a claim and a position together. /// @param _claim A Claim type. /// @param _position The position of `claim`. /// @param _challengeIndex The index of the claim being moved against. /// @return claimHash_ A hash of abi.encodePacked(claim, position|challengeIndex); function hashClaimPos( Claim _claim, Position _position, uint256 _challengeIndex ) internal pure returns (ClaimHash claimHash_) { assembly { mstore(0x00, _claim) mstore(0x20, or(shl(128, _position), and(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, _challengeIndex))) claimHash_ := keccak256(0x00, 0x40) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.15; import "src/libraries/DisputeTypes.sol"; import "src/libraries/DisputeErrors.sol"; /// @title LibPosition /// @notice This library contains helper functions for working with the `Position` type. library LibPosition { /// @notice Computes a generalized index (2^{depth} + indexAtDepth). /// @param _depth The depth of the position. /// @param _indexAtDepth The index at the depth of the position. /// @return position_ The computed generalized index. function wrap(uint64 _depth, uint64 _indexAtDepth) internal pure returns (Position position_) { assembly { // gindex = 2^{_depth} + _indexAtDepth position_ := add(shl(_depth, 1), _indexAtDepth) } } /// @notice Pulls the `depth` out of a `Position` type. /// @param _position The generalized index to get the `depth` of. /// @return depth_ The `depth` of the `position` gindex. /// @custom:attribution Solady <https://github.com/Vectorized/Solady> function depth(Position _position) internal pure returns (uint64 depth_) { // Return the most significant bit offset, which signifies the depth of the gindex. assembly { depth_ := or(depth_, shl(6, lt(0xffffffffffffffff, shr(depth_, _position)))) depth_ := or(depth_, shl(5, lt(0xffffffff, shr(depth_, _position)))) // For the remaining 32 bits, use a De Bruijn lookup. _position := shr(depth_, _position) _position := or(_position, shr(1, _position)) _position := or(_position, shr(2, _position)) _position := or(_position, shr(4, _position)) _position := or(_position, shr(8, _position)) _position := or(_position, shr(16, _position)) depth_ := or( depth_, byte( shr(251, mul(_position, shl(224, 0x07c4acdd))), 0x0009010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f ) ) } } /// @notice Pulls the `indexAtDepth` out of a `Position` type. /// The `indexAtDepth` is the left/right index of a position at a specific depth within /// the binary tree, starting from index 0. For example, at gindex 2, the `depth` = 1 /// and the `indexAtDepth` = 0. /// @param _position The generalized index to get the `indexAtDepth` of. /// @return indexAtDepth_ The `indexAtDepth` of the `position` gindex. function indexAtDepth(Position _position) internal pure returns (uint64 indexAtDepth_) { // Return bits p_{msb-1}...p_{0}. This effectively pulls the 2^{depth} out of the gindex, // leaving only the `indexAtDepth`. uint256 msb = depth(_position); assembly { indexAtDepth_ := sub(_position, shl(msb, 1)) } } /// @notice Get the left child of `_position`. /// @param _position The position to get the left position of. /// @return left_ The position to the left of `position`. function left(Position _position) internal pure returns (Position left_) { assembly { left_ := shl(1, _position) } } /// @notice Get the right child of `_position` /// @param _position The position to get the right position of. /// @return right_ The position to the right of `position`. function right(Position _position) internal pure returns (Position right_) { assembly { right_ := or(1, shl(1, _position)) } } /// @notice Get the parent position of `_position`. /// @param _position The position to get the parent position of. /// @return parent_ The parent position of `position`. function parent(Position _position) internal pure returns (Position parent_) { assembly { parent_ := shr(1, _position) } } /// @notice Get the deepest, right most gindex relative to the `position`. This is equivalent to /// calling `right` on a position until the maximum depth is reached. /// @param _position The position to get the relative deepest, right most gindex of. /// @param _maxDepth The maximum depth of the game. /// @return rightIndex_ The deepest, right most gindex relative to the `position`. function rightIndex(Position _position, uint256 _maxDepth) internal pure returns (Position rightIndex_) { uint256 msb = depth(_position); assembly { let remaining := sub(_maxDepth, msb) rightIndex_ := or(shl(remaining, _position), sub(shl(remaining, 1), 1)) } } /// @notice Get the deepest, right most trace index relative to the `position`. This is /// equivalent to calling `right` on a position until the maximum depth is reached and /// then finding its index at depth. /// @param _position The position to get the relative trace index of. /// @param _maxDepth The maximum depth of the game. /// @return traceIndex_ The trace index relative to the `position`. function traceIndex(Position _position, uint256 _maxDepth) internal pure returns (uint256 traceIndex_) { uint256 msb = depth(_position); assembly { let remaining := sub(_maxDepth, msb) traceIndex_ := sub(or(shl(remaining, _position), sub(shl(remaining, 1), 1)), shl(_maxDepth, 1)) } } /// @notice Gets the position of the highest ancestor of `_position` that commits to the same /// trace index. /// @param _position The position to get the highest ancestor of. /// @return ancestor_ The highest ancestor of `position` that commits to the same trace index. function traceAncestor(Position _position) internal pure returns (Position ancestor_) { // Create a field with only the lowest unset bit of `_position` set. Position lsb; assembly { lsb := and(not(_position), add(_position, 1)) } // Find the index of the lowest unset bit within the field. uint256 msb = depth(lsb); // The highest ancestor that commits to the same trace index is the original position // shifted right by the index of the lowest unset bit. assembly { let a := shr(msb, _position) // Bound the ancestor to the minimum gindex, 1. ancestor_ := or(a, iszero(a)) } } /// @notice Gets the position of the highest ancestor of `_position` that commits to the same /// trace index, while still being below `_upperBoundExclusive`. /// @param _position The position to get the highest ancestor of. /// @param _upperBoundExclusive The exclusive upper depth bound, used to inform where to stop in order /// to not escape a sub-tree. /// @return ancestor_ The highest ancestor of `position` that commits to the same trace index. function traceAncestorBounded( Position _position, uint256 _upperBoundExclusive ) internal pure returns (Position ancestor_) { // This function only works for positions that are below the upper bound. if (_position.depth() <= _upperBoundExclusive) revert ClaimAboveSplit(); // Grab the global trace ancestor. ancestor_ = traceAncestor(_position); // If the ancestor is above or at the upper bound, shift it to be below the upper bound. // This should be a special case that only covers positions that commit to the final leaf // in a sub-tree. if (ancestor_.depth() <= _upperBoundExclusive) { ancestor_ = ancestor_.rightIndex(_upperBoundExclusive + 1); } } /// @notice Get the move position of `_position`, which is the left child of: /// 1. `_position` if `_isAttack` is true. /// 2. `_position | 1` if `_isAttack` is false. /// @param _position The position to get the relative attack/defense position of. /// @param _isAttack Whether or not the move is an attack move. /// @return move_ The move position relative to `position`. function move(Position _position, bool _isAttack) internal pure returns (Position move_) { assembly { move_ := shl(1, or(iszero(_isAttack), _position)) } } /// @notice Get the value of a `Position` type in the form of the underlying uint128. /// @param _position The position to get the value of. /// @return raw_ The value of the `position` as a uint128 type. function raw(Position _position) internal pure returns (uint128 raw_) { assembly { raw_ := _position } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.15; import "src/libraries/DisputeTypes.sol"; import "src/dispute/interfaces/IDisputeGame.sol"; /// @title LibGameId /// @notice Utility functions for packing and unpacking GameIds. library LibGameId { /// @notice Packs values into a 32 byte GameId type. /// @param _gameType The game type. /// @param _timestamp The timestamp of the game's creation. /// @param _gameProxy The game proxy address. /// @return gameId_ The packed GameId. function pack( GameType _gameType, Timestamp _timestamp, IDisputeGame _gameProxy ) internal pure returns (GameId gameId_) { assembly { gameId_ := or(or(shl(224, _gameType), shl(160, _timestamp)), _gameProxy) } } /// @notice Unpacks values from a 32 byte GameId type. /// @param _gameId The packed GameId. /// @return gameType_ The game type. /// @return timestamp_ The timestamp of the game's creation. /// @return gameProxy_ The game proxy address. function unpack(GameId _gameId) internal pure returns (GameType gameType_, Timestamp timestamp_, IDisputeGame gameProxy_) { assembly { gameType_ := shr(224, _gameId) timestamp_ := and(shr(160, _gameId), 0xFFFFFFFFFFFFFFFF) gameProxy_ := and(_gameId, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) } } }
{ "remappings": [ "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@rari-capital/solmate/=lib/solmate/", "@cwia/=lib/clones-with-immutable-args/src/", "@lib-keccak/=lib/lib-keccak/contracts/lib/", "forge-std/=lib/forge-std/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "safe-contracts/=lib/safe-contracts/contracts/", "kontrol-cheatcodes/=lib/kontrol-cheatcodes/src/", "solady/=lib/solady/src/", "@solady-test/=lib/lib-keccak/lib/solady/test/", "@solady/=lib/lib-keccak/lib/solady/src/", "clones-with-immutable-args/=lib/clones-with-immutable-args/src/", "lib-keccak/=lib/lib-keccak/contracts/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "solmate/=lib/solmate/src/" ], "optimizer": { "enabled": true, "runs": 999999 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract ABI
API[{"inputs":[{"internalType":"GameType","name":"_gameType","type":"uint32"},{"internalType":"Claim","name":"_absolutePrestate","type":"bytes32"},{"internalType":"uint256","name":"_maxGameDepth","type":"uint256"},{"internalType":"uint256","name":"_splitDepth","type":"uint256"},{"internalType":"Duration","name":"_gameDuration","type":"uint64"},{"internalType":"contract IBigStepper","name":"_vm","type":"address"},{"internalType":"contract IDelayedWETH","name":"_weth","type":"address"},{"internalType":"contract IAnchorStateRegistry","name":"_anchorStateRegistry","type":"address"},{"internalType":"uint256","name":"_l2ChainId","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AnchorRootNotFound","type":"error"},{"inputs":[],"name":"BondTransferFailed","type":"error"},{"inputs":[],"name":"CannotDefendRootClaim","type":"error"},{"inputs":[],"name":"ClaimAboveSplit","type":"error"},{"inputs":[],"name":"ClaimAlreadyExists","type":"error"},{"inputs":[],"name":"ClaimAlreadyResolved","type":"error"},{"inputs":[],"name":"ClockNotExpired","type":"error"},{"inputs":[],"name":"ClockTimeExceeded","type":"error"},{"inputs":[],"name":"DuplicateStep","type":"error"},{"inputs":[],"name":"GameDepthExceeded","type":"error"},{"inputs":[],"name":"GameNotInProgress","type":"error"},{"inputs":[],"name":"InsufficientBond","type":"error"},{"inputs":[],"name":"InvalidLocalIdent","type":"error"},{"inputs":[],"name":"InvalidParent","type":"error"},{"inputs":[],"name":"InvalidPrestate","type":"error"},{"inputs":[],"name":"InvalidSplitDepth","type":"error"},{"inputs":[],"name":"NoCreditToClaim","type":"error"},{"inputs":[],"name":"OutOfOrderResolution","type":"error"},{"inputs":[{"internalType":"Claim","name":"rootClaim","type":"bytes32"}],"name":"UnexpectedRootClaim","type":"error"},{"inputs":[],"name":"ValidStep","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"parentIndex","type":"uint256"},{"indexed":true,"internalType":"Claim","name":"claim","type":"bytes32"},{"indexed":true,"internalType":"address","name":"claimant","type":"address"}],"name":"Move","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum GameStatus","name":"status","type":"uint8"}],"name":"Resolved","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"absolutePrestate","outputs":[{"internalType":"Claim","name":"absolutePrestate_","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ident","type":"uint256"},{"internalType":"uint256","name":"_execLeafIdx","type":"uint256"},{"internalType":"uint256","name":"_partOffset","type":"uint256"}],"name":"addLocalData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_parentIndex","type":"uint256"},{"internalType":"Claim","name":"_claim","type":"bytes32"}],"name":"attack","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimCredit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"claimData","outputs":[{"internalType":"uint32","name":"parentIndex","type":"uint32"},{"internalType":"address","name":"counteredBy","type":"address"},{"internalType":"address","name":"claimant","type":"address"},{"internalType":"uint128","name":"bond","type":"uint128"},{"internalType":"Claim","name":"claim","type":"bytes32"},{"internalType":"Position","name":"position","type":"uint128"},{"internalType":"Clock","name":"clock","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimDataLen","outputs":[{"internalType":"uint256","name":"len_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimedBondFlag","outputs":[{"internalType":"uint128","name":"claimedBondFlag_","type":"uint128"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"createdAt","outputs":[{"internalType":"Timestamp","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"credit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_parentIndex","type":"uint256"},{"internalType":"Claim","name":"_claim","type":"bytes32"}],"name":"defend","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"extraData","outputs":[{"internalType":"bytes","name":"extraData_","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"gameData","outputs":[{"internalType":"GameType","name":"gameType_","type":"uint32"},{"internalType":"Claim","name":"rootClaim_","type":"bytes32"},{"internalType":"bytes","name":"extraData_","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gameDuration","outputs":[{"internalType":"Duration","name":"gameDuration_","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gameType","outputs":[{"internalType":"GameType","name":"gameType_","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Position","name":"_position","type":"uint128"}],"name":"getRequiredBond","outputs":[{"internalType":"uint256","name":"requiredBond_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"l1Head","outputs":[{"internalType":"Hash","name":"l1Head_","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"l2BlockNumber","outputs":[{"internalType":"uint256","name":"l2BlockNumber_","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"l2ChainId","outputs":[{"internalType":"uint256","name":"l2ChainId_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxGameDepth","outputs":[{"internalType":"uint256","name":"maxGameDepth_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_challengeIndex","type":"uint256"},{"internalType":"Claim","name":"_claim","type":"bytes32"},{"internalType":"bool","name":"_isAttack","type":"bool"}],"name":"move","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"resolve","outputs":[{"internalType":"enum GameStatus","name":"status_","type":"uint8"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_claimIndex","type":"uint256"}],"name":"resolveClaim","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"resolvedAt","outputs":[{"internalType":"Timestamp","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rootClaim","outputs":[{"internalType":"Claim","name":"rootClaim_","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"splitDepth","outputs":[{"internalType":"uint256","name":"splitDepth_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startingBlockNumber","outputs":[{"internalType":"uint256","name":"startingBlockNumber_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startingOutputRoot","outputs":[{"internalType":"Hash","name":"root","type":"bytes32"},{"internalType":"uint256","name":"l2BlockNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startingRootHash","outputs":[{"internalType":"Hash","name":"startingRootHash_","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"status","outputs":[{"internalType":"enum GameStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_claimIndex","type":"uint256"},{"internalType":"bool","name":"_isAttack","type":"bool"},{"internalType":"bytes","name":"_stateData","type":"bytes"},{"internalType":"bytes","name":"_proof","type":"bytes"}],"name":"step","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vm","outputs":[{"internalType":"contract IBigStepper","name":"vm_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IDelayedWETH","name":"weth_","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6101a06040523480156200001257600080fd5b5060405162004988380380620049888339810160408190526200003591620000d0565b868610620000565760405163e62ccf3960e01b815260040160405180910390fd5b63ffffffff9098166101205260809690965260a09490945260c0929092526001600160401b031660e0526001600160a01b03908116610100529081166101405216610160526101805262000183565b6001600160a01b0381168114620000bb57600080fd5b50565b8051620000cb81620000a5565b919050565b60008060008060008060008060006101208a8c031215620000f057600080fd5b895163ffffffff811681146200010557600080fd5b60208b015160408c015160608d015160808e0151939c50919a50985096506001600160401b03811681146200013957600080fd5b60a08b01519095506200014c81620000a5565b93506200015c60c08b01620000be565b92506200016c60e08b01620000be565b91506101008a015190509295985092959850929598565b60805160a05160c05160e05161010051610120516101405161016051610180516146d7620002b1600039600081816106a7015261267d015260008181610a02015261157a01526000818161033801528181610b5701528181611430015281816119310152613b9d0152600081816105260152818161153901526127170152600081816102e401528181611fea01526123460152600081816106fa0152818161105b015261287501526000818161072d01528181610e4801528181610f1101528181611e450152818161254501528181612cb6015281816133f3015281816135210152818161362901526137050152600081816107cf01528181610eb401528181611aa301528181611b2901528181611d340152611e660152600081816104eb0152611efc01526146d76000f3fe6080604052600436106101ff5760003560e01c80638d450a951161010e578063d6ae3cd5116100a7578063f3f7214e11610079578063fa24f74311610061578063fa24f7431461079c578063fa315aa9146107c0578063fdffbb28146107f357005b8063f3f7214e14610751578063f8f43ff61461077c57005b8063d6ae3cd514610698578063d8cc1a3c146106cb578063e1f0c376146106eb578063ec5e63081461071e57005b8063c55cd0c7116100e0578063c55cd0c7146105ad578063c6f0308c146105c0578063cf09e0d01461064a578063d5d44d801461066b57005b80638d450a95146104dc578063bbdc02db1461050f578063bcef3b5514610550578063c395e1ca1461058d57005b806357da950e116101985780636361506d1161016a5780638129fc1c116101525780638129fc1c1461047f5780638980e0cc146104875780638b85902b1461049c57005b80636361506d1461042a57806370872aa51461046a57005b806357da950e146103b2578063609d3334146103e257806360e27464146103f7578063632247ea1461041757005b806335fef567116101d157806335fef567146102c25780633a768463146102d55780633fc8cef31461032957806354fd4d501461035c57005b806319effeb414610208578063200d2ed21461025357806325fc2ace1461028e5780632810e1d6146102ad57005b3661020657005b005b34801561021457600080fd5b506000546102359068010000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020015b60405180910390f35b34801561025f57600080fd5b5060005461028190700100000000000000000000000000000000900460ff1681565b60405161024a9190613f78565b34801561029a57600080fd5b506006545b60405190815260200161024a565b3480156102b957600080fd5b50610281610806565b6102066102d0366004613fb9565b610a83565b3480156102e157600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161024a565b34801561033557600080fd5b507f0000000000000000000000000000000000000000000000000000000000000000610304565b34801561036857600080fd5b506103a56040518060400160405280600581526020017f302e382e3100000000000000000000000000000000000000000000000000000081525081565b60405161024a9190614046565b3480156103be57600080fd5b506006546007546103cd919082565b6040805192835260208301919091520161024a565b3480156103ee57600080fd5b506103a5610a93565b34801561040357600080fd5b5061020661041236600461407b565b610aa6565b6102066104253660046140b4565b610c52565b34801561043657600080fd5b50367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c90036020013561029f565b34801561047657600080fd5b5060075461029f565b6102066114ca565b34801561049357600080fd5b5060015461029f565b3480156104a857600080fd5b50367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c90036040013561029f565b3480156104e857600080fd5b507f000000000000000000000000000000000000000000000000000000000000000061029f565b34801561051b57600080fd5b5060405163ffffffff7f000000000000000000000000000000000000000000000000000000000000000016815260200161024a565b34801561055c57600080fd5b50367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c90033561029f565b34801561059957600080fd5b5061029f6105a83660046140e9565b6119f6565b6102066105bb366004613fb9565b611be0565b3480156105cc57600080fd5b506105e06105db36600461411b565b611bec565b6040805163ffffffff909816885273ffffffffffffffffffffffffffffffffffffffff968716602089015295909416948601949094526fffffffffffffffffffffffffffffffff9182166060860152608085015291821660a08401521660c082015260e00161024a565b34801561065657600080fd5b506000546102359067ffffffffffffffff1681565b34801561067757600080fd5b5061029f61068636600461407b565b60026020526000908152604090205481565b3480156106a457600080fd5b507f000000000000000000000000000000000000000000000000000000000000000061029f565b3480156106d757600080fd5b506102066106e636600461417d565b611c83565b3480156106f757600080fd5b507f0000000000000000000000000000000000000000000000000000000000000000610235565b34801561072a57600080fd5b507f000000000000000000000000000000000000000000000000000000000000000061029f565b34801561075d57600080fd5b506040516fffffffffffffffffffffffffffffffff815260200161024a565b34801561078857600080fd5b50610206610797366004614207565b6122b8565b3480156107a857600080fd5b506107b1612715565b60405161024a93929190614233565b3480156107cc57600080fd5b507f000000000000000000000000000000000000000000000000000000000000000061029f565b61020661080136600461411b565b612772565b600080600054700100000000000000000000000000000000900460ff16600281111561083457610834613f49565b1461086b576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055460ff166108a7576040517f9a07664600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff1660016000815481106108d3576108d3614261565b6000918252602090912060059091020154640100000000900473ffffffffffffffffffffffffffffffffffffffff161461090e576001610911565b60025b6000805467ffffffffffffffff421668010000000000000000027fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff82168117835592935083927fffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffff000000000000000000ffffffffffffffff909116177001000000000000000000000000000000008360028111156109c2576109c2613f49565b0217905560028111156109d7576109d7613f49565b6040517f5e186f09b9c93491f14e277eea7faa5de6a2d4bda75a79af7a3684fbfb42da6090600090a27f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663838c2d1e6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610a6857600080fd5b505af1158015610a7c573d6000803e3d6000fd5b5050505090565b610a8f82826000610c52565b5050565b6060610aa160406020612bd3565b905090565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260026020526040812080549082905590819003610b0b576040517f17bfe5f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff3fef3a300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063f3fef3a390604401600060405180830381600087803b158015610b9b57600080fd5b505af1158015610baf573d6000803e3d6000fd5b5050505060008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114610c0d576040519150601f19603f3d011682016040523d82523d6000602084013e610c12565b606091505b5050905080610c4d576040517f83e6cc6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b60008054700100000000000000000000000000000000900460ff166002811115610c7e57610c7e613f49565b14610cb5576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060018481548110610cca57610cca614261565b600091825260208083206040805160e0810182526005909402909101805463ffffffff808216865273ffffffffffffffffffffffffffffffffffffffff6401000000009092048216948601949094526001820154169184019190915260028101546fffffffffffffffffffffffffffffffff90811660608501526003820154608085015260049091015480821660a0850181905270010000000000000000000000000000000090910490911660c0840152919350909190610d8f9083908690612c6a16565b90506000610e2f826fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff169050861580610e715750610e6e7f000000000000000000000000000000000000000000000000000000000000000060026142bf565b81145b8015610e7b575084155b15610eb2576040517fa42637bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000811115610f0c576040517f56f57b2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f377f000000000000000000000000000000000000000000000000000000000000000060016142bf565b8103610f4957610f4986888588612c72565b34610f53836119f6565b1115610f8b576040517fe92c469f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835160009063ffffffff90811614610feb576001856000015163ffffffff1681548110610fba57610fba614261565b906000526020600020906005020160040160109054906101000a90046fffffffffffffffffffffffffffffffff1690505b60c085015160009061100f9067ffffffffffffffff165b67ffffffffffffffff1690565b67ffffffffffffffff1642611039611002856fffffffffffffffffffffffffffffffff1660401c90565b67ffffffffffffffff1661104d91906142bf565b61105791906142d7565b90507f000000000000000000000000000000000000000000000000000000000000000060011c677fffffffffffffff1667ffffffffffffffff821611156110ca576040517f3381d11400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000604082901b421760008a8152608087901b6fffffffffffffffffffffffffffffffff8d1617602052604081209192509060008181526003602052604090205490915060ff1615611148576040517f80497e3b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016003600083815260200190815260200160002060006101000a81548160ff02191690831515021790555060016040518060e001604052808d63ffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff168152602001346fffffffffffffffffffffffffffffffff1681526020018c8152602001886fffffffffffffffffffffffffffffffff168152602001846fffffffffffffffffffffffffffffffff16815250908060018154018082558091505060019003906000526020600020906005020160009091909190915060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160020160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506080820151816003015560a08201518160040160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060c08201518160040160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055505050600460008c8152602001908152602001600020600180805490506113dd91906142d7565b81546001810183556000928352602083200155604080517fd0e30db0000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169263d0e30db09234926004808301939282900301818588803b15801561147557600080fd5b505af1158015611489573d6000803e3d6000fd5b50506040513393508d92508e91507f9b3245740ec3b155098a55be84957a4da13eaf7f14a8bc6f53126c0b9350f2be90600090a45050505050505050505050565b600554610100900460ff161561150c576040517f0dc149f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f7258a80700000000000000000000000000000000000000000000000000000000815263ffffffff7f0000000000000000000000000000000000000000000000000000000000000000166004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690637258a807906024016040805180830381865afa1580156115c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e491906142ee565b909250905081611620576040517f6a6bc3b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518082018252838152602001829052600683905560078290558190367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c90030135116116d2576040517ff40239db000000000000000000000000000000000000000000000000000000008152367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c90033560048201526024015b60405180910390fd5b60663611156116e95763c407e0256000526004601cfd5b6040805160e08101825263ffffffff808252600060208301818152328486019081526fffffffffffffffffffffffffffffffff34818116606088019081527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe369081013560f01c90033560808901908152600160a08a0181815242861660c08c0190815282548084018455928a529a5160059092027fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf681018054995173ffffffffffffffffffffffffffffffffffffffff908116640100000000027fffffffffffffffff000000000000000000000000000000000000000000000000909b1694909c16939093179890981790915594517fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf787018054918a167fffffffffffffffffffffffff000000000000000000000000000000000000000090921691909117905590517fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf8860180549185167fffffffffffffffffffffffffffffffff00000000000000000000000000000000909216919091179055517fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf9850155915195518116700100000000000000000000000000000000029516949094177fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cfa9091015583517fd0e30db000000000000000000000000000000000000000000000000000000000815293517f00000000000000000000000000000000000000000000000000000000000000009092169363d0e30db093926004828101939282900301818588803b15801561197757600080fd5b505af115801561198b573d6000803e3d6000fd5b50506000805467ffffffffffffffff42167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009091161790555050600580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055505050565b600080611a95836fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff1690507f0000000000000000000000000000000000000000000000000000000000000000811115611afb576040517f56f57b2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b642e90edd00062061a80630bebc2006000611b168383614341565b9050670de0b6b3a76400006000611b4d827f0000000000000000000000000000000000000000000000000000000000000000614355565b90506000611b6b611b66670de0b6b3a764000086614355565b612e33565b90506000611b79848461308e565b90506000611b8783836130dd565b90506000611b948261310b565b90506000611bb382611bae670de0b6b3a76400008f614355565b6132f3565b90506000611bc18b836130dd565b9050611bcd818d614355565b9f9e505050505050505050505050505050565b610a8f82826001610c52565b60018181548110611bfc57600080fd5b60009182526020909120600590910201805460018201546002830154600384015460049094015463ffffffff8416955064010000000090930473ffffffffffffffffffffffffffffffffffffffff908116949216926fffffffffffffffffffffffffffffffff91821692918082169170010000000000000000000000000000000090041687565b60008054700100000000000000000000000000000000900460ff166002811115611caf57611caf613f49565b14611ce6576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060018781548110611cfb57611cfb614261565b6000918252602082206005919091020160048101549092506fffffffffffffffffffffffffffffffff16908715821760011b9050611d5a7f000000000000000000000000000000000000000000000000000000000000000060016142bf565b611df6826fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff1614611e37576040517f5f53dd9800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808915611f2657611e8a7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006142d7565b6001901b611ea9846fffffffffffffffffffffffffffffffff1661332d565b67ffffffffffffffff16611ebd9190614392565b15611efa57611ef1611ee260016fffffffffffffffffffffffffffffffff87166143a6565b865463ffffffff1660006133d3565b60030154611f1c565b7f00000000000000000000000000000000000000000000000000000000000000005b9150849050611f50565b60038501549150611f4d611ee26fffffffffffffffffffffffffffffffff861660016143d7565b90505b600882901b60088a8a604051611f6792919061440b565b6040518091039020901b14611fa8576040517f696550ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611fb38c6134b7565b90506000611fc2836003015490565b6040517fe14ced320000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e14ced329061203c908f908f908f908f908a90600401614464565b6020604051808303816000875af115801561205b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061207f919061449e565b60048501549114915060009060029061212a906fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b6121c6896fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b6121d091906144b7565b6121da91906144d8565b67ffffffffffffffff161590508115158103612222576040517ffb4e40dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8754640100000000900473ffffffffffffffffffffffffffffffffffffffff1615612279576040517f9071e6af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505085547fffffffffffffffff0000000000000000000000000000000000000000ffffffff163364010000000002179095555050505050505050505050565b60008054700100000000000000000000000000000000900460ff1660028111156122e4576122e4613f49565b1461231b576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060008061232a866134e6565b93509350935093506000612340858585856138f5565b905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16637dc0d1d06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123d391906144ff565b9050600189036124cb5773ffffffffffffffffffffffffffffffffffffffff81166352f0f3ad8a8461242f367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c90036020013590565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815260048101939093526024830191909152604482015260206064820152608481018a905260a4015b6020604051808303816000875af11580156124a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124c5919061449e565b5061270a565b600289036124f75773ffffffffffffffffffffffffffffffffffffffff81166352f0f3ad8a848961242f565b600389036125235773ffffffffffffffffffffffffffffffffffffffff81166352f0f3ad8a848761242f565b6004890361263f5760006125696fffffffffffffffffffffffffffffffff85167f00000000000000000000000000000000000000000000000000000000000000006139b4565b60075461257691906142bf565b6125819060016142bf565b905073ffffffffffffffffffffffffffffffffffffffff82166352f0f3ad8b8560405160e084901b7fffffffff000000000000000000000000000000000000000000000000000000001681526004810192909252602482015260c084901b604482015260086064820152608481018b905260a4016020604051808303816000875af1158015612614573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612638919061449e565b505061270a565b600589036126d8576040517f52f0f3ad000000000000000000000000000000000000000000000000000000008152600481018a9052602481018390527f000000000000000000000000000000000000000000000000000000000000000060c01b6044820152600860648201526084810188905273ffffffffffffffffffffffffffffffffffffffff8216906352f0f3ad9060a401612482565b6040517fff137e6500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050565b7f0000000000000000000000000000000000000000000000000000000000000000367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c900335606061276b610a93565b9050909192565b60008054700100000000000000000000000000000000900460ff16600281111561279e5761279e613f49565b146127d5576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600182815481106127ea576127ea614261565b60009182526020822060059190910201600481015490925061282c90700100000000000000000000000000000000900460401c67ffffffffffffffff16611002565b600483015490915060009061285e90700100000000000000000000000000000000900467ffffffffffffffff16611002565b61286890426144b7565b9050677fffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000060011c166128a2828461451c565b67ffffffffffffffff16116128e3576040517ff2440b5300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000848152600460205260409020805485158015612903575060055460ff165b1561293a576040517ff1a9458100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8015801561294757508515155b156129ac578454640100000000900473ffffffffffffffffffffffffffffffffffffffff166000811561297a5781612996565b600187015473ffffffffffffffffffffffffffffffffffffffff165b90506129a28188613a69565b5050505050505050565b60006fffffffffffffffffffffffffffffffff815b83811015612af25760008582815481106129dd576129dd614261565b6000918252602080832090910154808352600490915260409091205490915015612a33576040517f9a07664600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060018281548110612a4857612a48614261565b600091825260209091206005909102018054909150640100000000900473ffffffffffffffffffffffffffffffffffffffff16158015612aa1575060048101546fffffffffffffffffffffffffffffffff908116908516115b15612adf576001810154600482015473ffffffffffffffffffffffffffffffffffffffff90911695506fffffffffffffffffffffffffffffffff1693505b505080612aeb9061453f565b90506129c1565b50612b3a73ffffffffffffffffffffffffffffffffffffffff831615612b185782612b34565b600188015473ffffffffffffffffffffffffffffffffffffffff165b88613a69565b86547fffffffffffffffff0000000000000000000000000000000000000000ffffffff1664010000000073ffffffffffffffffffffffffffffffffffffffff8416021787556000888152600460205260408120612b9691613f0f565b876000036129a257600580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555050505050505050565b60606000612c0a84367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c90036142bf565b90508267ffffffffffffffff1667ffffffffffffffff811115612c2f57612c2f614577565b6040519080825280601f01601f191660200182016040528015612c59576020820181803683370190505b509150828160208401375092915050565b151760011b90565b6000612c916fffffffffffffffffffffffffffffffff841660016143d7565b90506000612ca1828660016133d3565b9050600086901a8380612d945750612cda60027f0000000000000000000000000000000000000000000000000000000000000000614392565b6004830154600290612d7e906fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b612d8891906144d8565b67ffffffffffffffff16145b15612dec5760ff811660011480612dae575060ff81166002145b612de7576040517ff40239db000000000000000000000000000000000000000000000000000000008152600481018890526024016116c9565b612e2a565b60ff811615612e2a576040517ff40239db000000000000000000000000000000000000000000000000000000008152600481018890526024016116c9565b50505050505050565b6fffffffffffffffffffffffffffffffff811160071b81811c67ffffffffffffffff1060061b1781811c63ffffffff1060051b1781811c61ffff1060041b1781811c60ff1060031b1760008213612e9257631615e6386000526004601cfd5b7ff8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff6f8421084210842108cc6318c6db6d54be83831c1c601f161a1890811b609f90811c6c465772b2bbbb5f824b15207a3081018102606090811d6d0388eaa27412d5aca026815d636e018202811d6d0df99ac502031bf953eff472fdcc018202811d6d13cdffb29d51d99322bdff5f2211018202811d6d0a0f742023def783a307a986912e018202811d6d01920d8043ca89b5239253284e42018202811d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7883018302821d6d0139601a2efabe717e604cbb4894018302821d6d02247f7a7b6594320649aa03aba1018302821d7fffffffffffffffffffffffffffffffffffffff73c0c716a594e00d54e3c4cbc9018302821d7ffffffffffffffffffffffffffffffffffffffdc7b88c420e53a9890533129f6f01830290911d7fffffffffffffffffffffffffffffffffffffff465fda27eb4d63ded474e5f832019091027ffffffffffffffff5f6af8f7b3396644f18e157960000000000000000000000000105711340daa0d5f769dba1915cef59f0815a5506029190037d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d90565b60007812725dd1d243aba0e75fe645cc4873f9e65afe688c928e1f218311670de0b6b3a7640000021582026130cb57637c5f487d6000526004601cfd5b50670de0b6b3a7640000919091020490565b6000816000190483118202156130fb5763bac65e5b6000526004601cfd5b50670de0b6b3a764000091020490565b60007ffffffffffffffffffffffffffffffffffffffffffffffffdc0d0570925a462d7821361313957919050565b680755bf798b4a1bf1e582126131575763a37bfec96000526004601cfd5b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056b80000000000000000000000001901d6bb17217f7d1cf79abc9e3b39881029093037fffffffffffffffffffffffffffffffffffffffdbf3ccf1604d263450f02a550481018102606090811d6d0277594991cfc85f6e2461837cd9018202811d7fffffffffffffffffffffffffffffffffffffe5adedaa1cb095af9e4da10e363c018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d7ffffffffffffffffffffffffffffffffffffd38dc772608b0ae56cce01296c0eb018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084017ffffffffffffffffffffffffffffffffffffffe2c69812cf03b0763fd454a8f7e010290911d6e0587f503bb6ea29d25fcb7401964500190910279d835ebba824c98fb31b83b2ca45c000000000000000000000000010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b6000613324670de0b6b3a76400008361330b86612e33565b61331591906145a6565b61331f9190614662565b61310b565b90505b92915050565b6000806133ba837e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b600167ffffffffffffffff919091161b90920392915050565b6000808261341c576134176fffffffffffffffffffffffffffffffff86167f0000000000000000000000000000000000000000000000000000000000000000613bf5565b613437565b613437856fffffffffffffffffffffffffffffffff16613db3565b90506001848154811061344c5761344c614261565b906000526020600020906005020191505b60048201546fffffffffffffffffffffffffffffffff8281169116146134af57815460018054909163ffffffff1690811061349a5761349a614261565b9060005260206000209060050201915061345d565b509392505050565b60008060008060006134c8866134e6565b93509350935093506134dc848484846138f5565b9695505050505050565b600080600080600085905060006001828154811061350657613506614261565b600091825260209091206004600590920201908101549091507f0000000000000000000000000000000000000000000000000000000000000000906135dd906fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff161161361e576040517fb34b5c2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000815b60048301547f0000000000000000000000000000000000000000000000000000000000000000906136e5906fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff16925082111561376157825463ffffffff1661372b7f000000000000000000000000000000000000000000000000000000000000000060016142bf565b8303613735578391505b6001818154811061374857613748614261565b9060005260206000209060050201935080945050613622565b600481810154908401546fffffffffffffffffffffffffffffffff91821691166000816fffffffffffffffffffffffffffffffff166137ca6137b5856fffffffffffffffffffffffffffffffff1660011c90565b6fffffffffffffffffffffffffffffffff1690565b6fffffffffffffffffffffffffffffffff161490508015613891576000613802836fffffffffffffffffffffffffffffffff1661332d565b67ffffffffffffffff16111561386557600061383c61383460016fffffffffffffffffffffffffffffffff86166143a6565b8960016133d3565b6003810154600490910154909c506fffffffffffffffffffffffffffffffff169a5061386b9050565b6006549a505b600386015460048701549099506fffffffffffffffffffffffffffffffff1697506138e7565b60006138b36138346fffffffffffffffffffffffffffffffff851660016143d7565b6003808901546004808b015492840154930154909e506fffffffffffffffffffffffffffffffff9182169d50919b50169850505b505050505050509193509193565b60006fffffffffffffffffffffffffffffffff8416810361395b57828260405160200161393e9291909182526fffffffffffffffffffffffffffffffff16602082015260400190565b6040516020818303038152906040528051906020012090506139ac565b60408051602081018790526fffffffffffffffffffffffffffffffff8087169282019290925260608101859052908316608082015260a0016040516020818303038152906040528051906020012090505b949350505050565b600080613a41847e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff1690508083036001841b600180831b0386831b17039250505092915050565b60028101546fffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffff000000000000000000000000000000018101613ad9576040517ff1a9458100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280830180547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff17905573ffffffffffffffffffffffffffffffffffffffff84166000908152602091909152604081208054839290613b4c9084906142bf565b90915550506040517f7eee288d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018390527f00000000000000000000000000000000000000000000000000000000000000001690637eee288d90604401600060405180830381600087803b158015613be157600080fd5b505af1158015612e2a573d6000803e3d6000fd5b600081613c94846fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff1611613cd5576040517fb34b5c2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613cde83613db3565b905081613d7d826fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff161161332757613324613d9a8360016142bf565b6fffffffffffffffffffffffffffffffff831690613e5f565b60008119600183011681613e47827e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff169390931c8015179392505050565b600080613eec847e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff169050808303600180821b0385821b179250505092915050565b5080546000825590600052602060002090810190613f2d9190613f30565b50565b5b80821115613f455760008155600101613f31565b5090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160038310613fb3577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b60008060408385031215613fcc57600080fd5b50508035926020909101359150565b6000815180845260005b8181101561400157602081850181015186830182015201613fe5565b81811115614013576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006133246020830184613fdb565b73ffffffffffffffffffffffffffffffffffffffff81168114613f2d57600080fd5b60006020828403121561408d57600080fd5b813561409881614059565b9392505050565b803580151581146140af57600080fd5b919050565b6000806000606084860312156140c957600080fd5b83359250602084013591506140e06040850161409f565b90509250925092565b6000602082840312156140fb57600080fd5b81356fffffffffffffffffffffffffffffffff8116811461409857600080fd5b60006020828403121561412d57600080fd5b5035919050565b60008083601f84011261414657600080fd5b50813567ffffffffffffffff81111561415e57600080fd5b60208301915083602082850101111561417657600080fd5b9250929050565b6000806000806000806080878903121561419657600080fd5b863595506141a66020880161409f565b9450604087013567ffffffffffffffff808211156141c357600080fd5b6141cf8a838b01614134565b909650945060608901359150808211156141e857600080fd5b506141f589828a01614134565b979a9699509497509295939492505050565b60008060006060848603121561421c57600080fd5b505081359360208301359350604090920135919050565b63ffffffff841681528260208201526060604082015260006142586060830184613fdb565b95945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082198211156142d2576142d2614290565b500190565b6000828210156142e9576142e9614290565b500390565b6000806040838503121561430157600080fd5b505080516020909101519092909150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261435057614350614312565b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561438d5761438d614290565b500290565b6000826143a1576143a1614312565b500690565b60006fffffffffffffffffffffffffffffffff838116908316818110156143cf576143cf614290565b039392505050565b60006fffffffffffffffffffffffffffffffff80831681851680830382111561440257614402614290565b01949350505050565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60608152600061447860608301878961441b565b828103602084015261448b81868861441b565b9150508260408301529695505050505050565b6000602082840312156144b057600080fd5b5051919050565b600067ffffffffffffffff838116908316818110156143cf576143cf614290565b600067ffffffffffffffff808416806144f3576144f3614312565b92169190910692915050565b60006020828403121561451157600080fd5b815161409881614059565b600067ffffffffffffffff80831681851680830382111561440257614402614290565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361457057614570614290565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000841360008413858304851182821616156145e7576145e7614290565b7f8000000000000000000000000000000000000000000000000000000000000000600087128682058812818416161561462257614622614290565b6000871292508782058712848416161561463e5761463e614290565b8785058712818416161561465457614654614290565b505050929093029392505050565b60008261467157614671614312565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f8000000000000000000000000000000000000000000000000000000000000000831416156146c5576146c5614290565b50059056fea164736f6c634300080f000a0000000000000000000000000000000000000000000000000000000000000000031e3b504740d0b1264e8cf72b6dde0d497184cfb3f98e451c6be8b33bd3f8080000000000000000000000000000000000000000000000000000000000000049000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000093a80000000000000000000000000c29ae51b025f3f58243cb3331243460a13d8cf330000000000000000000000009bd56b189234fe25cf3547c4343e50c3259e383a0000000000000000000000001874a5cca34ebce29adf1ebdd7fd2725fe1848380000000000000000000000000000000000000000000000000000000000aa37dc
Deployed Bytecode
0x6080604052600436106101ff5760003560e01c80638d450a951161010e578063d6ae3cd5116100a7578063f3f7214e11610079578063fa24f74311610061578063fa24f7431461079c578063fa315aa9146107c0578063fdffbb28146107f357005b8063f3f7214e14610751578063f8f43ff61461077c57005b8063d6ae3cd514610698578063d8cc1a3c146106cb578063e1f0c376146106eb578063ec5e63081461071e57005b8063c55cd0c7116100e0578063c55cd0c7146105ad578063c6f0308c146105c0578063cf09e0d01461064a578063d5d44d801461066b57005b80638d450a95146104dc578063bbdc02db1461050f578063bcef3b5514610550578063c395e1ca1461058d57005b806357da950e116101985780636361506d1161016a5780638129fc1c116101525780638129fc1c1461047f5780638980e0cc146104875780638b85902b1461049c57005b80636361506d1461042a57806370872aa51461046a57005b806357da950e146103b2578063609d3334146103e257806360e27464146103f7578063632247ea1461041757005b806335fef567116101d157806335fef567146102c25780633a768463146102d55780633fc8cef31461032957806354fd4d501461035c57005b806319effeb414610208578063200d2ed21461025357806325fc2ace1461028e5780632810e1d6146102ad57005b3661020657005b005b34801561021457600080fd5b506000546102359068010000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020015b60405180910390f35b34801561025f57600080fd5b5060005461028190700100000000000000000000000000000000900460ff1681565b60405161024a9190613f78565b34801561029a57600080fd5b506006545b60405190815260200161024a565b3480156102b957600080fd5b50610281610806565b6102066102d0366004613fb9565b610a83565b3480156102e157600080fd5b507f000000000000000000000000c29ae51b025f3f58243cb3331243460a13d8cf335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161024a565b34801561033557600080fd5b507f0000000000000000000000009bd56b189234fe25cf3547c4343e50c3259e383a610304565b34801561036857600080fd5b506103a56040518060400160405280600581526020017f302e382e3100000000000000000000000000000000000000000000000000000081525081565b60405161024a9190614046565b3480156103be57600080fd5b506006546007546103cd919082565b6040805192835260208301919091520161024a565b3480156103ee57600080fd5b506103a5610a93565b34801561040357600080fd5b5061020661041236600461407b565b610aa6565b6102066104253660046140b4565b610c52565b34801561043657600080fd5b50367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c90036020013561029f565b34801561047657600080fd5b5060075461029f565b6102066114ca565b34801561049357600080fd5b5060015461029f565b3480156104a857600080fd5b50367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c90036040013561029f565b3480156104e857600080fd5b507f031e3b504740d0b1264e8cf72b6dde0d497184cfb3f98e451c6be8b33bd3f80861029f565b34801561051b57600080fd5b5060405163ffffffff7f000000000000000000000000000000000000000000000000000000000000000016815260200161024a565b34801561055c57600080fd5b50367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c90033561029f565b34801561059957600080fd5b5061029f6105a83660046140e9565b6119f6565b6102066105bb366004613fb9565b611be0565b3480156105cc57600080fd5b506105e06105db36600461411b565b611bec565b6040805163ffffffff909816885273ffffffffffffffffffffffffffffffffffffffff968716602089015295909416948601949094526fffffffffffffffffffffffffffffffff9182166060860152608085015291821660a08401521660c082015260e00161024a565b34801561065657600080fd5b506000546102359067ffffffffffffffff1681565b34801561067757600080fd5b5061029f61068636600461407b565b60026020526000908152604090205481565b3480156106a457600080fd5b507f0000000000000000000000000000000000000000000000000000000000aa37dc61029f565b3480156106d757600080fd5b506102066106e636600461417d565b611c83565b3480156106f757600080fd5b507f0000000000000000000000000000000000000000000000000000000000093a80610235565b34801561072a57600080fd5b507f000000000000000000000000000000000000000000000000000000000000001e61029f565b34801561075d57600080fd5b506040516fffffffffffffffffffffffffffffffff815260200161024a565b34801561078857600080fd5b50610206610797366004614207565b6122b8565b3480156107a857600080fd5b506107b1612715565b60405161024a93929190614233565b3480156107cc57600080fd5b507f000000000000000000000000000000000000000000000000000000000000004961029f565b61020661080136600461411b565b612772565b600080600054700100000000000000000000000000000000900460ff16600281111561083457610834613f49565b1461086b576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055460ff166108a7576040517f9a07664600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff1660016000815481106108d3576108d3614261565b6000918252602090912060059091020154640100000000900473ffffffffffffffffffffffffffffffffffffffff161461090e576001610911565b60025b6000805467ffffffffffffffff421668010000000000000000027fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff82168117835592935083927fffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffff000000000000000000ffffffffffffffff909116177001000000000000000000000000000000008360028111156109c2576109c2613f49565b0217905560028111156109d7576109d7613f49565b6040517f5e186f09b9c93491f14e277eea7faa5de6a2d4bda75a79af7a3684fbfb42da6090600090a27f0000000000000000000000001874a5cca34ebce29adf1ebdd7fd2725fe18483873ffffffffffffffffffffffffffffffffffffffff1663838c2d1e6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610a6857600080fd5b505af1158015610a7c573d6000803e3d6000fd5b5050505090565b610a8f82826000610c52565b5050565b6060610aa160406020612bd3565b905090565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260026020526040812080549082905590819003610b0b576040517f17bfe5f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff3fef3a300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390527f0000000000000000000000009bd56b189234fe25cf3547c4343e50c3259e383a169063f3fef3a390604401600060405180830381600087803b158015610b9b57600080fd5b505af1158015610baf573d6000803e3d6000fd5b5050505060008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114610c0d576040519150601f19603f3d011682016040523d82523d6000602084013e610c12565b606091505b5050905080610c4d576040517f83e6cc6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b60008054700100000000000000000000000000000000900460ff166002811115610c7e57610c7e613f49565b14610cb5576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060018481548110610cca57610cca614261565b600091825260208083206040805160e0810182526005909402909101805463ffffffff808216865273ffffffffffffffffffffffffffffffffffffffff6401000000009092048216948601949094526001820154169184019190915260028101546fffffffffffffffffffffffffffffffff90811660608501526003820154608085015260049091015480821660a0850181905270010000000000000000000000000000000090910490911660c0840152919350909190610d8f9083908690612c6a16565b90506000610e2f826fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff169050861580610e715750610e6e7f000000000000000000000000000000000000000000000000000000000000001e60026142bf565b81145b8015610e7b575084155b15610eb2576040517fa42637bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000049811115610f0c576040517f56f57b2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f377f000000000000000000000000000000000000000000000000000000000000001e60016142bf565b8103610f4957610f4986888588612c72565b34610f53836119f6565b1115610f8b576040517fe92c469f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835160009063ffffffff90811614610feb576001856000015163ffffffff1681548110610fba57610fba614261565b906000526020600020906005020160040160109054906101000a90046fffffffffffffffffffffffffffffffff1690505b60c085015160009061100f9067ffffffffffffffff165b67ffffffffffffffff1690565b67ffffffffffffffff1642611039611002856fffffffffffffffffffffffffffffffff1660401c90565b67ffffffffffffffff1661104d91906142bf565b61105791906142d7565b90507f0000000000000000000000000000000000000000000000000000000000093a8060011c677fffffffffffffff1667ffffffffffffffff821611156110ca576040517f3381d11400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000604082901b421760008a8152608087901b6fffffffffffffffffffffffffffffffff8d1617602052604081209192509060008181526003602052604090205490915060ff1615611148576040517f80497e3b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016003600083815260200190815260200160002060006101000a81548160ff02191690831515021790555060016040518060e001604052808d63ffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff168152602001346fffffffffffffffffffffffffffffffff1681526020018c8152602001886fffffffffffffffffffffffffffffffff168152602001846fffffffffffffffffffffffffffffffff16815250908060018154018082558091505060019003906000526020600020906005020160009091909190915060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160020160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506080820151816003015560a08201518160040160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060c08201518160040160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055505050600460008c8152602001908152602001600020600180805490506113dd91906142d7565b81546001810183556000928352602083200155604080517fd0e30db0000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000009bd56b189234fe25cf3547c4343e50c3259e383a169263d0e30db09234926004808301939282900301818588803b15801561147557600080fd5b505af1158015611489573d6000803e3d6000fd5b50506040513393508d92508e91507f9b3245740ec3b155098a55be84957a4da13eaf7f14a8bc6f53126c0b9350f2be90600090a45050505050505050505050565b600554610100900460ff161561150c576040517f0dc149f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f7258a80700000000000000000000000000000000000000000000000000000000815263ffffffff7f0000000000000000000000000000000000000000000000000000000000000000166004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000001874a5cca34ebce29adf1ebdd7fd2725fe1848381690637258a807906024016040805180830381865afa1580156115c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e491906142ee565b909250905081611620576040517f6a6bc3b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518082018252838152602001829052600683905560078290558190367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c90030135116116d2576040517ff40239db000000000000000000000000000000000000000000000000000000008152367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c90033560048201526024015b60405180910390fd5b60663611156116e95763c407e0256000526004601cfd5b6040805160e08101825263ffffffff808252600060208301818152328486019081526fffffffffffffffffffffffffffffffff34818116606088019081527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe369081013560f01c90033560808901908152600160a08a0181815242861660c08c0190815282548084018455928a529a5160059092027fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf681018054995173ffffffffffffffffffffffffffffffffffffffff908116640100000000027fffffffffffffffff000000000000000000000000000000000000000000000000909b1694909c16939093179890981790915594517fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf787018054918a167fffffffffffffffffffffffff000000000000000000000000000000000000000090921691909117905590517fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf8860180549185167fffffffffffffffffffffffffffffffff00000000000000000000000000000000909216919091179055517fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf9850155915195518116700100000000000000000000000000000000029516949094177fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cfa9091015583517fd0e30db000000000000000000000000000000000000000000000000000000000815293517f0000000000000000000000009bd56b189234fe25cf3547c4343e50c3259e383a9092169363d0e30db093926004828101939282900301818588803b15801561197757600080fd5b505af115801561198b573d6000803e3d6000fd5b50506000805467ffffffffffffffff42167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009091161790555050600580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055505050565b600080611a95836fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff1690507f0000000000000000000000000000000000000000000000000000000000000049811115611afb576040517f56f57b2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b642e90edd00062061a80630bebc2006000611b168383614341565b9050670de0b6b3a76400006000611b4d827f0000000000000000000000000000000000000000000000000000000000000049614355565b90506000611b6b611b66670de0b6b3a764000086614355565b612e33565b90506000611b79848461308e565b90506000611b8783836130dd565b90506000611b948261310b565b90506000611bb382611bae670de0b6b3a76400008f614355565b6132f3565b90506000611bc18b836130dd565b9050611bcd818d614355565b9f9e505050505050505050505050505050565b610a8f82826001610c52565b60018181548110611bfc57600080fd5b60009182526020909120600590910201805460018201546002830154600384015460049094015463ffffffff8416955064010000000090930473ffffffffffffffffffffffffffffffffffffffff908116949216926fffffffffffffffffffffffffffffffff91821692918082169170010000000000000000000000000000000090041687565b60008054700100000000000000000000000000000000900460ff166002811115611caf57611caf613f49565b14611ce6576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060018781548110611cfb57611cfb614261565b6000918252602082206005919091020160048101549092506fffffffffffffffffffffffffffffffff16908715821760011b9050611d5a7f000000000000000000000000000000000000000000000000000000000000004960016142bf565b611df6826fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff1614611e37576040517f5f53dd9800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808915611f2657611e8a7f000000000000000000000000000000000000000000000000000000000000001e7f00000000000000000000000000000000000000000000000000000000000000496142d7565b6001901b611ea9846fffffffffffffffffffffffffffffffff1661332d565b67ffffffffffffffff16611ebd9190614392565b15611efa57611ef1611ee260016fffffffffffffffffffffffffffffffff87166143a6565b865463ffffffff1660006133d3565b60030154611f1c565b7f031e3b504740d0b1264e8cf72b6dde0d497184cfb3f98e451c6be8b33bd3f8085b9150849050611f50565b60038501549150611f4d611ee26fffffffffffffffffffffffffffffffff861660016143d7565b90505b600882901b60088a8a604051611f6792919061440b565b6040518091039020901b14611fa8576040517f696550ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611fb38c6134b7565b90506000611fc2836003015490565b6040517fe14ced320000000000000000000000000000000000000000000000000000000081527f000000000000000000000000c29ae51b025f3f58243cb3331243460a13d8cf3373ffffffffffffffffffffffffffffffffffffffff169063e14ced329061203c908f908f908f908f908a90600401614464565b6020604051808303816000875af115801561205b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061207f919061449e565b60048501549114915060009060029061212a906fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b6121c6896fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b6121d091906144b7565b6121da91906144d8565b67ffffffffffffffff161590508115158103612222576040517ffb4e40dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8754640100000000900473ffffffffffffffffffffffffffffffffffffffff1615612279576040517f9071e6af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505085547fffffffffffffffff0000000000000000000000000000000000000000ffffffff163364010000000002179095555050505050505050505050565b60008054700100000000000000000000000000000000900460ff1660028111156122e4576122e4613f49565b1461231b576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060008061232a866134e6565b93509350935093506000612340858585856138f5565b905060007f000000000000000000000000c29ae51b025f3f58243cb3331243460a13d8cf3373ffffffffffffffffffffffffffffffffffffffff16637dc0d1d06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123d391906144ff565b9050600189036124cb5773ffffffffffffffffffffffffffffffffffffffff81166352f0f3ad8a8461242f367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c90036020013590565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815260048101939093526024830191909152604482015260206064820152608481018a905260a4015b6020604051808303816000875af11580156124a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124c5919061449e565b5061270a565b600289036124f75773ffffffffffffffffffffffffffffffffffffffff81166352f0f3ad8a848961242f565b600389036125235773ffffffffffffffffffffffffffffffffffffffff81166352f0f3ad8a848761242f565b6004890361263f5760006125696fffffffffffffffffffffffffffffffff85167f000000000000000000000000000000000000000000000000000000000000001e6139b4565b60075461257691906142bf565b6125819060016142bf565b905073ffffffffffffffffffffffffffffffffffffffff82166352f0f3ad8b8560405160e084901b7fffffffff000000000000000000000000000000000000000000000000000000001681526004810192909252602482015260c084901b604482015260086064820152608481018b905260a4016020604051808303816000875af1158015612614573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612638919061449e565b505061270a565b600589036126d8576040517f52f0f3ad000000000000000000000000000000000000000000000000000000008152600481018a9052602481018390527f0000000000000000000000000000000000000000000000000000000000aa37dc60c01b6044820152600860648201526084810188905273ffffffffffffffffffffffffffffffffffffffff8216906352f0f3ad9060a401612482565b6040517fff137e6500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050565b7f0000000000000000000000000000000000000000000000000000000000000000367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c900335606061276b610a93565b9050909192565b60008054700100000000000000000000000000000000900460ff16600281111561279e5761279e613f49565b146127d5576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600182815481106127ea576127ea614261565b60009182526020822060059190910201600481015490925061282c90700100000000000000000000000000000000900460401c67ffffffffffffffff16611002565b600483015490915060009061285e90700100000000000000000000000000000000900467ffffffffffffffff16611002565b61286890426144b7565b9050677fffffffffffffff7f0000000000000000000000000000000000000000000000000000000000093a8060011c166128a2828461451c565b67ffffffffffffffff16116128e3576040517ff2440b5300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000848152600460205260409020805485158015612903575060055460ff165b1561293a576040517ff1a9458100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8015801561294757508515155b156129ac578454640100000000900473ffffffffffffffffffffffffffffffffffffffff166000811561297a5781612996565b600187015473ffffffffffffffffffffffffffffffffffffffff165b90506129a28188613a69565b5050505050505050565b60006fffffffffffffffffffffffffffffffff815b83811015612af25760008582815481106129dd576129dd614261565b6000918252602080832090910154808352600490915260409091205490915015612a33576040517f9a07664600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060018281548110612a4857612a48614261565b600091825260209091206005909102018054909150640100000000900473ffffffffffffffffffffffffffffffffffffffff16158015612aa1575060048101546fffffffffffffffffffffffffffffffff908116908516115b15612adf576001810154600482015473ffffffffffffffffffffffffffffffffffffffff90911695506fffffffffffffffffffffffffffffffff1693505b505080612aeb9061453f565b90506129c1565b50612b3a73ffffffffffffffffffffffffffffffffffffffff831615612b185782612b34565b600188015473ffffffffffffffffffffffffffffffffffffffff165b88613a69565b86547fffffffffffffffff0000000000000000000000000000000000000000ffffffff1664010000000073ffffffffffffffffffffffffffffffffffffffff8416021787556000888152600460205260408120612b9691613f0f565b876000036129a257600580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555050505050505050565b60606000612c0a84367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c90036142bf565b90508267ffffffffffffffff1667ffffffffffffffff811115612c2f57612c2f614577565b6040519080825280601f01601f191660200182016040528015612c59576020820181803683370190505b509150828160208401375092915050565b151760011b90565b6000612c916fffffffffffffffffffffffffffffffff841660016143d7565b90506000612ca1828660016133d3565b9050600086901a8380612d945750612cda60027f000000000000000000000000000000000000000000000000000000000000001e614392565b6004830154600290612d7e906fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b612d8891906144d8565b67ffffffffffffffff16145b15612dec5760ff811660011480612dae575060ff81166002145b612de7576040517ff40239db000000000000000000000000000000000000000000000000000000008152600481018890526024016116c9565b612e2a565b60ff811615612e2a576040517ff40239db000000000000000000000000000000000000000000000000000000008152600481018890526024016116c9565b50505050505050565b6fffffffffffffffffffffffffffffffff811160071b81811c67ffffffffffffffff1060061b1781811c63ffffffff1060051b1781811c61ffff1060041b1781811c60ff1060031b1760008213612e9257631615e6386000526004601cfd5b7ff8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff6f8421084210842108cc6318c6db6d54be83831c1c601f161a1890811b609f90811c6c465772b2bbbb5f824b15207a3081018102606090811d6d0388eaa27412d5aca026815d636e018202811d6d0df99ac502031bf953eff472fdcc018202811d6d13cdffb29d51d99322bdff5f2211018202811d6d0a0f742023def783a307a986912e018202811d6d01920d8043ca89b5239253284e42018202811d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7883018302821d6d0139601a2efabe717e604cbb4894018302821d6d02247f7a7b6594320649aa03aba1018302821d7fffffffffffffffffffffffffffffffffffffff73c0c716a594e00d54e3c4cbc9018302821d7ffffffffffffffffffffffffffffffffffffffdc7b88c420e53a9890533129f6f01830290911d7fffffffffffffffffffffffffffffffffffffff465fda27eb4d63ded474e5f832019091027ffffffffffffffff5f6af8f7b3396644f18e157960000000000000000000000000105711340daa0d5f769dba1915cef59f0815a5506029190037d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d90565b60007812725dd1d243aba0e75fe645cc4873f9e65afe688c928e1f218311670de0b6b3a7640000021582026130cb57637c5f487d6000526004601cfd5b50670de0b6b3a7640000919091020490565b6000816000190483118202156130fb5763bac65e5b6000526004601cfd5b50670de0b6b3a764000091020490565b60007ffffffffffffffffffffffffffffffffffffffffffffffffdc0d0570925a462d7821361313957919050565b680755bf798b4a1bf1e582126131575763a37bfec96000526004601cfd5b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056b80000000000000000000000001901d6bb17217f7d1cf79abc9e3b39881029093037fffffffffffffffffffffffffffffffffffffffdbf3ccf1604d263450f02a550481018102606090811d6d0277594991cfc85f6e2461837cd9018202811d7fffffffffffffffffffffffffffffffffffffe5adedaa1cb095af9e4da10e363c018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d7ffffffffffffffffffffffffffffffffffffd38dc772608b0ae56cce01296c0eb018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084017ffffffffffffffffffffffffffffffffffffffe2c69812cf03b0763fd454a8f7e010290911d6e0587f503bb6ea29d25fcb7401964500190910279d835ebba824c98fb31b83b2ca45c000000000000000000000000010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b6000613324670de0b6b3a76400008361330b86612e33565b61331591906145a6565b61331f9190614662565b61310b565b90505b92915050565b6000806133ba837e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b600167ffffffffffffffff919091161b90920392915050565b6000808261341c576134176fffffffffffffffffffffffffffffffff86167f000000000000000000000000000000000000000000000000000000000000001e613bf5565b613437565b613437856fffffffffffffffffffffffffffffffff16613db3565b90506001848154811061344c5761344c614261565b906000526020600020906005020191505b60048201546fffffffffffffffffffffffffffffffff8281169116146134af57815460018054909163ffffffff1690811061349a5761349a614261565b9060005260206000209060050201915061345d565b509392505050565b60008060008060006134c8866134e6565b93509350935093506134dc848484846138f5565b9695505050505050565b600080600080600085905060006001828154811061350657613506614261565b600091825260209091206004600590920201908101549091507f000000000000000000000000000000000000000000000000000000000000001e906135dd906fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff161161361e576040517fb34b5c2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000815b60048301547f000000000000000000000000000000000000000000000000000000000000001e906136e5906fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff16925082111561376157825463ffffffff1661372b7f000000000000000000000000000000000000000000000000000000000000001e60016142bf565b8303613735578391505b6001818154811061374857613748614261565b9060005260206000209060050201935080945050613622565b600481810154908401546fffffffffffffffffffffffffffffffff91821691166000816fffffffffffffffffffffffffffffffff166137ca6137b5856fffffffffffffffffffffffffffffffff1660011c90565b6fffffffffffffffffffffffffffffffff1690565b6fffffffffffffffffffffffffffffffff161490508015613891576000613802836fffffffffffffffffffffffffffffffff1661332d565b67ffffffffffffffff16111561386557600061383c61383460016fffffffffffffffffffffffffffffffff86166143a6565b8960016133d3565b6003810154600490910154909c506fffffffffffffffffffffffffffffffff169a5061386b9050565b6006549a505b600386015460048701549099506fffffffffffffffffffffffffffffffff1697506138e7565b60006138b36138346fffffffffffffffffffffffffffffffff851660016143d7565b6003808901546004808b015492840154930154909e506fffffffffffffffffffffffffffffffff9182169d50919b50169850505b505050505050509193509193565b60006fffffffffffffffffffffffffffffffff8416810361395b57828260405160200161393e9291909182526fffffffffffffffffffffffffffffffff16602082015260400190565b6040516020818303038152906040528051906020012090506139ac565b60408051602081018790526fffffffffffffffffffffffffffffffff8087169282019290925260608101859052908316608082015260a0016040516020818303038152906040528051906020012090505b949350505050565b600080613a41847e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff1690508083036001841b600180831b0386831b17039250505092915050565b60028101546fffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffff000000000000000000000000000000018101613ad9576040517ff1a9458100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280830180547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff17905573ffffffffffffffffffffffffffffffffffffffff84166000908152602091909152604081208054839290613b4c9084906142bf565b90915550506040517f7eee288d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018390527f0000000000000000000000009bd56b189234fe25cf3547c4343e50c3259e383a1690637eee288d90604401600060405180830381600087803b158015613be157600080fd5b505af1158015612e2a573d6000803e3d6000fd5b600081613c94846fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff1611613cd5576040517fb34b5c2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613cde83613db3565b905081613d7d826fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff161161332757613324613d9a8360016142bf565b6fffffffffffffffffffffffffffffffff831690613e5f565b60008119600183011681613e47827e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff169390931c8015179392505050565b600080613eec847e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff169050808303600180821b0385821b179250505092915050565b5080546000825590600052602060002090810190613f2d9190613f30565b50565b5b80821115613f455760008155600101613f31565b5090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160038310613fb3577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b60008060408385031215613fcc57600080fd5b50508035926020909101359150565b6000815180845260005b8181101561400157602081850181015186830182015201613fe5565b81811115614013576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006133246020830184613fdb565b73ffffffffffffffffffffffffffffffffffffffff81168114613f2d57600080fd5b60006020828403121561408d57600080fd5b813561409881614059565b9392505050565b803580151581146140af57600080fd5b919050565b6000806000606084860312156140c957600080fd5b83359250602084013591506140e06040850161409f565b90509250925092565b6000602082840312156140fb57600080fd5b81356fffffffffffffffffffffffffffffffff8116811461409857600080fd5b60006020828403121561412d57600080fd5b5035919050565b60008083601f84011261414657600080fd5b50813567ffffffffffffffff81111561415e57600080fd5b60208301915083602082850101111561417657600080fd5b9250929050565b6000806000806000806080878903121561419657600080fd5b863595506141a66020880161409f565b9450604087013567ffffffffffffffff808211156141c357600080fd5b6141cf8a838b01614134565b909650945060608901359150808211156141e857600080fd5b506141f589828a01614134565b979a9699509497509295939492505050565b60008060006060848603121561421c57600080fd5b505081359360208301359350604090920135919050565b63ffffffff841681528260208201526060604082015260006142586060830184613fdb565b95945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082198211156142d2576142d2614290565b500190565b6000828210156142e9576142e9614290565b500390565b6000806040838503121561430157600080fd5b505080516020909101519092909150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261435057614350614312565b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561438d5761438d614290565b500290565b6000826143a1576143a1614312565b500690565b60006fffffffffffffffffffffffffffffffff838116908316818110156143cf576143cf614290565b039392505050565b60006fffffffffffffffffffffffffffffffff80831681851680830382111561440257614402614290565b01949350505050565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60608152600061447860608301878961441b565b828103602084015261448b81868861441b565b9150508260408301529695505050505050565b6000602082840312156144b057600080fd5b5051919050565b600067ffffffffffffffff838116908316818110156143cf576143cf614290565b600067ffffffffffffffff808416806144f3576144f3614312565b92169190910692915050565b60006020828403121561451157600080fd5b815161409881614059565b600067ffffffffffffffff80831681851680830382111561440257614402614290565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361457057614570614290565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000841360008413858304851182821616156145e7576145e7614290565b7f8000000000000000000000000000000000000000000000000000000000000000600087128682058812818416161561462257614622614290565b6000871292508782058712848416161561463e5761463e614290565b8785058712818416161561465457614654614290565b505050929093029392505050565b60008261467157614671614312565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f8000000000000000000000000000000000000000000000000000000000000000831416156146c5576146c5614290565b50059056fea164736f6c634300080f000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000000000031e3b504740d0b1264e8cf72b6dde0d497184cfb3f98e451c6be8b33bd3f8080000000000000000000000000000000000000000000000000000000000000049000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000093a80000000000000000000000000c29ae51b025f3f58243cb3331243460a13d8cf330000000000000000000000009bd56b189234fe25cf3547c4343e50c3259e383a0000000000000000000000001874a5cca34ebce29adf1ebdd7fd2725fe1848380000000000000000000000000000000000000000000000000000000000aa37dc
-----Decoded View---------------
Arg [0] : _gameType (uint32): 0
Arg [1] : _absolutePrestate (bytes32): 0x031e3b504740d0b1264e8cf72b6dde0d497184cfb3f98e451c6be8b33bd3f808
Arg [2] : _maxGameDepth (uint256): 73
Arg [3] : _splitDepth (uint256): 30
Arg [4] : _gameDuration (uint64): 604800
Arg [5] : _vm (address): 0xC29aE51B025f3F58243Cb3331243460A13d8CF33
Arg [6] : _weth (address): 0x9bD56B189234FE25CF3547c4343e50C3259e383a
Arg [7] : _anchorStateRegistry (address): 0x1874A5CCA34eBCe29aDf1ebdd7fD2725fe184838
Arg [8] : _l2ChainId (uint256): 11155420
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [1] : 031e3b504740d0b1264e8cf72b6dde0d497184cfb3f98e451c6be8b33bd3f808
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000049
Arg [3] : 000000000000000000000000000000000000000000000000000000000000001e
Arg [4] : 0000000000000000000000000000000000000000000000000000000000093a80
Arg [5] : 000000000000000000000000c29ae51b025f3f58243cb3331243460a13d8cf33
Arg [6] : 0000000000000000000000009bd56b189234fe25cf3547c4343e50c3259e383a
Arg [7] : 0000000000000000000000001874a5cca34ebce29adf1ebdd7fd2725fe184838
Arg [8] : 0000000000000000000000000000000000000000000000000000000000aa37dc
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.