Skip to content

Commit 2e0181d

Browse files
committed
emit event on setRespectedGameTypeUpdatedAt, and test wasRespectedGameType as withdrawal finality condition
1 parent 7e520b7 commit 2e0181d

File tree

2 files changed

+92
-5
lines changed

2 files changed

+92
-5
lines changed

packages/contracts-bedrock/src/L1/OptimismPortal2.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ISemver {
482482
// respectedGameTypeUpdatedAt timestamp without modifying this function's signature.
483483
if (_gameType.raw() == type(uint32).max) {
484484
respectedGameTypeUpdatedAt = uint64(block.timestamp);
485+
emit RespectedGameTypeSet(respectedGameType, Timestamp.wrap(respectedGameTypeUpdatedAt));
485486
} else {
486487
respectedGameType = _gameType;
487488
emit RespectedGameTypeSet(_gameType, Timestamp.wrap(respectedGameTypeUpdatedAt));

packages/contracts-bedrock/test/L1/OptimismPortal2.t.sol

Lines changed: 91 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -462,8 +462,9 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
462462
emit RespectedGameTypeSet(_ty, Timestamp.wrap(respectedGameTypeUpdatedAt));
463463
vm.prank(optimismPortal2.guardian());
464464
optimismPortal2.setRespectedGameType(_ty);
465-
465+
// GameType changes, but the timestamp doesn't.
466466
assertEq(optimismPortal2.respectedGameType().raw(), _ty.raw());
467+
assertEq(optimismPortal2.respectedGameTypeUpdatedAt(), respectedGameTypeUpdatedAt);
467468
}
468469

469470
/// @dev Tests that the guardian can set the `respectedGameTypeUpdatedAt` timestamp to current timestamp.
@@ -472,12 +473,15 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
472473
{
473474
_elapsed = uint64(bound(_elapsed, 0, type(uint64).max - uint64(block.timestamp)));
474475
GameType _ty = GameType.wrap(type(uint32).max);
475-
uint64 _timestamp = uint64(block.timestamp) + _elapsed;
476-
vm.warp(_timestamp);
477-
// TODO: event?
476+
uint64 _newRespectedGameTypeUpdatedAt = uint64(block.timestamp) + _elapsed;
477+
GameType _existingGameType = optimismPortal2.respectedGameType();
478+
vm.warp(_newRespectedGameTypeUpdatedAt);
479+
emit RespectedGameTypeSet(_existingGameType, Timestamp.wrap(_newRespectedGameTypeUpdatedAt));
478480
vm.prank(optimismPortal2.guardian());
479481
optimismPortal2.setRespectedGameType(_ty);
480-
assertEq(optimismPortal2.respectedGameTypeUpdatedAt(), _timestamp);
482+
// GameType doesn't change, but the timestamp does.
483+
assertEq(optimismPortal2.respectedGameType().raw(), _existingGameType.raw());
484+
assertEq(optimismPortal2.respectedGameTypeUpdatedAt(), _newRespectedGameTypeUpdatedAt);
481485
}
482486

483487
/// @dev Tests that `proveWithdrawalTransaction` reverts when paused.
@@ -1252,6 +1256,88 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
12521256
assertTrue(optimismPortal2.finalizedWithdrawals(withdrawalHash));
12531257
}
12541258

1259+
/// @dev Tests that `finalizeWithdrawalTransaction` succeeds even if the respected game type is changed.
1260+
function test_finalizeWithdrawalTransaction_wasRespectedGameType_succeeds(
1261+
address _sender,
1262+
address _target,
1263+
uint256 _value,
1264+
uint256 _gasLimit,
1265+
bytes memory _data,
1266+
GameType _newGameType
1267+
)
1268+
external
1269+
{
1270+
vm.assume(
1271+
_target != address(optimismPortal2) // Cannot call the optimism portal or a contract
1272+
&& _target.code.length == 0 // No accounts with code
1273+
&& _target != CONSOLE // The console has no code but behaves like a contract
1274+
&& uint160(_target) > 9 // No precompiles (or zero address)
1275+
);
1276+
1277+
// Bound to prevent changes in respectedGameTypeUpdatedAt
1278+
_newGameType = GameType.wrap(uint32(bound(_newGameType.raw(), 0, type(uint32).max - 1)));
1279+
1280+
// Total ETH supply is currently about 120M ETH.
1281+
uint256 value = bound(_value, 0, 200_000_000 ether);
1282+
vm.deal(address(optimismPortal2), value);
1283+
1284+
uint256 gasLimit = bound(_gasLimit, 0, 50_000_000);
1285+
uint256 nonce = l2ToL1MessagePasser.messageNonce();
1286+
1287+
// Get a withdrawal transaction and mock proof from the differential testing script.
1288+
Types.WithdrawalTransaction memory _tx = Types.WithdrawalTransaction({
1289+
nonce: nonce,
1290+
sender: _sender,
1291+
target: _target,
1292+
value: value,
1293+
gasLimit: gasLimit,
1294+
data: _data
1295+
});
1296+
(
1297+
bytes32 stateRoot,
1298+
bytes32 storageRoot,
1299+
bytes32 outputRoot,
1300+
bytes32 withdrawalHash,
1301+
bytes[] memory withdrawalProof
1302+
) = ffi.getProveWithdrawalTransactionInputs(_tx);
1303+
1304+
// Create the output root proof
1305+
Types.OutputRootProof memory proof = Types.OutputRootProof({
1306+
version: bytes32(uint256(0)),
1307+
stateRoot: stateRoot,
1308+
messagePasserStorageRoot: storageRoot,
1309+
latestBlockhash: bytes32(uint256(0))
1310+
});
1311+
1312+
// Ensure the values returned from ffi are correct
1313+
assertEq(outputRoot, Hashing.hashOutputRootProof(proof));
1314+
assertEq(withdrawalHash, Hashing.hashWithdrawal(_tx));
1315+
1316+
// Setup the dispute game to return the output root
1317+
vm.mockCall(address(game), abi.encodeCall(game.rootClaim, ()), abi.encode(outputRoot));
1318+
1319+
// Prove the withdrawal transaction
1320+
optimismPortal2.proveWithdrawalTransaction(_tx, _proposedGameIndex, proof, withdrawalProof);
1321+
(IDisputeGame _game,) = optimismPortal2.provenWithdrawals(withdrawalHash, address(this));
1322+
assertTrue(_game.rootClaim().raw() != bytes32(0));
1323+
1324+
// Resolve the dispute game
1325+
game.resolveClaim(0, 0);
1326+
game.resolve();
1327+
1328+
// Warp past the finalization period
1329+
vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1);
1330+
1331+
// Change the respectedGameType
1332+
vm.prank(optimismPortal2.guardian());
1333+
optimismPortal2.setRespectedGameType(_newGameType);
1334+
1335+
// Withdrawal transaction still finalizable
1336+
vm.expectCallMinGas(_tx.target, _tx.value, uint64(_tx.gasLimit), _tx.data);
1337+
optimismPortal2.finalizeWithdrawalTransaction(_tx);
1338+
assertTrue(optimismPortal2.finalizedWithdrawals(withdrawalHash));
1339+
}
1340+
12551341
/// @dev Tests that `finalizeWithdrawalTransaction` reverts if the withdrawal's dispute game has been blacklisted.
12561342
function test_finalizeWithdrawalTransaction_blacklisted_reverts() external {
12571343
vm.expectEmit(true, true, true, true);

0 commit comments

Comments
 (0)