Commit 2947c71f authored by clabby's avatar clabby

Add `GameType` to `GameId` type

parent edafea3e
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -17,7 +17,7 @@ AttestationStationTest:test_attest_bulk_succeeds() (gas: 703749)
AttestationStationTest:test_attest_individual_succeeds() (gas: 632087)
AttestationStationTest:test_attest_single_succeeds() (gas: 651325)
BlockOracle_Test:test_checkpointAndLoad_succeeds() (gas: 58341)
BlockOracle_Test:test_load_noBlockHash_reverts() (gas: 12805)
BlockOracle_Test:test_load_noBlockHash_reverts() (gas: 12855)
Bytes_slice_Test:test_slice_acrossMultipleWords_works() (gas: 9413)
Bytes_slice_Test:test_slice_acrossWords_works() (gas: 1430)
Bytes_slice_Test:test_slice_fromNonZeroIdx_works() (gas: 17240)
......@@ -173,7 +173,7 @@ L1CrossDomainMessenger_Test:test_relayMessage_v2_reverts() (gas: 12343)
L1CrossDomainMessenger_Test:test_replayMessage_withValue_reverts() (gas: 33166)
L1CrossDomainMessenger_Test:test_sendMessage_succeeds() (gas: 392870)
L1CrossDomainMessenger_Test:test_sendMessage_twice_succeeds() (gas: 1669046)
L1CrossDomainMessenger_Test:test_xDomainMessageSender_reset_succeeds() (gas: 87043)
L1CrossDomainMessenger_Test:test_xDomainMessageSender_reset_succeeds() (gas: 87094)
L1CrossDomainMessenger_Test:test_xDomainSender_notSet_reverts() (gas: 24253)
L1ERC721Bridge_Test:test_bridgeERC721To_localTokenZeroAddress_reverts() (gas: 62677)
L1ERC721Bridge_Test:test_bridgeERC721To_remoteTokenZeroAddress_reverts() (gas: 37273)
......@@ -217,7 +217,7 @@ L2CrossDomainMessenger_Test:test_relayMessage_toSystemContract_reverts() (gas: 3
L2CrossDomainMessenger_Test:test_relayMessage_v2_reverts() (gas: 11689)
L2CrossDomainMessenger_Test:test_sendMessage_succeeds() (gas: 123768)
L2CrossDomainMessenger_Test:test_sendMessage_twice_succeeds() (gas: 135434)
L2CrossDomainMessenger_Test:test_xDomainMessageSender_reset_succeeds() (gas: 48422)
L2CrossDomainMessenger_Test:test_xDomainMessageSender_reset_succeeds() (gas: 48472)
L2CrossDomainMessenger_Test:test_xDomainSender_senderNotSet_reverts() (gas: 10590)
L2ERC721Bridge_Test:test_bridgeERC721To_localTokenZeroAddress_reverts() (gas: 31428)
L2ERC721Bridge_Test:test_bridgeERC721To_remoteTokenZeroAddress_reverts() (gas: 26826)
......@@ -250,12 +250,12 @@ L2OutputOracle_deleteOutputs_Test:test_deleteL2Outputs_ifNotChallenger_reverts()
L2OutputOracle_deleteOutputs_Test:test_deleteL2Outputs_nonExistent_reverts() (gas: 111651)
L2OutputOracle_deleteOutputs_Test:test_deleteOutputs_multipleOutputs_succeeds() (gas: 307411)
L2OutputOracle_deleteOutputs_Test:test_deleteOutputs_singleOutput_succeeds() (gas: 185564)
L2OutputOracle_getter_Test:test_computeL2Timestamp_succeeds() (gas: 37341)
L2OutputOracle_getter_Test:test_computeL2Timestamp_succeeds() (gas: 37391)
L2OutputOracle_getter_Test:test_getL2OutputIndexAfter_multipleOutputsExist_succeeds() (gas: 269700)
L2OutputOracle_getter_Test:test_getL2OutputIndexAfter_noOutputsExis_reverts() (gas: 17892)
L2OutputOracle_getter_Test:test_getL2OutputIndexAfter_previousBlock_succeeds() (gas: 98188)
L2OutputOracle_getter_Test:test_getL2OutputIndexAfter_sameBlock_succeeds() (gas: 98096)
L2OutputOracle_getter_Test:test_getL2Output_succeeds() (gas: 103735)
L2OutputOracle_getter_Test:test_getL2Output_succeeds() (gas: 103786)
L2OutputOracle_getter_Test:test_latestBlockNumber_succeeds() (gas: 99129)
L2OutputOracle_getter_Test:test_nextBlockNumber_succeeds() (gas: 17447)
L2OutputOracle_proposeL2Output_Test:test_proposeL2Output_emptyOutput_reverts() (gas: 28812)
......@@ -463,7 +463,7 @@ OptimismPortal_Test:test_depositTransaction_withEthValueAndContractContractCreat
OptimismPortal_Test:test_depositTransaction_withEthValueAndEOAContractCreation_succeeds() (gas: 75929)
OptimismPortal_Test:test_depositTransaction_withEthValueFromContract_succeeds() (gas: 83476)
OptimismPortal_Test:test_depositTransaction_withEthValueFromEOA_succeeds() (gas: 84069)
OptimismPortal_Test:test_isOutputFinalized_succeeds() (gas: 126749)
OptimismPortal_Test:test_isOutputFinalized_succeeds() (gas: 126800)
OptimismPortal_Test:test_minimumGasLimit_succeeds() (gas: 17430)
OptimismPortal_Test:test_pause_onlyGuardian_reverts() (gas: 24487)
OptimismPortal_Test:test_pause_succeeds() (gas: 27344)
......@@ -523,7 +523,7 @@ PreimageOracle_Test:test_loadKeccak256PreimagePart_outOfBoundsOffset_reverts() (
PreimageOracle_Test:test_loadKeccak256PreimagePart_succeeds() (gas: 76098)
PreimageOracle_Test:test_loadLocalData_onePart_succeeds() (gas: 75840)
PreimageOracle_Test:test_loadLocalData_outOfBoundsOffset_reverts() (gas: 8803)
ProxyAdmin_Test:test_chugsplashChangeProxyAdmin_succeeds() (gas: 35586)
ProxyAdmin_Test:test_chugsplashChangeProxyAdmin_succeeds() (gas: 35635)
ProxyAdmin_Test:test_chugsplashGetProxyAdmin_succeeds() (gas: 15675)
ProxyAdmin_Test:test_chugsplashGetProxyImplementation_succeeds() (gas: 51084)
ProxyAdmin_Test:test_chugsplashUpgradeAndCall_succeeds() (gas: 82311)
......@@ -533,7 +533,7 @@ ProxyAdmin_Test:test_delegateResolvedGetProxyAdmin_succeeds() (gas: 17691)
ProxyAdmin_Test:test_delegateResolvedGetProxyImplementation_succeeds() (gas: 62028)
ProxyAdmin_Test:test_delegateResolvedUpgradeAndCall_succeeds() (gas: 98039)
ProxyAdmin_Test:test_delegateResolvedUpgrade_succeeds() (gas: 58482)
ProxyAdmin_Test:test_erc1967ChangeProxyAdmin_succeeds() (gas: 33812)
ProxyAdmin_Test:test_erc1967ChangeProxyAdmin_succeeds() (gas: 33861)
ProxyAdmin_Test:test_erc1967GetProxyAdmin_succeeds() (gas: 15616)
ProxyAdmin_Test:test_erc1967GetProxyImplementation_succeeds() (gas: 52071)
ProxyAdmin_Test:test_erc1967UpgradeAndCall_succeeds() (gas: 78969)
......@@ -551,9 +551,9 @@ Proxy_Test:test_implementationKey_succeeds() (gas: 20909)
Proxy_Test:test_implementation_isZeroAddress_reverts() (gas: 47626)
Proxy_Test:test_implementation_zeroAddressCaller_succeeds() (gas: 14752)
Proxy_Test:test_ownerKey_succeeds() (gas: 19059)
Proxy_Test:test_ownerProxyCall_notAdmin_succeeds() (gas: 34615)
Proxy_Test:test_ownerProxyCall_notAdmin_succeeds() (gas: 34665)
Proxy_Test:test_proxyCallToImp_notAdmin_succeeds() (gas: 30008)
Proxy_Test:test_upgradeToAndCall_functionDoesNotExist_reverts() (gas: 104565)
Proxy_Test:test_upgradeToAndCall_functionDoesNotExist_reverts() (gas: 104765)
Proxy_Test:test_upgradeToAndCall_isPayable_succeeds() (gas: 53742)
Proxy_Test:test_upgradeToAndCall_succeeds() (gas: 125190)
Proxy_Test:test_upgradeTo_clashingFunctionSignatures_succeeds() (gas: 101359)
......@@ -646,8 +646,8 @@ StandardBridge_Stateless_Test:test_isOptimismMintableERC20_succeeds() (gas: 3307
SystemConfig_Initialize_Test:test_initialize_events_succeeds() (gas: 72059)
SystemConfig_Initialize_Test:test_initialize_startBlockOverride_succeeds() (gas: 65240)
SystemConfig_Initialize_Test:test_initialize_values_succeeds() (gas: 64946)
SystemConfig_Initialize_TestFail:test_initialize_lowGasLimit_reverts() (gas: 55653)
SystemConfig_Initialize_TestFail:test_initialize_startBlock_reverts() (gas: 78350)
SystemConfig_Initialize_TestFail:test_initialize_lowGasLimit_reverts() (gas: 55730)
SystemConfig_Initialize_TestFail:test_initialize_startBlock_reverts() (gas: 78427)
SystemConfig_Setters_TestFail:test_setBatcherHash_notOwner_reverts() (gas: 15607)
SystemConfig_Setters_TestFail:test_setGasConfig_notOwner_reverts() (gas: 15577)
SystemConfig_Setters_TestFail:test_setGasLimit_notOwner_reverts() (gas: 15676)
......@@ -658,9 +658,9 @@ SystemConfig_Setters_TestFail:test_setResourceConfig_notOwner_reverts() (gas: 16
SystemConfig_Setters_TestFail:test_setResourceConfig_zeroDenominator_reverts() (gas: 18578)
SystemConfig_Setters_TestFail:test_setUnsafeBlockSigner_notOwner_reverts() (gas: 15590)
TransactorTest:test_call_succeeds() (gas: 26709)
TransactorTest:test_call_unauthorized_reverts() (gas: 16543)
TransactorTest:test_call_unauthorized_reverts() (gas: 16640)
TransactorTest:test_constructor_succeeds() (gas: 9739)
TransactorTest:test_delegateCall_succeeds() (gas: 20909)
TransactorTest:test_delegateCall_unauthorized_reverts() (gas: 16550)
TransactorTest:test_delegateCall_unauthorized_reverts() (gas: 16647)
TransferOnionTest:test_constructor_succeeds() (gas: 564855)
TransferOnionTest:test_unwrap_succeeds() (gas: 724955)
\ No newline at end of file
......@@ -8,6 +8,8 @@ import { Semver } from "src/universal/Semver.sol";
import { IDisputeGame } from "./interfaces/IDisputeGame.sol";
import { IDisputeGameFactory } from "./interfaces/IDisputeGameFactory.sol";
import { LibGameId } from "src/dispute/lib/LibGameId.sol";
import "src/libraries/DisputeTypes.sol";
import "src/libraries/DisputeErrors.sol";
......@@ -35,7 +37,7 @@ contract DisputeGameFactory is OwnableUpgradeable, IDisputeGameFactory, Semver {
GameId[] internal _disputeGameList;
/// @notice constructs a new DisputeGameFactory contract.
constructor() OwnableUpgradeable() Semver(0, 0, 4) {
constructor() OwnableUpgradeable() Semver(0, 0, 5) {
initialize(address(0));
}
......@@ -59,61 +61,63 @@ contract DisputeGameFactory is OwnableUpgradeable, IDisputeGameFactory, Semver {
)
external
view
returns (IDisputeGame proxy_, uint256 timestamp_)
returns (IDisputeGame proxy_, Timestamp timestamp_)
{
Hash uuid = getGameUUID(_gameType, _rootClaim, _extraData);
GameId slot = _disputeGames[uuid];
(address addr, uint256 timestamp) = _unpackSlot(slot);
proxy_ = IDisputeGame(addr);
timestamp_ = timestamp;
(, timestamp_, proxy_) = _disputeGames[uuid].unpack();
}
/// @inheritdoc IDisputeGameFactory
function gameAtIndex(uint256 _index) external view returns (IDisputeGame proxy_, uint256 timestamp_) {
GameId slot = _disputeGameList[_index];
(address addr, uint256 timestamp) = _unpackSlot(slot);
proxy_ = IDisputeGame(addr);
timestamp_ = timestamp;
function gameAtIndex(uint256 _index) external view returns (IDisputeGame proxy_, Timestamp timestamp_) {
(, timestamp_, proxy_) = _disputeGameList[_index].unpack();
}
/// @inheritdoc IDisputeGameFactory
function create(
GameType gameType,
Claim rootClaim,
bytes calldata extraData
GameType _gameType,
Claim _rootClaim,
bytes calldata _extraData
)
external
returns (IDisputeGame proxy)
{
// Grab the implementation contract for the given `GameType`.
IDisputeGame impl = gameImpls[gameType];
IDisputeGame impl = gameImpls[_gameType];
// If there is no implementation to clone for the given `GameType`, revert.
if (address(impl) == address(0)) revert NoImplementation(gameType);
if (address(impl) == address(0)) revert NoImplementation(_gameType);
// Clone the implementation contract and initialize it with the given parameters.
proxy = IDisputeGame(address(impl).clone(abi.encodePacked(rootClaim, extraData)));
proxy = IDisputeGame(address(impl).clone(abi.encodePacked(_rootClaim, _extraData)));
proxy.initialize();
// Compute the unique identifier for the dispute game.
Hash uuid = getGameUUID(gameType, rootClaim, extraData);
Hash uuid = getGameUUID(_gameType, _rootClaim, _extraData);
// If a dispute game with the same UUID already exists, revert.
if (GameId.unwrap(_disputeGames[uuid]) != bytes32(0)) revert GameAlreadyExists(uuid);
GameId slot = _packSlot(address(proxy), block.timestamp);
GameId id = LibGameId.pack(_gameType, Timestamp.wrap(uint64(block.timestamp)), proxy);
// Store the dispute game in the mapping & emit the `DisputeGameCreated` event.
_disputeGames[uuid] = slot;
_disputeGameList.push(slot);
emit DisputeGameCreated(address(proxy), gameType, rootClaim);
// Store the dispute game id in the mapping & emit the `DisputeGameCreated` event.
_disputeGames[uuid] = id;
_disputeGameList.push(id);
emit DisputeGameCreated(address(proxy), _gameType, _rootClaim);
}
/// @inheritdoc IDisputeGameFactory
function getGameUUID(GameType gameType, Claim rootClaim, bytes memory extraData) public pure returns (Hash _uuid) {
function getGameUUID(
GameType _gameType,
Claim _rootClaim,
bytes memory _extraData
)
public
pure
returns (Hash _uuid)
{
assembly {
// Grab the offsets of the other memory locations we will need to temporarily overwrite.
let gameTypeOffset := sub(extraData, 0x60)
let gameTypeOffset := sub(_extraData, 0x60)
let rootClaimOffset := add(gameTypeOffset, 0x20)
let pointerOffset := add(rootClaimOffset, 0x20)
......@@ -124,13 +128,13 @@ contract DisputeGameFactory is OwnableUpgradeable, IDisputeGameFactory, Semver {
let tempC := mload(pointerOffset)
// Overwrite the memory with the data we want to hash
mstore(gameTypeOffset, gameType)
mstore(rootClaimOffset, rootClaim)
mstore(gameTypeOffset, _gameType)
mstore(rootClaimOffset, _rootClaim)
mstore(pointerOffset, 0x60)
// Compute the length of the memory to hash
// `0x60 + 0x20 + extraData.length` rounded to the *next* multiple of 32.
let hashLen := and(add(mload(extraData), 0x9F), not(0x1F))
let hashLen := and(add(mload(_extraData), 0x9F), not(0x1F))
// Hash the memory to produce the UUID digest
_uuid := keccak256(gameTypeOffset, hashLen)
......@@ -143,24 +147,8 @@ contract DisputeGameFactory is OwnableUpgradeable, IDisputeGameFactory, Semver {
}
/// @inheritdoc IDisputeGameFactory
function setImplementation(GameType gameType, IDisputeGame impl) external onlyOwner {
gameImpls[gameType] = impl;
emit ImplementationSet(address(impl), gameType);
}
/// @dev Packs an address and a uint256 into a single bytes32 slot. This
/// is only safe for up to uint96 values.
function _packSlot(address _addr, uint256 _num) internal pure returns (GameId slot_) {
assembly {
slot_ := or(shl(0xa0, _num), _addr)
}
}
/// @dev Unpacks an address and a uint256 from a single bytes32 slot.
function _unpackSlot(GameId _slot) internal pure returns (address addr_, uint256 num_) {
assembly {
addr_ := and(_slot, 0xffffffffffffffffffffffffffffffffffffffff)
num_ := shr(0xa0, _slot)
}
function setImplementation(GameType _gameType, IDisputeGame _impl) external onlyOwner {
gameImpls[_gameType] = _impl;
emit ImplementationSet(address(_impl), _gameType);
}
}
......@@ -39,7 +39,7 @@ interface IDisputeGameFactory {
)
external
view
returns (IDisputeGame _proxy, uint256 _timestamp);
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.
......@@ -47,7 +47,7 @@ interface IDisputeGameFactory {
/// @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 gameAtIndex(uint256 _index) external view returns (IDisputeGame _proxy, uint256 _timestamp);
function gameAtIndex(uint256 _index) external view returns (IDisputeGame _proxy, Timestamp _timestamp);
/// @notice `gameImpls` is a mapping that maps `GameType`s to their respective
/// `IDisputeGame` implementations.
......
// 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(248, _gameType), shl(184, _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(248, _gameId)
timestamp_ := shr(184, and(_gameId, not(shl(248, 0xff))))
gameProxy_ := and(_gameId, 0xffffffffffffffffffffffffffffffffffffffff)
}
}
}
......@@ -4,10 +4,12 @@ pragma solidity ^0.8.15;
import { LibHashing } from "../dispute/lib/LibHashing.sol";
import { LibPosition } from "../dispute/lib/LibPosition.sol";
import { LibClock } from "../dispute/lib/LibClock.sol";
import { LibGameId } from "../dispute/lib/LibGameId.sol";
using LibHashing for Claim global;
using LibPosition for Position global;
using LibClock for Clock global;
using LibGameId for GameId global;
/// @notice A custom type for a generic hash.
type Hash is bytes32;
......@@ -31,12 +33,13 @@ type Duration is uint64;
/// @notice A `GameId` represents a packed 12 byte timestamp and a 20 byte address.
/// @dev The packed layout of this type is as follows:
/// ┌────────────┬────────────────┐
/// │ Bits │ Value │
/// ├────────────┼────────────────┤
/// │ [0, 96) │ Timestamp │
/// │ [96, 256) │ Address │
/// └────────────┴────────────────┘
/// ┌───────────┬───────────┐
/// │ 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`
......
......@@ -51,16 +51,16 @@ contract DisputeGameFactory_Create_Test is DisputeGameFactory_Init {
emit DisputeGameCreated(address(0), gt, rootClaim);
IDisputeGame proxy = factory.create(gt, rootClaim, extraData);
(IDisputeGame game, uint256 timestamp) = factory.games(gt, rootClaim, extraData);
(IDisputeGame game, Timestamp timestamp) = factory.games(gt, rootClaim, extraData);
// Ensure that the dispute game was assigned to the `disputeGames` mapping.
assertEq(address(game), address(proxy));
assertEq(timestamp, block.timestamp);
assertEq(Timestamp.unwrap(timestamp), block.timestamp);
assertEq(factory.gameCount(), 1);
(IDisputeGame game2, uint256 timestamp2) = factory.gameAtIndex(0);
(IDisputeGame game2, Timestamp timestamp2) = factory.gameAtIndex(0);
assertEq(address(game2), address(proxy));
assertEq(timestamp2, block.timestamp);
assertEq(Timestamp.unwrap(timestamp2), block.timestamp);
}
/// @dev Tests that the `create` function reverts when there is no implementation
......@@ -88,10 +88,10 @@ contract DisputeGameFactory_Create_Test is DisputeGameFactory_Init {
emit DisputeGameCreated(address(0), gt, rootClaim);
IDisputeGame proxy = factory.create(gt, rootClaim, extraData);
(IDisputeGame game, uint256 timestamp) = factory.games(gt, rootClaim, extraData);
(IDisputeGame game, Timestamp timestamp) = factory.games(gt, rootClaim, extraData);
// Ensure that the dispute game was assigned to the `disputeGames` mapping.
assertEq(address(game), address(proxy));
assertEq(timestamp, block.timestamp);
assertEq(Timestamp.unwrap(timestamp), block.timestamp);
// Ensure that the `create` function reverts when called with parameters that would result in the same UUID.
vm.expectRevert(
......@@ -161,37 +161,6 @@ contract DisputeGameFactory_TransferOwnership_Test is DisputeGameFactory_Init {
}
}
/// @title PackingTester
/// @notice Exposes the internal packing functions so that they can be fuzzed
/// in a roundtrip manner.
contract PackingTester is DisputeGameFactory {
function packSlot(address _addr, uint256 _num) external pure returns (GameId) {
return _packSlot(_addr, _num);
}
function unpackSlot(GameId _slot) external pure returns (address, uint256) {
return _unpackSlot(_slot);
}
}
/// @title DisputeGameFactory_PackSlot_Test
/// @notice Fuzzes the PackingTester contract
contract DisputeGameFactory_PackSlot_Test is Test {
PackingTester tester;
function setUp() public {
tester = new PackingTester();
}
/// @dev Tests that the `packSlot` and `unpackSlot` functions roundtrip correctly.
function testFuzz_packSlot_succeeds(address _addr, uint96 _num) public {
GameId slot = tester.packSlot(_addr, uint256(_num));
(address addr, uint256 num) = tester.unpackSlot(slot);
assertEq(addr, _addr);
assertEq(num, _num);
}
}
/// @dev A fake clone used for testing the `DisputeGameFactory` contract's `create` function.
contract FakeClone {
function initialize() external {
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import { Test } from "forge-std/Test.sol";
import { LibGameId } from "src/dispute/lib/LibGameId.sol";
import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol";
import "src/libraries/DisputeTypes.sol";
contract LibGameId_Test is Test {
/// @dev Tests that a round trip of packing and unpacking a GameId maintains the same values.
function testFuzz_gameId_roundTrip_succeeds(
GameType _gameType,
Timestamp _timestamp,
IDisputeGame _gameProxy
)
public
{
GameId gameId = LibGameId.pack(_gameType, _timestamp, _gameProxy);
(GameType gameType_, Timestamp timestamp_, IDisputeGame gameProxy_) = LibGameId.unpack(gameId);
assertEq(GameType.unwrap(gameType_), GameType.unwrap(_gameType));
assertEq(Timestamp.unwrap(timestamp_), Timestamp.unwrap(_timestamp));
assertEq(address(gameProxy_), address(_gameProxy));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment