ETH Price: $2,095.47 (+2.99%)

Contract

0x83a126e4DDe48eA211aa4B698eA5045CCec0cBB0
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Advance Match233758912025-09-16 13:21:23196 days ago1758028883IN
0x83a126e4...CCec0cBB0
0 ETH0.000121831.45021881
Join Tournament233758892025-09-16 13:20:59196 days ago1758028859IN
0x83a126e4...CCec0cBB0
0 ETH0.000497032.37056462
Join Tournament233482772025-09-12 16:48:35200 days ago1757695715IN
0x83a126e4...CCec0cBB0
0 ETH0.000187662.15658116
Join Tournament233481802025-09-12 16:28:59200 days ago1757694539IN
0x83a126e4...CCec0cBB0
0 ETH0.000067522.03151971
Join Tournament233294162025-09-10 1:27:35202 days ago1757467655IN
0x83a126e4...CCec0cBB0
0 ETH0.000019980.13957975

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Method Block
From
To
0x6101ad3d233293202025-09-10 1:08:11202 days ago1757466491  Contract Creation0 ETH
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

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

Minimal Proxy Contract for 0x09114973ae4bf3af3896e4e541082c73f224f8aa

Contract Name:
TopTournament

Compiler Version
v0.8.27+commit.40a35a09

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.17;

import {Clones} from "@openzeppelin-contracts-5.2.0/proxy/Clones.sol";

import "prt-contracts/tournament/abstracts/NonLeafTournament.sol";
import "prt-contracts/tournament/abstracts/RootTournament.sol";

import "prt-contracts/tournament/factories/IMultiLevelTournamentFactory.sol";

/// @notice Top tournament of a multi-level instance
contract TopTournament is NonLeafTournament, RootTournament {
    using Clones for address;

    struct Args {
        TournamentArgs tournamentArgs;
        IMultiLevelTournamentFactory tournamentFactory;
    }

    function _args() internal view returns (Args memory) {
        return abi.decode(address(this).fetchCloneArgs(), (Args));
    }

    function _tournamentArgs()
        internal
        view
        override
        returns (TournamentArgs memory)
    {
        return _args().tournamentArgs;
    }

    function _tournamentFactory()
        internal
        view
        override
        returns (IMultiLevelTournamentFactory)
    {
        return _args().tournamentFactory;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (proxy/Clones.sol)

pragma solidity ^0.8.20;

import {Create2} from "../utils/Create2.sol";
import {Errors} from "../utils/Errors.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[ERC-1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 */
library Clones {
    error CloneArgumentsTooLong();

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        return clone(implementation, 0);
    }

    /**
     * @dev Same as {xref-Clones-clone-address-}[clone], but with a `value` parameter to send native currency
     * to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function clone(address implementation, uint256 value) internal returns (address instance) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        assembly ("memory-safe") {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create(value, 0x09, 0x37)
        }
        if (instance == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple times will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        return cloneDeterministic(implementation, salt, 0);
    }

    /**
     * @dev Same as {xref-Clones-cloneDeterministic-address-bytes32-}[cloneDeterministic], but with
     * a `value` parameter to send native currency to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function cloneDeterministic(
        address implementation,
        bytes32 salt,
        uint256 value
    ) internal returns (address instance) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        assembly ("memory-safe") {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create2(value, 0x09, 0x37, salt)
        }
        if (instance == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(add(ptr, 0x38), deployer)
            mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
            mstore(add(ptr, 0x14), implementation)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
            mstore(add(ptr, 0x58), salt)
            mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
            predicted := and(keccak256(add(ptr, 0x43), 0x55), 0xffffffffffffffffffffffffffffffffffffffff)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt
    ) internal view returns (address predicted) {
        return predictDeterministicAddress(implementation, salt, address(this));
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom
     * immutable arguments. These are provided through `args` and cannot be changed after deployment. To
     * access the arguments within the implementation, use {fetchCloneArgs}.
     *
     * This function uses the create opcode, which should never revert.
     */
    function cloneWithImmutableArgs(address implementation, bytes memory args) internal returns (address instance) {
        return cloneWithImmutableArgs(implementation, args, 0);
    }

    /**
     * @dev Same as {xref-Clones-cloneWithImmutableArgs-address-bytes-}[cloneWithImmutableArgs], but with a `value`
     * parameter to send native currency to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function cloneWithImmutableArgs(
        address implementation,
        bytes memory args,
        uint256 value
    ) internal returns (address instance) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
        assembly ("memory-safe") {
            instance := create(value, add(bytecode, 0x20), mload(bytecode))
        }
        if (instance == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation` with custom
     * immutable arguments. These are provided through `args` and cannot be changed after deployment. To
     * access the arguments within the implementation, use {fetchCloneArgs}.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy the clone. Using the same
     * `implementation`, `args` and `salt` multiple times will revert, since the clones cannot be deployed twice
     * at the same address.
     */
    function cloneDeterministicWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt
    ) internal returns (address instance) {
        return cloneDeterministicWithImmutableArgs(implementation, args, salt, 0);
    }

    /**
     * @dev Same as {xref-Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-}[cloneDeterministicWithImmutableArgs],
     * but with a `value` parameter to send native currency to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function cloneDeterministicWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt,
        uint256 value
    ) internal returns (address instance) {
        bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
        return Create2.deploy(value, salt, bytecode);
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.
     */
    function predictDeterministicAddressWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
        return Create2.computeAddress(salt, keccak256(bytecode), deployer);
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.
     */
    function predictDeterministicAddressWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt
    ) internal view returns (address predicted) {
        return predictDeterministicAddressWithImmutableArgs(implementation, args, salt, address(this));
    }

    /**
     * @dev Get the immutable args attached to a clone.
     *
     * - If `instance` is a clone that was deployed using `clone` or `cloneDeterministic`, this
     *   function will return an empty array.
     * - If `instance` is a clone that was deployed using `cloneWithImmutableArgs` or
     *   `cloneDeterministicWithImmutableArgs`, this function will return the args array used at
     *   creation.
     * - If `instance` is NOT a clone deployed using this library, the behavior is undefined. This
     *   function should only be used to check addresses that are known to be clones.
     */
    function fetchCloneArgs(address instance) internal view returns (bytes memory) {
        bytes memory result = new bytes(instance.code.length - 45); // revert if length is too short
        assembly ("memory-safe") {
            extcodecopy(instance, add(result, 32), 45, mload(result))
        }
        return result;
    }

    /**
     * @dev Helper that prepares the initcode of the proxy with immutable args.
     *
     * An assembly variant of this function requires copying the `args` array, which can be efficiently done using
     * `mcopy`. Unfortunately, that opcode is not available before cancun. A pure solidity implementation using
     * abi.encodePacked is more expensive but also more portable and easier to review.
     *
     * NOTE: https://eips.ethereum.org/EIPS/eip-170[EIP-170] limits the length of the contract code to 24576 bytes.
     * With the proxy code taking 45 bytes, that limits the length of the immutable args to 24531 bytes.
     */
    function _cloneCodeWithImmutableArgs(
        address implementation,
        bytes memory args
    ) private pure returns (bytes memory) {
        if (args.length > 24531) revert CloneArgumentsTooLong();
        return
            abi.encodePacked(
                hex"61",
                uint16(args.length + 45),
                hex"3d81600a3d39f3363d3d373d3d3d363d73",
                implementation,
                hex"5af43d82803e903d91602b57fd5bf3",
                args
            );
    }
}

// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.17;

import "prt-contracts/tournament/abstracts/Tournament.sol";
import "prt-contracts/tournament/abstracts/NonRootTournament.sol";
import "prt-contracts/tournament/factories/IMultiLevelTournamentFactory.sol";

/// @notice Non-leaf tournament can create inner tournaments and matches
abstract contract NonLeafTournament is Tournament {
    using Clock for Clock.State;
    using Commitment for Tree.Node;
    using Machine for Machine.Hash;
    using Tree for Tree.Node;
    using Time for Time.Instant;
    using Match for Match.State;
    using Match for Match.Id;
    using Match for Match.IdHash;

    //
    // Storage
    //
    mapping(NonRootTournament => Match.IdHash) matchIdFromInnerTournaments;

    //
    // Events
    //
    event newInnerTournament(Match.IdHash indexed, NonRootTournament);

    function sealInnerMatchAndCreateInnerTournament(
        Match.Id calldata _matchId,
        Tree.Node _leftLeaf,
        Tree.Node _rightLeaf,
        Machine.Hash _agreeHash,
        bytes32[] calldata _agreeHashProof
    ) external tournamentNotFinished {
        Match.State storage _matchState = matches[_matchId.hashFromId()];
        _matchState.requireCanBeFinalized();
        // Pause clocks
        Time.Duration _maxDuration;
        {
            Clock.State storage _clock1 = clocks[_matchId.commitmentOne];
            Clock.State storage _clock2 = clocks[_matchId.commitmentTwo];
            _clock1.setPaused();
            _clock2.setPaused();
            _maxDuration = Clock.max(_clock1, _clock2);
        }
        TournamentArgs memory args = _tournamentArgs();
        (Machine.Hash _finalStateOne, Machine.Hash _finalStateTwo) = _matchState
            .sealMatch(
            _matchId,
            args.initialHash,
            _leftLeaf,
            _rightLeaf,
            _agreeHash,
            _agreeHashProof
        );
        NonRootTournament _inner = instantiateInner(
            _agreeHash,
            _matchId.commitmentOne,
            _finalStateOne,
            _matchId.commitmentTwo,
            _finalStateTwo,
            _maxDuration,
            _matchState.toCycle(args.startCycle),
            args.level + 1
        );
        matchIdFromInnerTournaments[_inner] = _matchId.hashFromId();

        emit newInnerTournament(_matchId.hashFromId(), _inner);
    }

    error ChildTournamentNotFinished();
    error ChildTournamentCannotBeEliminated();
    error ChildTournamentMustBeEliminated();
    error WrongTournamentWinner(Tree.Node commitmentRoot, Tree.Node winner);

    function winInnerTournament(
        NonRootTournament _childTournament,
        Tree.Node _leftNode,
        Tree.Node _rightNode
    ) external tournamentNotFinished {
        Match.IdHash _matchIdHash =
            matchIdFromInnerTournaments[_childTournament];
        _matchIdHash.requireExist();

        Match.State storage _matchState = matches[_matchIdHash];
        _matchState.requireExist();
        _matchState.requireIsFinished();

        require(
            !_childTournament.canBeEliminated(),
            ChildTournamentMustBeEliminated()
        );

        (bool finished, Tree.Node _winner,, Clock.State memory _innerClock) =
            _childTournament.innerTournamentWinner();
        require(finished, ChildTournamentNotFinished());
        _winner.requireExist();

        Tree.Node _commitmentRoot = _leftNode.join(_rightNode);
        require(
            _commitmentRoot.eq(_winner),
            WrongTournamentWinner(_commitmentRoot, _winner)
        );

        Clock.State storage _clock = clocks[_commitmentRoot];
        _clock.requireInitialized();
        _clock.reInitialized(_innerClock);

        pairCommitment(_commitmentRoot, _clock, _leftNode, _rightNode);

        // delete storage
        deleteMatch(_matchIdHash);
        matchIdFromInnerTournaments[_childTournament] = Match.ZERO_ID;
    }

    function eliminateInnerTournament(NonRootTournament _childTournament)
        external
        tournamentNotFinished
    {
        Match.IdHash _matchIdHash =
            matchIdFromInnerTournaments[_childTournament];
        _matchIdHash.requireExist();

        Match.State storage _matchState = matches[_matchIdHash];
        _matchState.requireExist();
        _matchState.requireIsFinished();

        require(
            _childTournament.canBeEliminated(),
            ChildTournamentCannotBeEliminated()
        );

        // delete storage
        deleteMatch(_matchIdHash);
        matchIdFromInnerTournaments[_childTournament] = Match.ZERO_ID;
    }

    function instantiateInner(
        Machine.Hash _initialHash,
        Tree.Node _contestedCommitmentOne,
        Machine.Hash _contestedFinalStateOne,
        Tree.Node _contestedCommitmentTwo,
        Machine.Hash _contestedFinalStateTwo,
        Time.Duration _allowance,
        uint256 _startCycle,
        uint64 _level
    ) private returns (NonRootTournament) {
        // the inner tournament is bottom tournament at last level
        // else instantiate middle tournament
        TournamentArgs memory args = _tournamentArgs();
        Tournament _tournament;
        IMultiLevelTournamentFactory tournamentFactory = _tournamentFactory();
        if (_level == args.levels - 1) {
            _tournament = tournamentFactory.instantiateBottom(
                _initialHash,
                _contestedCommitmentOne,
                _contestedFinalStateOne,
                _contestedCommitmentTwo,
                _contestedFinalStateTwo,
                _allowance,
                _startCycle,
                _level,
                args.provider
            );
        } else {
            _tournament = tournamentFactory.instantiateMiddle(
                _initialHash,
                _contestedCommitmentOne,
                _contestedFinalStateOne,
                _contestedCommitmentTwo,
                _contestedFinalStateTwo,
                _allowance,
                _startCycle,
                _level,
                args.provider
            );
        }

        return NonRootTournament(address(_tournament));
    }

    function _tournamentFactory()
        internal
        view
        virtual
        returns (IMultiLevelTournamentFactory);
}

// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.17;

import "prt-contracts/ITournament.sol";
import "prt-contracts/tournament/abstracts/Tournament.sol";
import "prt-contracts/types/TournamentParameters.sol";

/// @notice Root tournament has no parent
abstract contract RootTournament is Tournament, ITournament {
    function validContestedFinalState(Machine.Hash)
        internal
        pure
        override
        returns (bool, Machine.Hash, Machine.Hash)
    {
        // always returns true in root tournament
        return (true, Machine.ZERO_STATE, Machine.ZERO_STATE);
    }

    function arbitrationResult()
        external
        view
        override
        returns (bool, Tree.Node, Machine.Hash)
    {
        if (!isFinished()) {
            return (false, Tree.ZERO_NODE, Machine.ZERO_STATE);
        }

        (bool _hasDanglingCommitment, Tree.Node _danglingCommitment) =
            hasDanglingCommitment();
        assert(_hasDanglingCommitment);

        Machine.Hash _finalState = finalStates[_danglingCommitment];
        return (true, _danglingCommitment, _finalState);
    }
}

// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.17;

import "prt-contracts/ITournamentFactory.sol";

interface IMultiLevelTournamentFactory is ITournamentFactory {
    function instantiateTop(Machine.Hash _initialHash, IDataProvider _provider)
        external
        returns (Tournament);

    function instantiateMiddle(
        Machine.Hash _initialHash,
        Tree.Node _contestedCommitmentOne,
        Machine.Hash _contestedFinalStateOne,
        Tree.Node _contestedCommitmentTwo,
        Machine.Hash _contestedFinalStateTwo,
        Time.Duration _allowance,
        uint256 _startCycle,
        uint64 _level,
        IDataProvider _provider
    ) external returns (Tournament);

    function instantiateBottom(
        Machine.Hash _initialHash,
        Tree.Node _contestedCommitmentOne,
        Machine.Hash _contestedFinalStateOne,
        Tree.Node _contestedCommitmentTwo,
        Machine.Hash _contestedFinalStateTwo,
        Time.Duration _allowance,
        uint256 _startCycle,
        uint64 _level,
        IDataProvider _provider
    ) external returns (Tournament);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Create2.sol)

pragma solidity ^0.8.20;

import {Errors} from "./Errors.sol";

/**
 * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
 * `CREATE2` can be used to compute in advance the address where a smart
 * contract will be deployed, which allows for interesting new mechanisms known
 * as 'counterfactual interactions'.
 *
 * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
 * information.
 */
library Create2 {
    /**
     * @dev There's no code to deploy.
     */
    error Create2EmptyBytecode();

    /**
     * @dev Deploys a contract using `CREATE2`. The address where the contract
     * will be deployed can be known in advance via {computeAddress}.
     *
     * The bytecode for a contract can be obtained from Solidity with
     * `type(contractName).creationCode`.
     *
     * Requirements:
     *
     * - `bytecode` must not be empty.
     * - `salt` must have not been used for `bytecode` already.
     * - the factory must have a balance of at least `amount`.
     * - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
     */
    function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
        if (address(this).balance < amount) {
            revert Errors.InsufficientBalance(address(this).balance, amount);
        }
        if (bytecode.length == 0) {
            revert Create2EmptyBytecode();
        }
        assembly ("memory-safe") {
            addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
            // if no address was created, and returndata is not empty, bubble revert
            if and(iszero(addr), not(iszero(returndatasize()))) {
                let p := mload(0x40)
                returndatacopy(p, 0, returndatasize())
                revert(p, returndatasize())
            }
        }
        if (addr == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
     * `bytecodeHash` or `salt` will result in a new destination address.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
        return computeAddress(salt, bytecodeHash, address(this));
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
     * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
        assembly ("memory-safe") {
            let ptr := mload(0x40) // Get free memory pointer

            // |                   | ↓ ptr ...  ↓ ptr + 0x0B (start) ...  ↓ ptr + 0x20 ...  ↓ ptr + 0x40 ...   |
            // |-------------------|---------------------------------------------------------------------------|
            // | bytecodeHash      |                                                        CCCCCCCCCCCCC...CC |
            // | salt              |                                      BBBBBBBBBBBBB...BB                   |
            // | deployer          | 000000...0000AAAAAAAAAAAAAAAAAAA...AA                                     |
            // | 0xFF              |            FF                                                             |
            // |-------------------|---------------------------------------------------------------------------|
            // | memory            | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
            // | keccak(start, 85) |            ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |

            mstore(add(ptr, 0x40), bytecodeHash)
            mstore(add(ptr, 0x20), salt)
            mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
            let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
            mstore8(start, 0xff)
            addr := and(keccak256(start, 85), 0xffffffffffffffffffffffffffffffffffffffff)
        }
    }
}

File 7 of 20 : Errors.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of common custom errors used in multiple contracts
 *
 * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
 * It is recommended to avoid relying on the error API for critical functionality.
 *
 * _Available since v5.1._
 */
library Errors {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error InsufficientBalance(uint256 balance, uint256 needed);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedCall();

    /**
     * @dev The deployment failed.
     */
    error FailedDeployment();

    /**
     * @dev A necessary precompile is missing.
     */
    error MissingPrecompile(address);
}

// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.17;

import "prt-contracts/arbitration-config/ArbitrationConstants.sol";
import "prt-contracts/IDataProvider.sol";
import "prt-contracts/types/TournamentParameters.sol";
import "prt-contracts/types/Machine.sol";
import "prt-contracts/types/Tree.sol";

import "prt-contracts/tournament/libs/Commitment.sol";
import "prt-contracts/tournament/libs/Time.sol";
import "prt-contracts/tournament/libs/Clock.sol";
import "prt-contracts/tournament/libs/Match.sol";

struct TournamentArgs {
    Machine.Hash initialHash;
    uint256 startCycle;
    uint64 level;
    uint64 levels;
    uint64 log2step;
    uint64 height;
    Time.Instant startInstant;
    Time.Duration allowance;
    Time.Duration maxAllowance;
    Time.Duration matchEffort;
    IDataProvider provider;
}

/// @notice Implements the core functionalities of a permissionless tournament that resolves
/// disputes of n parties in O(log(n))
/// @dev tournaments and matches are nested alternately. Anyone can join a tournament
/// while the tournament is still open, and two of the participants with unique commitments
/// will form a match. A match located in the last level is called `leafMatch`,
/// meaning the one-step disagreement is found and can be resolved by solidity-step.
/// Non-leaf (inner) matches would normally create inner tournaments with height = height + 1,
/// to find the divergence with improved precision.
abstract contract Tournament {
    using Machine for Machine.Hash;
    using Tree for Tree.Node;
    using Commitment for Tree.Node;

    using Time for Time.Instant;
    using Time for Time.Duration;

    using Clock for Clock.State;

    using Match for Match.Id;
    using Match for Match.IdHash;
    using Match for Match.State;

    //
    // Storage
    //
    Tree.Node danglingCommitment;
    uint256 matchCount;
    Time.Instant lastMatchDeleted;

    mapping(Tree.Node => Clock.State) clocks;
    mapping(Tree.Node => Machine.Hash) finalStates;
    // matches existing in current tournament
    mapping(Match.IdHash => Match.State) matches;

    //
    // Events
    //
    event matchCreated(
        Tree.Node indexed one, Tree.Node indexed two, Tree.Node leftOfTwo
    );
    event matchDeleted(Match.IdHash);
    event commitmentJoined(Tree.Node root);

    //
    // Modifiers
    //
    error TournamentIsFinished();
    error TournamentIsClosed();

    modifier tournamentNotFinished() {
        require(!isFinished(), TournamentIsFinished());

        _;
    }

    modifier tournamentOpen() {
        require(!isClosed(), TournamentIsClosed());

        _;
    }

    //
    // Virtual Methods
    //

    /// @return bool if commitment with _finalState is allowed to join the tournament
    function validContestedFinalState(Machine.Hash _finalState)
        internal
        view
        virtual
        returns (bool, Machine.Hash, Machine.Hash);

    //
    // Methods
    //

    /// @dev root tournaments are open to everyone,
    /// while non-root tournaments are open to anyone
    /// who's final state hash matches the one of the two in the tournament
    function joinTournament(
        Machine.Hash _finalState,
        bytes32[] calldata _proof,
        Tree.Node _leftNode,
        Tree.Node _rightNode
    ) external tournamentOpen {
        Tree.Node _commitmentRoot = _leftNode.join(_rightNode);

        TournamentArgs memory args = _tournamentArgs();

        // Prove final state is in commitmentRoot
        _commitmentRoot.requireFinalState(args.height, _finalState, _proof);

        // Verify whether finalState is one of the two allowed of tournament if nested
        requireValidContestedFinalState(_finalState);
        finalStates[_commitmentRoot] = _finalState;

        Clock.State storage _clock = clocks[_commitmentRoot];
        _clock.requireNotInitialized(); // reverts if commitment is duplicate
        _clock.setNewPaused(args.startInstant, args.allowance);

        pairCommitment(_commitmentRoot, _clock, _leftNode, _rightNode);
        emit commitmentJoined(_commitmentRoot);
    }

    /// @notice Advance the match until the smallest divergence is found at current level
    /// @dev this function is being called repeatedly in turns by the two parties that disagree on the commitment.
    function advanceMatch(
        Match.Id calldata _matchId,
        Tree.Node _leftNode,
        Tree.Node _rightNode,
        Tree.Node _newLeftNode,
        Tree.Node _newRightNode
    ) external tournamentNotFinished {
        Match.State storage _matchState = matches[_matchId.hashFromId()];
        _matchState.requireExist();
        _matchState.requireCanBeAdvanced();

        _matchState.advanceMatch(
            _matchId, _leftNode, _rightNode, _newLeftNode, _newRightNode
        );

        // advance clocks
        clocks[_matchId.commitmentOne].advanceClock();
        clocks[_matchId.commitmentTwo].advanceClock();
    }

    error WrongChildren(
        uint256 commitment, Tree.Node parent, Tree.Node left, Tree.Node right
    );
    error WinByTimeout();

    function winMatchByTimeout(
        Match.Id calldata _matchId,
        Tree.Node _leftNode,
        Tree.Node _rightNode
    ) external tournamentNotFinished {
        matches[_matchId.hashFromId()].requireExist();
        Clock.State storage _clockOne = clocks[_matchId.commitmentOne];
        Clock.State storage _clockTwo = clocks[_matchId.commitmentTwo];

        _clockOne.requireInitialized();
        _clockTwo.requireInitialized();

        if (_clockOne.hasTimeLeft() && !_clockTwo.hasTimeLeft()) {
            require(
                _matchId.commitmentOne.verify(_leftNode, _rightNode),
                WrongChildren(1, _matchId.commitmentOne, _leftNode, _rightNode)
            );

            _clockOne.deducted(_clockTwo.timeSinceTimeout());
            pairCommitment(
                _matchId.commitmentOne, _clockOne, _leftNode, _rightNode
            );
        } else if (!_clockOne.hasTimeLeft() && _clockTwo.hasTimeLeft()) {
            require(
                _matchId.commitmentTwo.verify(_leftNode, _rightNode),
                WrongChildren(2, _matchId.commitmentTwo, _leftNode, _rightNode)
            );

            _clockTwo.deducted(_clockOne.timeSinceTimeout());
            pairCommitment(
                _matchId.commitmentTwo, _clockTwo, _leftNode, _rightNode
            );
        } else {
            revert WinByTimeout();
        }

        // delete storage
        deleteMatch(_matchId.hashFromId());
    }

    error EliminateByTimeout();

    function eliminateMatchByTimeout(Match.Id calldata _matchId)
        external
        tournamentNotFinished
    {
        matches[_matchId.hashFromId()].requireExist();
        Clock.State storage _clockOne = clocks[_matchId.commitmentOne];
        Clock.State storage _clockTwo = clocks[_matchId.commitmentTwo];

        _clockOne.requireInitialized();
        _clockTwo.requireInitialized();

        // check if both clocks are out of time
        if (
            (
                !_clockOne.hasTimeLeft()
                    && !_clockTwo.timeLeft().gt(_clockOne.timeSinceTimeout())
            )
                || (
                    !_clockTwo.hasTimeLeft()
                        && !_clockOne.timeLeft().gt(_clockTwo.timeSinceTimeout())
                )
        ) {
            // delete storage
            deleteMatch(_matchId.hashFromId());
        } else {
            revert EliminateByTimeout();
        }
    }

    //
    // View methods
    //
    function canWinMatchByTimeout(Match.Id calldata _matchId)
        external
        view
        returns (bool)
    {
        Clock.State memory _clockOne = clocks[_matchId.commitmentOne];
        Clock.State memory _clockTwo = clocks[_matchId.commitmentTwo];

        return !_clockOne.hasTimeLeft() || !_clockTwo.hasTimeLeft();
    }

    function getCommitment(Tree.Node _commitmentRoot)
        public
        view
        returns (Clock.State memory, Machine.Hash)
    {
        return (clocks[_commitmentRoot], finalStates[_commitmentRoot]);
    }

    function getMatch(Match.IdHash _matchIdHash)
        public
        view
        returns (Match.State memory)
    {
        return matches[_matchIdHash];
    }

    function getMatchCycle(Match.IdHash _matchIdHash)
        external
        view
        returns (uint256)
    {
        Match.State memory _m = getMatch(_matchIdHash);
        uint256 startCycle = _tournamentArgs().startCycle;
        return _m.toCycle(startCycle);
    }

    function tournamentLevelConstants()
        external
        view
        returns (
            uint64 _maxLevel,
            uint64 _level,
            uint64 _log2step,
            uint64 _height
        )
    {
        TournamentArgs memory args;
        args = _tournamentArgs();
        _maxLevel = args.levels;
        _level = args.level;
        _log2step = args.log2step;
        _height = args.height;
    }

    //
    // Helper functions
    //
    error InvalidContestedFinalState(
        Machine.Hash contestedFinalStateOne,
        Machine.Hash contestedFinalStateTwo,
        Machine.Hash finalState
    );

    function requireValidContestedFinalState(Machine.Hash _finalState)
        internal
        view
    {
        (
            bool valid,
            Machine.Hash contestedFinalStateOne,
            Machine.Hash contestedFinalStateTwo
        ) = validContestedFinalState(_finalState);
        require(
            valid,
            InvalidContestedFinalState(
                contestedFinalStateOne, contestedFinalStateTwo, _finalState
            )
        );
    }

    function hasDanglingCommitment()
        internal
        view
        returns (bool _h, Tree.Node _node)
    {
        _node = danglingCommitment;

        if (!_node.isZero()) {
            _h = true;
        }
    }

    function setDanglingCommitment(Tree.Node _node) internal {
        danglingCommitment = _node;
    }

    function clearDanglingCommitment() internal {
        danglingCommitment = Tree.ZERO_NODE;
    }

    function pairCommitment(
        Tree.Node _rootHash,
        Clock.State storage _newClock,
        Tree.Node _leftNode,
        Tree.Node _rightNode
    ) internal {
        assert(_leftNode.join(_rightNode).eq(_rootHash));
        (bool _hasDanglingCommitment, Tree.Node _danglingCommitment) =
            hasDanglingCommitment();

        if (_hasDanglingCommitment) {
            TournamentArgs memory args = _tournamentArgs();
            (Match.IdHash _matchId, Match.State memory _matchState) = Match
                .createMatch(
                _danglingCommitment,
                _rootHash,
                _leftNode,
                _rightNode,
                args.log2step,
                args.height
            );

            matches[_matchId] = _matchState;

            Clock.State storage _firstClock = clocks[_danglingCommitment];

            // grant extra match effort for both clocks
            _firstClock.addMatchEffort(args.matchEffort, args.maxAllowance);
            _newClock.addMatchEffort(args.matchEffort, args.maxAllowance);

            _firstClock.advanceClock();

            clearDanglingCommitment();
            matchCount++;

            emit matchCreated(_danglingCommitment, _rootHash, _leftNode);
        } else {
            setDanglingCommitment(_rootHash);
        }
    }

    function deleteMatch(Match.IdHash _matchIdHash) internal {
        matchCount--;
        lastMatchDeleted = Time.currentTime();
        delete matches[_matchIdHash];
        emit matchDeleted(_matchIdHash);
    }

    //
    // Clock methods
    //

    /// @return bool if the tournament is still open to join
    function isClosed() public view returns (bool) {
        Time.Instant startInstant;
        Time.Duration allowance;
        {
            TournamentArgs memory args;
            args = _tournamentArgs();
            startInstant = args.startInstant;
            allowance = args.allowance;
        }
        return startInstant.timeoutElapsed(allowance);
    }

    /// @return bool if the tournament is over
    function isFinished() public view returns (bool) {
        return isClosed() && matchCount == 0;
    }

    /// @notice returns if and when tournament was finished.
    /// @return (bool, Time.Instant)
    /// - if the tournament can be eliminated
    /// - the time when the tournament was finished
    function timeFinished() public view returns (bool, Time.Instant) {
        if (!isFinished()) {
            return (false, Time.ZERO_INSTANT);
        }

        TournamentArgs memory args = _tournamentArgs();

        // Here, we know that `lastMatchDeleted` holds the Instant when `matchCount` became zero.
        // However, we still must consider when the tournament was closed, in case it
        // happens after `lastMatchDeleted`.
        // Note that `lastMatchDeleted` could be zero if there are no matches eliminated.
        // In this case, we'd only care about `tournamentClosed`.
        Time.Instant tournamentClosed = args.startInstant.add(args.allowance);
        Time.Instant winnerCouldWin = tournamentClosed.max(lastMatchDeleted);

        return (true, winnerCouldWin);
    }

    //
    // Internal functions
    //
    function _tournamentArgs()
        internal
        view
        virtual
        returns (TournamentArgs memory);
}

// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.17;

import "prt-contracts/tournament/abstracts/Tournament.sol";
import "prt-contracts/types/TournamentParameters.sol";

struct NonRootTournamentArgs {
    Tree.Node contestedCommitmentOne;
    Machine.Hash contestedFinalStateOne;
    Tree.Node contestedCommitmentTwo;
    Machine.Hash contestedFinalStateTwo;
}

/// @notice Non-root tournament needs to propagate side-effects to its parent
abstract contract NonRootTournament is Tournament {
    using Machine for Machine.Hash;
    using Tree for Tree.Node;

    using Time for Time.Instant;
    using Time for Time.Duration;

    using Clock for Clock.State;

    /// @notice get the dangling commitment at current level and then retrieve the winner commitment
    /// @return (bool, Tree.Node, Tree.Node)
    /// - if the tournament is finished
    /// - the contested parent commitment
    /// - the winning inner commitment
    /// - the paused clock of the winning inner commitment
    function innerTournamentWinner()
        external
        view
        returns (bool, Tree.Node, Tree.Node, Clock.State memory)
    {
        if (!isFinished() || canBeEliminated()) {
            Clock.State memory zeroClock;
            return (false, Tree.ZERO_NODE, Tree.ZERO_NODE, zeroClock);
        }

        (bool _hasDanglingCommitment, Tree.Node _winner) =
            hasDanglingCommitment();
        assert(_hasDanglingCommitment);

        (bool finished, Time.Instant timeFinished) = timeFinished();
        assert(finished);

        Clock.State memory _clock = clocks[_winner];
        _clock = _clock.deduct(Time.currentTime().timeSpan(timeFinished));

        NonRootTournamentArgs memory args = _nonRootTournamentArgs();
        Machine.Hash _finalState = finalStates[_winner];

        if (_finalState.eq(args.contestedFinalStateOne)) {
            return (true, args.contestedCommitmentOne, _winner, _clock);
        } else {
            assert(_finalState.eq(args.contestedFinalStateTwo));
            return (true, args.contestedCommitmentTwo, _winner, _clock);
        }
    }

    /// @notice returns whether this inner tournament can be safely eliminated.
    /// @return (bool)
    /// - if the tournament can be eliminated
    function canBeEliminated() public view returns (bool) {
        (bool finished, Time.Instant winnerCouldHaveWon) = timeFinished();

        if (!finished) {
            return false;
        }

        (bool _hasDanglingCommitment, Tree.Node _danglingCommitment) =
            hasDanglingCommitment();

        // If the tournament is finished but has no winners,
        // inner tournament can be eliminated
        if (!_hasDanglingCommitment) {
            return true;
        }

        // We know that, after `winnerCouldHaveWon` plus  winner's clock.allowance has elapsed,
        // it is safe to elminate the tournament.
        (Clock.State memory clock,) = getCommitment(_danglingCommitment);
        return winnerCouldHaveWon.timeoutElapsed(clock.allowance);
    }

    /// @notice a final state is valid if it's equal to ContestedFinalStateOne or ContestedFinalStateTwo
    function validContestedFinalState(Machine.Hash _finalState)
        internal
        view
        override
        returns (bool, Machine.Hash, Machine.Hash)
    {
        NonRootTournamentArgs memory args = _nonRootTournamentArgs();
        return (
            args.contestedFinalStateOne.eq(_finalState)
                || args.contestedFinalStateTwo.eq(_finalState),
            args.contestedFinalStateOne,
            args.contestedFinalStateTwo
        );
    }

    function _nonRootTournamentArgs()
        internal
        view
        virtual
        returns (NonRootTournamentArgs memory);
}

// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.17;

import "prt-contracts/types/Machine.sol";
import "prt-contracts/types/Tree.sol";

interface ITournament {
    function arbitrationResult()
        external
        view
        returns (
            bool finished,
            Tree.Node winnerCommitment,
            Machine.Hash finalState
        );
}

File 11 of 20 : TournamentParameters.sol
// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.17;

import "prt-contracts/tournament/libs/Time.sol";

struct TournamentParameters {
    uint64 levels;
    uint64 log2step;
    uint64 height;
    Time.Duration matchEffort;
    Time.Duration maxAllowance;
}

// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.17;

import "prt-contracts/ITournament.sol";
import "prt-contracts/tournament/abstracts/Tournament.sol";
import "prt-contracts/IDataProvider.sol";

interface ITournamentFactory {
    event tournamentCreated(ITournament tournament);

    function instantiate(Machine.Hash initialState, IDataProvider provider)
        external
        returns (ITournament);
}

// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.17;

import "prt-contracts/tournament/libs/Time.sol";

library ArbitrationConstants {
    // 3-level tournament
    uint64 constant LEVELS = 3;

    /// @return log2step gap of each leaf in the tournament[level]
    function log2step(uint64 level) internal pure returns (uint64) {
        uint64[LEVELS] memory arr = [uint64(44), uint64(27), uint64(0)];
        return arr[level];
    }

    /// @return height of the tournament[level] tree which is calculated by subtracting the log2step[level] from the log2step[level - 1]
    function height(uint64 level) internal pure returns (uint64) {
        uint64[LEVELS] memory arr = [uint64(48), uint64(17), uint64(27)];
        return arr[level];
    }
}

// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.17;

interface IDataProvider {
    /// @notice Provides the Merkle root of an input
    /// @param inputIndexWithinEpoch The index of the input within the epoch
    /// @param input The input blob (to hash and check against the input box)
    /// @return The root of smallest Merkle tree that fits the input
    function provideMerkleRootOfInput(
        uint256 inputIndexWithinEpoch,
        bytes calldata input
    ) external view returns (bytes32);
}

// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.17;

library Machine {
    type Hash is bytes32;

    Hash constant ZERO_STATE = Hash.wrap(0x0);

    function notInitialized(Hash hash) internal pure returns (bool) {
        bytes32 h = Hash.unwrap(hash);
        return h == 0x0;
    }

    function eq(Hash left, Hash right) internal pure returns (bool) {
        bytes32 l = Hash.unwrap(left);
        bytes32 r = Hash.unwrap(right);
        return l == r;
    }
}

// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.17;

import "prt-contracts/types/Machine.sol";

library Tree {
    using Tree for Node;

    type Node is bytes32;

    Node constant ZERO_NODE = Node.wrap(bytes32(0x0));

    function eq(Node left, Node right) internal pure returns (bool) {
        bytes32 l = Node.unwrap(left);
        bytes32 r = Node.unwrap(right);
        return l == r;
    }

    function join(Node left, Node right) internal pure returns (Node) {
        bytes32 l = Node.unwrap(left);
        bytes32 r = Node.unwrap(right);
        bytes32 p = keccak256(abi.encode(l, r));
        return Node.wrap(p);
    }

    function verify(Node parent, Node left, Node right)
        internal
        pure
        returns (bool)
    {
        return parent.eq(left.join(right));
    }

    function requireChildren(Node parent, Node left, Node right)
        internal
        pure
    {
        require(parent.verify(left, right), "child nodes don't match parent");
    }

    function isZero(Node node) internal pure returns (bool) {
        bytes32 n = Node.unwrap(node);
        return n == 0x0;
    }

    function requireExist(Node node) internal pure {
        require(!node.isZero(), "tree node doesn't exist");
    }

    function toMachineHash(Node node) internal pure returns (Machine.Hash) {
        return Machine.Hash.wrap(Node.unwrap(node));
    }
}

// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.17;

import "prt-contracts/arbitration-config/ArbitrationConstants.sol";
import "prt-contracts/types/Tree.sol";
import "prt-contracts/types/Machine.sol";

library Commitment {
    using Tree for Tree.Node;
    using Commitment for Tree.Node;

    error CommitmentMismatch(Tree.Node received, Tree.Node expected);

    function requireState(
        Tree.Node commitment,
        uint64 treeHeight,
        uint256 position,
        Machine.Hash state,
        bytes32[] calldata hashProof
    ) internal pure {
        Tree.Node expectedCommitment =
            getRoot(Machine.Hash.unwrap(state), treeHeight, position, hashProof);

        require(
            commitment.eq(expectedCommitment),
            CommitmentMismatch(commitment, expectedCommitment)
        );
    }

    function isEven(uint256 x) private pure returns (bool) {
        return x % 2 == 0;
    }

    error LengthMismatch(uint64 treeHeight, uint64 siblingsLength);

    function getRoot(
        bytes32 leaf,
        uint64 treeHeight,
        uint256 position,
        bytes32[] calldata siblings
    ) internal pure returns (Tree.Node) {
        uint64 siblingsLength = uint64(siblings.length);
        require(
            treeHeight == siblingsLength,
            LengthMismatch(treeHeight, siblingsLength)
        );

        for (uint256 i = 0; i < treeHeight; i++) {
            if (isEven(position >> i)) {
                leaf = keccak256(abi.encodePacked(leaf, siblings[i]));
            } else {
                leaf = keccak256(abi.encodePacked(siblings[i], leaf));
            }
        }

        return Tree.Node.wrap(leaf);
    }

    function requireFinalState(
        Tree.Node commitment,
        uint64 treeHeight,
        Machine.Hash finalState,
        bytes32[] calldata hashProof
    ) internal pure {
        Tree.Node expectedCommitment = getRootForLastLeaf(
            treeHeight, Machine.Hash.unwrap(finalState), hashProof
        );

        require(
            commitment.eq(expectedCommitment),
            "commitment last state doesn't match"
        );
    }

    function getRootForLastLeaf(
        uint64 treeHeight,
        bytes32 leaf,
        bytes32[] calldata siblings
    ) internal pure returns (Tree.Node) {
        assert(treeHeight == siblings.length);

        for (uint256 i = 0; i < treeHeight; i++) {
            leaf = keccak256(abi.encodePacked(siblings[i], leaf));
        }

        return Tree.Node.wrap(leaf);
    }
}

// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.17;

library Time {
    type Instant is uint64;
    type Duration is uint64;

    using Time for Instant;
    using Time for Duration;

    Instant constant ZERO_INSTANT = Instant.wrap(0);
    Duration constant ZERO_DURATION = Duration.wrap(0);

    function currentTime() internal view returns (Instant) {
        return Instant.wrap(uint64(block.number));
    }

    function add(Instant timestamp, Duration duration)
        internal
        pure
        returns (Instant)
    {
        uint64 t = Instant.unwrap(timestamp);
        uint64 d = Duration.unwrap(duration);
        return Instant.wrap(t + d);
    }

    function gt(Instant left, Instant right) internal pure returns (bool) {
        uint64 l = Instant.unwrap(left);
        uint64 r = Instant.unwrap(right);
        return l > r;
    }

    function gt(Duration left, Duration right) internal pure returns (bool) {
        uint64 l = Duration.unwrap(left);
        uint64 r = Duration.unwrap(right);
        return l > r;
    }

    function isZero(Instant timestamp) internal pure returns (bool) {
        uint64 t = Instant.unwrap(timestamp);
        return t == 0;
    }

    function isZero(Duration duration) internal pure returns (bool) {
        uint64 d = Duration.unwrap(duration);
        return d == 0;
    }

    function add(Duration left, Duration right)
        internal
        pure
        returns (Duration)
    {
        uint64 l = Duration.unwrap(left);
        uint64 r = Duration.unwrap(right);
        return Duration.wrap(l + r);
    }

    function sub(Duration left, Duration right)
        internal
        pure
        returns (Duration)
    {
        uint64 l = Duration.unwrap(left);
        uint64 r = Duration.unwrap(right);
        return Duration.wrap(l - r);
    }

    function monus(Duration left, Duration right)
        internal
        pure
        returns (Duration)
    {
        uint64 l = Duration.unwrap(left);
        uint64 r = Duration.unwrap(right);
        return Duration.wrap(l < r ? 0 : l - r);
    }

    function timeSpan(Instant left, Instant right)
        internal
        pure
        returns (Duration)
    {
        uint64 l = Instant.unwrap(left);
        uint64 r = Instant.unwrap(right);
        return Duration.wrap(l - r);
    }

    function timeoutElapsedSince(
        Instant timestamp,
        Duration duration,
        Instant current
    ) internal pure returns (bool) {
        return !timestamp.add(duration).gt(current);
    }

    function timeoutElapsed(Instant timestamp, Duration duration)
        internal
        view
        returns (bool)
    {
        return timestamp.timeoutElapsedSince(duration, currentTime());
    }

    function min(Duration left, Duration right)
        internal
        pure
        returns (Duration)
    {
        return left.gt(right) ? right : left;
    }

    function max(Instant left, Instant right) internal pure returns (Instant) {
        return left.gt(right) ? left : right;
    }
}

// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.17;

import "prt-contracts/tournament/libs/Time.sol";
import "prt-contracts/arbitration-config/ArbitrationConstants.sol";

library Clock {
    using Time for Time.Instant;
    using Time for Time.Duration;

    using Clock for State;

    struct State {
        Time.Duration allowance;
        Time.Instant startInstant; // the block number when the clock started ticking, zero means clock is paused
    }

    //
    // View/Pure methods
    //
    function notInitialized(State memory state) internal pure returns (bool) {
        return state.allowance.isZero();
    }

    function requireInitialized(State memory state) internal pure {
        require(!state.notInitialized(), "clock is not initialized");
    }

    function requireNotInitialized(State memory state) internal pure {
        require(state.notInitialized(), "clock is initialized");
    }

    function hasTimeLeft(State memory state) internal view returns (bool) {
        if (state.startInstant.isZero()) {
            // a paused clock is always considered having time left
            return true;
        } else {
            // otherwise the allowance must be greater than the timespan from current time to start instant
            return state.allowance.gt(
                Time.timeSpan(Time.currentTime(), state.startInstant)
            );
        }
    }

    /// @return max allowance of two paused clocks
    function max(State memory pausedState1, State memory pausedState2)
        internal
        pure
        returns (Time.Duration)
    {
        if (pausedState1.allowance.gt(pausedState2.allowance)) {
            return pausedState1.allowance;
        } else {
            return pausedState2.allowance;
        }
    }

    /// @return duration of time has elapsed since the clock timeout
    function timeSinceTimeout(State memory state)
        internal
        view
        returns (Time.Duration)
    {
        if (state.startInstant.isZero()) {
            revert("a paused clock can't timeout");
        }

        return Time.timeSpan(Time.currentTime(), state.startInstant).monus(
            state.allowance
        );
    }

    function timeLeft(State memory state)
        internal
        view
        returns (Time.Duration)
    {
        if (state.startInstant.isZero()) {
            return state.allowance;
        } else {
            return state.allowance.monus(
                Time.timeSpan(Time.currentTime(), state.startInstant)
            );
        }
    }

    //
    // Storage methods
    //

    /// @notice re-initialize a clock with new state
    function reInitialized(State storage state, State memory newState)
        internal
    {
        Time.Duration _allowance = timeLeft(newState);
        _setNewPaused(state, _allowance);
    }

    function setNewPaused(
        State storage state,
        Time.Instant checkinInstant,
        Time.Duration initialAllowance
    ) internal {
        Time.Duration _allowance =
            initialAllowance.monus(Time.currentTime().timeSpan(checkinInstant));
        _setNewPaused(state, _allowance);
    }

    /// @notice Resume the clock from pause state, or pause a clock and update the allowance
    function advanceClock(State storage state) internal {
        Time.Duration _timeLeft = timeLeft(state);

        if (_timeLeft.isZero()) {
            revert("can't advance clock with no time left");
        }

        toggleClock(state);
        state.allowance = _timeLeft;
    }

    /// @notice Deduct duration from a clock and set it to paused.
    /// The clock must have time left after deduction.
    function deducted(State storage state, Time.Duration deduction) internal {
        Time.Duration _timeLeft = state.allowance.monus(deduction);
        _setNewPaused(state, _timeLeft);
    }

    /// @notice Deduct duration from a clock and set it to paused.
    /// The clock must have time left after deduction.
    function deduct(State memory state, Time.Duration deduction)
        internal
        pure
        returns (State memory)
    {
        assert(state.startInstant.isZero());
        Time.Duration _timeLeft = state.allowance.monus(deduction);
        return State({startInstant: Time.ZERO_INSTANT, allowance: _timeLeft});
    }

    /// @notice Add matchEffort to a clock and set it to paused.
    /// The new clock allowance is capped by maxAllowance.
    function addMatchEffort(
        State storage state,
        Time.Duration matchEffort,
        Time.Duration maxAllowance
    ) internal {
        Time.Duration _timeLeft = timeLeft(state);

        Time.Duration _allowance = _timeLeft.add(matchEffort).min(maxAllowance);

        _setNewPaused(state, _allowance);
    }

    function setPaused(State storage state) internal {
        if (!state.startInstant.isZero()) {
            state.advanceClock();
        }
    }

    //
    // Private
    //
    function toggleClock(State storage state) private {
        if (state.startInstant.isZero()) {
            state.startInstant = Time.currentTime();
        } else {
            state.startInstant = Time.ZERO_INSTANT;
        }
    }

    function _setNewPaused(State storage state, Time.Duration allowance)
        private
    {
        if (allowance.isZero()) {
            revert("can't create clock with zero time");
        }

        state.allowance = allowance;
        state.startInstant = Time.ZERO_INSTANT;
    }
}

// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.17;

import "prt-contracts/arbitration-config/ArbitrationConstants.sol";
import "prt-contracts/types/Tree.sol";
import "prt-contracts/types/Machine.sol";
import "./Commitment.sol";

/// @notice Implements functionalities to advance a match, until the point where divergence is found.
library Match {
    using Tree for Tree.Node;
    using Match for Id;
    using Match for IdHash;
    using Match for State;
    using Machine for Machine.Hash;
    using Commitment for Tree.Node;

    //
    // Events
    //
    event matchAdvanced(Match.IdHash indexed, Tree.Node parent, Tree.Node left);

    //
    // Id
    //
    struct Id {
        Tree.Node commitmentOne;
        Tree.Node commitmentTwo;
    }

    //
    // IdHash
    //
    type IdHash is bytes32;

    IdHash constant ZERO_ID = IdHash.wrap(bytes32(0x0));

    function hashFromId(Id memory id) internal pure returns (IdHash) {
        return IdHash.wrap(keccak256(abi.encode(id)));
    }

    function isZero(IdHash idHash) internal pure returns (bool) {
        return IdHash.unwrap(idHash) == 0x0;
    }

    function eq(IdHash left, IdHash right) internal pure returns (bool) {
        bytes32 l = IdHash.unwrap(left);
        bytes32 r = IdHash.unwrap(right);
        return l == r;
    }

    function requireEq(IdHash left, IdHash right) internal pure {
        require(left.eq(right), "matches are not equal");
    }

    function requireExist(IdHash idHash) internal pure {
        require(!idHash.isZero(), "match doesn't exist");
    }

    //
    // State
    //
    struct State {
        Tree.Node otherParent;
        Tree.Node leftNode;
        Tree.Node rightNode;
        // Once match is done, leftNode and rightNode change meaning
        // and contains contested final states.
        uint256 runningLeafPosition;
        uint64 currentHeight;
        uint64 log2step; // constant
        uint64 height; // constant
    }

    function createMatch(
        Tree.Node one,
        Tree.Node two,
        Tree.Node leftNodeOfTwo,
        Tree.Node rightNodeOfTwo,
        uint64 log2step,
        uint64 height
    ) internal pure returns (IdHash, State memory) {
        assert(two.verify(leftNodeOfTwo, rightNodeOfTwo));

        Id memory matchId = Id(one, two);

        State memory state = State({
            otherParent: one,
            leftNode: leftNodeOfTwo,
            rightNode: rightNodeOfTwo,
            runningLeafPosition: 0,
            currentHeight: height,
            log2step: log2step,
            height: height
        });

        return (matchId.hashFromId(), state);
    }

    function advanceMatch(
        State storage state,
        Id calldata id,
        Tree.Node leftNode,
        Tree.Node rightNode,
        Tree.Node newLeftNode,
        Tree.Node newRightNode
    ) internal {
        state.requireParentHasChildren(leftNode, rightNode);

        if (!state.agreesOnLeftNode(leftNode)) {
            // go down left in Commitment tree
            leftNode.requireChildren(newLeftNode, newRightNode);
            state._goDownLeftTree(newLeftNode, newRightNode);
        } else {
            // go down right in Commitment tree
            rightNode.requireChildren(newLeftNode, newRightNode);
            state._goDownRightTree(newLeftNode, newRightNode);
        }

        emit matchAdvanced(id.hashFromId(), state.otherParent, state.leftNode);
    }

    error IncorrectAgreeState(
        Machine.Hash initialState, Machine.Hash agreeState
    );

    function sealMatch(
        State storage state,
        Id calldata id,
        Machine.Hash initialState,
        Tree.Node leftLeaf,
        Tree.Node rightLeaf,
        Machine.Hash agreeState,
        bytes32[] calldata agreeStateProof
    )
        internal
        returns (Machine.Hash divergentStateOne, Machine.Hash divergentStateTwo)
    {
        state.requireParentHasChildren(leftLeaf, rightLeaf);

        if (!state.agreesOnLeftNode(leftLeaf)) {
            // Divergence is in the left leaf!
            (divergentStateOne, divergentStateTwo) =
                state._setDivergenceOnLeftLeaf(leftLeaf);
        } else {
            // Divergence is in the right leaf!
            (divergentStateOne, divergentStateTwo) =
                state._setDivergenceOnRightLeaf(rightLeaf);
        }

        // Prove agree hash is in commitment
        if (state.runningLeafPosition == 0) {
            require(
                agreeState.eq(initialState),
                IncorrectAgreeState(initialState, agreeState)
            );
        } else {
            Tree.Node commitment;
            if (state.height % 2 == 1) {
                commitment = id.commitmentOne;
            } else {
                commitment = id.commitmentTwo;
            }

            commitment.requireState(
                state.height,
                state.runningLeafPosition - 1,
                agreeState,
                agreeStateProof
            );
        }

        state._setAgreeState(agreeState);
    }

    //
    // View methods
    //
    function exists(State memory state) internal pure returns (bool) {
        return !state.otherParent.isZero();
    }

    function isFinished(State memory state) internal pure returns (bool) {
        return state.currentHeight == 0;
    }

    function canBeFinalized(State memory state) internal pure returns (bool) {
        return state.currentHeight == 1;
    }

    function canBeAdvanced(State memory state) internal pure returns (bool) {
        return state.currentHeight > 1;
    }

    function agreesOnLeftNode(State memory state, Tree.Node newLeftNode)
        internal
        pure
        returns (bool)
    {
        return newLeftNode.eq(state.leftNode);
    }

    function toCycle(State memory state, uint256 startCycle)
        internal
        pure
        returns (uint256)
    {
        uint256 step = 1 << state.log2step;
        uint256 leafPosition = state.runningLeafPosition;
        return startCycle + (leafPosition * step);
    }

    function getDivergence(State memory state, uint256 startCycle)
        internal
        pure
        returns (
            Machine.Hash agreeHash,
            uint256 agreeCycle,
            Machine.Hash finalStateOne,
            Machine.Hash finalStateTwo
        )
    {
        assert(state.currentHeight == 0);
        agreeHash = Machine.Hash.wrap(Tree.Node.unwrap(state.otherParent));
        agreeCycle = state.toCycle(startCycle);

        if (state.runningLeafPosition % 2 == 0) {
            // divergence was set on left leaf
            (finalStateOne, finalStateTwo) = _getDivergenceOnLeftLeaf(state);
        } else {
            // divergence was set on right leaf
            (finalStateOne, finalStateTwo) = _getDivergenceOnRightLeaf(state);
        }
    }

    //
    // Requires
    //
    function requireExist(State memory state) internal pure {
        require(state.exists(), "match does not exist");
    }

    function requireIsFinished(State memory state) internal pure {
        require(state.isFinished(), "match is not finished");
    }

    function requireCanBeFinalized(State memory state) internal pure {
        require(state.canBeFinalized(), "match is not ready to be finalized");
    }

    function requireCanBeAdvanced(State memory state) internal pure {
        require(state.canBeAdvanced(), "match can't be advanced");
    }

    function requireParentHasChildren(
        State memory state,
        Tree.Node leftNode,
        Tree.Node rightNode
    ) internal pure {
        state.otherParent.requireChildren(leftNode, rightNode);
    }

    //
    // Private
    //
    function _goDownLeftTree(
        State storage state,
        Tree.Node newLeftNode,
        Tree.Node newRightNode
    ) internal {
        assert(state.currentHeight > 1);
        state.otherParent = state.leftNode;
        state.leftNode = newLeftNode;
        state.rightNode = newRightNode;

        state.currentHeight--;
    }

    function _goDownRightTree(
        State storage state,
        Tree.Node newLeftNode,
        Tree.Node newRightNode
    ) internal {
        assert(state.currentHeight > 1);
        state.otherParent = state.rightNode;
        state.leftNode = newLeftNode;
        state.rightNode = newRightNode;

        state.currentHeight--;
        state.runningLeafPosition += 1 << state.currentHeight;
    }

    function _setDivergenceOnLeftLeaf(State storage state, Tree.Node leftLeaf)
        internal
        returns (Machine.Hash finalStateOne, Machine.Hash finalStateTwo)
    {
        assert(state.currentHeight == 1);
        state.rightNode = leftLeaf;
        state.currentHeight = 0;

        (finalStateOne, finalStateTwo) = _getDivergenceOnLeftLeaf(state);
    }

    function _setDivergenceOnRightLeaf(State storage state, Tree.Node rightLeaf)
        internal
        returns (Machine.Hash finalStateOne, Machine.Hash finalStateTwo)
    {
        assert(state.currentHeight == 1);
        state.leftNode = rightLeaf;
        state.currentHeight = 0;
        state.runningLeafPosition += 1;

        (finalStateOne, finalStateTwo) = _getDivergenceOnRightLeaf(state);
    }

    function _getDivergenceOnLeftLeaf(State memory state)
        internal
        pure
        returns (Machine.Hash finalStateOne, Machine.Hash finalStateTwo)
    {
        if (state.height % 2 == 0) {
            finalStateOne = state.leftNode.toMachineHash();
            finalStateTwo = state.rightNode.toMachineHash();
        } else {
            finalStateOne = state.rightNode.toMachineHash();
            finalStateTwo = state.leftNode.toMachineHash();
        }
    }

    function _getDivergenceOnRightLeaf(State memory state)
        internal
        pure
        returns (Machine.Hash finalStateOne, Machine.Hash finalStateTwo)
    {
        if (state.height % 2 == 0) {
            finalStateOne = state.rightNode.toMachineHash();
            finalStateTwo = state.leftNode.toMachineHash();
        } else {
            finalStateOne = state.leftNode.toMachineHash();
            finalStateTwo = state.rightNode.toMachineHash();
        }
    }

    function _setAgreeState(State storage state, Machine.Hash initialState)
        internal
    {
        assert(state.currentHeight == 0);
        state.otherParent = Tree.Node.wrap(Machine.Hash.unwrap(initialState));
    }
}

Settings
{
  "remappings": [
    "@openzeppelin-contracts-5.2.0/=dependencies/@openzeppelin-contracts-5.2.0/",
    "forge-std-1.9.6/=dependencies/forge-std-1.9.6/",
    "prt-contracts/=src/",
    "step/=../../machine/step/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true,
  "libraries": {}
}

Contract ABI

API
[{"inputs":[],"name":"ChildTournamentCannotBeEliminated","type":"error"},{"inputs":[],"name":"ChildTournamentMustBeEliminated","type":"error"},{"inputs":[],"name":"ChildTournamentNotFinished","type":"error"},{"inputs":[{"internalType":"Tree.Node","name":"received","type":"bytes32"},{"internalType":"Tree.Node","name":"expected","type":"bytes32"}],"name":"CommitmentMismatch","type":"error"},{"inputs":[],"name":"EliminateByTimeout","type":"error"},{"inputs":[{"internalType":"Machine.Hash","name":"initialState","type":"bytes32"},{"internalType":"Machine.Hash","name":"agreeState","type":"bytes32"}],"name":"IncorrectAgreeState","type":"error"},{"inputs":[{"internalType":"Machine.Hash","name":"contestedFinalStateOne","type":"bytes32"},{"internalType":"Machine.Hash","name":"contestedFinalStateTwo","type":"bytes32"},{"internalType":"Machine.Hash","name":"finalState","type":"bytes32"}],"name":"InvalidContestedFinalState","type":"error"},{"inputs":[{"internalType":"uint64","name":"treeHeight","type":"uint64"},{"internalType":"uint64","name":"siblingsLength","type":"uint64"}],"name":"LengthMismatch","type":"error"},{"inputs":[],"name":"TournamentIsClosed","type":"error"},{"inputs":[],"name":"TournamentIsFinished","type":"error"},{"inputs":[],"name":"WinByTimeout","type":"error"},{"inputs":[{"internalType":"uint256","name":"commitment","type":"uint256"},{"internalType":"Tree.Node","name":"parent","type":"bytes32"},{"internalType":"Tree.Node","name":"left","type":"bytes32"},{"internalType":"Tree.Node","name":"right","type":"bytes32"}],"name":"WrongChildren","type":"error"},{"inputs":[{"internalType":"Tree.Node","name":"commitmentRoot","type":"bytes32"},{"internalType":"Tree.Node","name":"winner","type":"bytes32"}],"name":"WrongTournamentWinner","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"Tree.Node","name":"root","type":"bytes32"}],"name":"commitmentJoined","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"Match.IdHash","name":"","type":"bytes32"},{"indexed":false,"internalType":"Tree.Node","name":"parent","type":"bytes32"},{"indexed":false,"internalType":"Tree.Node","name":"left","type":"bytes32"}],"name":"matchAdvanced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"Tree.Node","name":"one","type":"bytes32"},{"indexed":true,"internalType":"Tree.Node","name":"two","type":"bytes32"},{"indexed":false,"internalType":"Tree.Node","name":"leftOfTwo","type":"bytes32"}],"name":"matchCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"Match.IdHash","name":"","type":"bytes32"}],"name":"matchDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"Match.IdHash","name":"","type":"bytes32"},{"indexed":false,"internalType":"contract NonRootTournament","name":"","type":"address"}],"name":"newInnerTournament","type":"event"},{"inputs":[{"components":[{"internalType":"Tree.Node","name":"commitmentOne","type":"bytes32"},{"internalType":"Tree.Node","name":"commitmentTwo","type":"bytes32"}],"internalType":"struct Match.Id","name":"_matchId","type":"tuple"},{"internalType":"Tree.Node","name":"_leftNode","type":"bytes32"},{"internalType":"Tree.Node","name":"_rightNode","type":"bytes32"},{"internalType":"Tree.Node","name":"_newLeftNode","type":"bytes32"},{"internalType":"Tree.Node","name":"_newRightNode","type":"bytes32"}],"name":"advanceMatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"arbitrationResult","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"Tree.Node","name":"","type":"bytes32"},{"internalType":"Machine.Hash","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"Tree.Node","name":"commitmentOne","type":"bytes32"},{"internalType":"Tree.Node","name":"commitmentTwo","type":"bytes32"}],"internalType":"struct Match.Id","name":"_matchId","type":"tuple"}],"name":"canWinMatchByTimeout","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract NonRootTournament","name":"_childTournament","type":"address"}],"name":"eliminateInnerTournament","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"Tree.Node","name":"commitmentOne","type":"bytes32"},{"internalType":"Tree.Node","name":"commitmentTwo","type":"bytes32"}],"internalType":"struct Match.Id","name":"_matchId","type":"tuple"}],"name":"eliminateMatchByTimeout","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"Tree.Node","name":"_commitmentRoot","type":"bytes32"}],"name":"getCommitment","outputs":[{"components":[{"internalType":"Time.Duration","name":"allowance","type":"uint64"},{"internalType":"Time.Instant","name":"startInstant","type":"uint64"}],"internalType":"struct Clock.State","name":"","type":"tuple"},{"internalType":"Machine.Hash","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Match.IdHash","name":"_matchIdHash","type":"bytes32"}],"name":"getMatch","outputs":[{"components":[{"internalType":"Tree.Node","name":"otherParent","type":"bytes32"},{"internalType":"Tree.Node","name":"leftNode","type":"bytes32"},{"internalType":"Tree.Node","name":"rightNode","type":"bytes32"},{"internalType":"uint256","name":"runningLeafPosition","type":"uint256"},{"internalType":"uint64","name":"currentHeight","type":"uint64"},{"internalType":"uint64","name":"log2step","type":"uint64"},{"internalType":"uint64","name":"height","type":"uint64"}],"internalType":"struct Match.State","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Match.IdHash","name":"_matchIdHash","type":"bytes32"}],"name":"getMatchCycle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isClosed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isFinished","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Machine.Hash","name":"_finalState","type":"bytes32"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"},{"internalType":"Tree.Node","name":"_leftNode","type":"bytes32"},{"internalType":"Tree.Node","name":"_rightNode","type":"bytes32"}],"name":"joinTournament","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"Tree.Node","name":"commitmentOne","type":"bytes32"},{"internalType":"Tree.Node","name":"commitmentTwo","type":"bytes32"}],"internalType":"struct Match.Id","name":"_matchId","type":"tuple"},{"internalType":"Tree.Node","name":"_leftLeaf","type":"bytes32"},{"internalType":"Tree.Node","name":"_rightLeaf","type":"bytes32"},{"internalType":"Machine.Hash","name":"_agreeHash","type":"bytes32"},{"internalType":"bytes32[]","name":"_agreeHashProof","type":"bytes32[]"}],"name":"sealInnerMatchAndCreateInnerTournament","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"timeFinished","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"Time.Instant","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tournamentLevelConstants","outputs":[{"internalType":"uint64","name":"_maxLevel","type":"uint64"},{"internalType":"uint64","name":"_level","type":"uint64"},{"internalType":"uint64","name":"_log2step","type":"uint64"},{"internalType":"uint64","name":"_height","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract NonRootTournament","name":"_childTournament","type":"address"},{"internalType":"Tree.Node","name":"_leftNode","type":"bytes32"},{"internalType":"Tree.Node","name":"_rightNode","type":"bytes32"}],"name":"winInnerTournament","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"Tree.Node","name":"commitmentOne","type":"bytes32"},{"internalType":"Tree.Node","name":"commitmentTwo","type":"bytes32"}],"internalType":"struct Match.Id","name":"_matchId","type":"tuple"},{"internalType":"Tree.Node","name":"_leftNode","type":"bytes32"},{"internalType":"Tree.Node","name":"_rightNode","type":"bytes32"}],"name":"winMatchByTimeout","outputs":[],"stateMutability":"nonpayable","type":"function"}]

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.