Commit 90552788 authored by refcell's avatar refcell Committed by GitHub

fix(ctb): Exact Bond Amounts (#9924)

* fix(ctb): require exact bond amounts

* fix(ctb): precise bond amount tests

* fix(ctb): ci checks

* Semver / DGF strict bonds

* Rename `InsufficientBond` error -> `IncorrectBondAmount`

---------
Co-authored-by: default avatarclabby <ben@clab.by>
parent 786cca3d
This diff is collapsed.
This diff is collapsed.
......@@ -108,12 +108,12 @@
"sourceCodeHash": "0xba941ad1f941f5a4a066182d50634fa9b190085ed82779decef71c019ba963c5"
},
"src/dispute/DisputeGameFactory.sol": {
"initCodeHash": "0x80d749a56c1776930fe0deb5c3c646217716e5875ace99c4d036af0452236476",
"sourceCodeHash": "0xf897c1a845a16cb8b217135a1c7819cdb20b315567066282f5860251e48d3611"
"initCodeHash": "0xdcdf98426bbe8ad7c9112dff7d7560c6cc39970aff9cc18b1a45753528b7b6cb",
"sourceCodeHash": "0x3ac8675f5dbc23ea992b23aa55504c89cf495199570ba420d46fef6c19349322"
},
"src/dispute/FaultDisputeGame.sol": {
"initCodeHash": "0x9dcd4df1dd3e7a09dab46bfe1ebd9376f533cc533f9edce2f01aa754301e25aa",
"sourceCodeHash": "0xbe89df391f9cd4165389a7f6f65af752db13d0e508a1ec8430737aba5b7174dc"
"initCodeHash": "0x047f99f09b4f6fb5b003e47e26af9134448aa026659716231a222a30109e549f",
"sourceCodeHash": "0x1c29d6edfa476ebb2c5cd2981aa8ac6eabcb7ded842dd6829cbaf833e575edad"
},
"src/dispute/weth/DelayedWETH.sol": {
"initCodeHash": "0xf179e4249be6eda22b24ae2b32717f154f35edeb9dee0332aefa6fad3ace4dbe",
......
......@@ -435,7 +435,7 @@
},
{
"inputs": [],
"name": "InsufficientBond",
"name": "IncorrectBondAmount",
"type": "error"
},
{
......
......@@ -187,19 +187,6 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "claimedBondFlag",
"outputs": [
{
"internalType": "uint128",
"name": "claimedBondFlag_",
"type": "uint128"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [],
"name": "createdAt",
......@@ -702,7 +689,7 @@
},
{
"inputs": [],
"name": "InsufficientBond",
"name": "IncorrectBondAmount",
"type": "error"
},
{
......
......@@ -197,19 +197,6 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "claimedBondFlag",
"outputs": [
{
"internalType": "uint128",
"name": "claimedBondFlag_",
"type": "uint128"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [],
"name": "createdAt",
......@@ -717,7 +704,7 @@
},
{
"inputs": [],
"name": "InsufficientBond",
"name": "IncorrectBondAmount",
"type": "error"
},
{
......
......@@ -23,8 +23,8 @@ contract DisputeGameFactory is OwnableUpgradeable, IDisputeGameFactory, ISemver
using ClonesWithImmutableArgs for address;
/// @notice Semantic version.
/// @custom:semver 0.2.0
string public constant version = "0.2.0";
/// @custom:semver 0.3.0
string public constant version = "0.3.0";
/// @inheritdoc IDisputeGameFactory
mapping(GameType => IDisputeGame) public gameImpls;
......@@ -97,7 +97,7 @@ contract DisputeGameFactory is OwnableUpgradeable, IDisputeGameFactory, ISemver
if (address(impl) == address(0)) revert NoImplementation(_gameType);
// If the required initialization bond is not met, revert.
if (msg.value < initBonds[_gameType]) revert InsufficientBond();
if (msg.value != initBonds[_gameType]) revert IncorrectBondAmount();
// Get the hash of the parent block.
bytes32 parentHash = blockhash(block.number - 1);
......
......@@ -91,8 +91,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
OutputRoot public startingOutputRoot;
/// @notice Semantic version.
/// @custom:semver 0.8.1
string public constant version = "0.8.1";
/// @custom:semver 0.9.0
string public constant version = "0.9.0";
/// @param _gameType The type ID of the game.
/// @param _absolutePrestate The absolute prestate of the instruction trace.
......@@ -256,8 +256,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
_verifyExecBisectionRoot(_claim, _challengeIndex, parentPos, _isAttack);
}
// INVARIANT: The `msg.value` must be sufficient to cover the required bond.
if (getRequiredBond(nextPosition) > msg.value) revert InsufficientBond();
// INVARIANT: The `msg.value` must exactly equal the required bond.
if (getRequiredBond(nextPosition) != msg.value) revert IncorrectBondAmount();
// Fetch the grandparent clock, if it exists.
// The grandparent clock should always exist unless the parent is the root claim.
......@@ -645,12 +645,6 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
if (!success) revert BondTransferFailed();
}
/// @notice Returns the flag set in the `bond` field of a `ClaimData` struct to indicate that the bond has been
/// claimed.
function claimedBondFlag() external pure returns (uint128 claimedBondFlag_) {
claimedBondFlag_ = CLAIMED_BOND_FLAG;
}
////////////////////////////////////////////////////////////////
// IMMUTABLE GETTERS //
////////////////////////////////////////////////////////////////
......
......@@ -27,8 +27,8 @@ error UnexpectedRootClaim(Claim rootClaim);
/// @notice Thrown when a dispute game has already been initialized.
error AlreadyInitialized();
/// @notice Thrown when a supplied bond is too low to cover the cost of the interaction.
error InsufficientBond();
/// @notice Thrown when a supplied bond is not equal to the required bond amount to cover the cost of the interaction.
error IncorrectBondAmount();
/// @notice Thrown when a credit claim is attempted for a value of 0.
error NoCreditToClaim();
......
......@@ -72,8 +72,8 @@ contract DisputeGameFactory_Create_Test is DisputeGameFactory_Init {
assertEq(address(proxy).balance, _value);
}
/// @dev Tests that the `create` function reverts when creating a new dispute game with an insufficient bond.
function testFuzz_create_insufficientBond_reverts(
/// @dev Tests that the `create` function reverts when creating a new dispute game with an incorrect bond amount.
function testFuzz_create_incorrectBondAmount_reverts(
uint8 gameType,
Claim rootClaim,
bytes calldata extraData
......@@ -92,7 +92,7 @@ contract DisputeGameFactory_Create_Test is DisputeGameFactory_Init {
disputeGameFactory.setInitBond(lgt, 1 ether);
}
vm.expectRevert(InsufficientBond.selector);
vm.expectRevert(IncorrectBondAmount.selector);
disputeGameFactory.create(gt, rootClaim, extraData);
}
......
......@@ -126,20 +126,30 @@ contract PermissionedDisputeGame_Test is PermissionedDisputeGame_Init {
/// @dev Tests that the challenger can participate in a permissioned dispute game.
function test_participateInGame_challenger_succeeds() public {
vm.startPrank(CHALLENGER, CHALLENGER);
vm.deal(CHALLENGER, MIN_BOND * 3);
gameProxy.attack{ value: MIN_BOND }(0, Claim.wrap(0));
gameProxy.defend{ value: MIN_BOND }(1, Claim.wrap(0));
gameProxy.move{ value: MIN_BOND }(2, Claim.wrap(0), true);
uint256 firstBond = _getRequiredBond(0);
vm.deal(CHALLENGER, firstBond);
gameProxy.attack{ value: firstBond }(0, Claim.wrap(0));
uint256 secondBond = _getRequiredBond(1);
vm.deal(CHALLENGER, secondBond);
gameProxy.defend{ value: secondBond }(1, Claim.wrap(0));
uint256 thirdBond = _getRequiredBond(2);
vm.deal(CHALLENGER, thirdBond);
gameProxy.move{ value: thirdBond }(2, Claim.wrap(0), true);
vm.stopPrank();
}
/// @dev Tests that the proposer can participate in a permissioned dispute game.
function test_participateInGame_proposer_succeeds() public {
vm.startPrank(PROPOSER, PROPOSER);
vm.deal(PROPOSER, MIN_BOND * 3);
gameProxy.attack{ value: MIN_BOND }(0, Claim.wrap(0));
gameProxy.defend{ value: MIN_BOND }(1, Claim.wrap(0));
gameProxy.move{ value: MIN_BOND }(2, Claim.wrap(0), true);
uint256 firstBond = _getRequiredBond(0);
vm.deal(PROPOSER, firstBond);
gameProxy.attack{ value: firstBond }(0, Claim.wrap(0));
uint256 secondBond = _getRequiredBond(1);
vm.deal(PROPOSER, secondBond);
gameProxy.defend{ value: secondBond }(1, Claim.wrap(0));
uint256 thirdBond = _getRequiredBond(2);
vm.deal(PROPOSER, thirdBond);
gameProxy.move{ value: thirdBond }(2, Claim.wrap(0), true);
vm.stopPrank();
}
......@@ -157,6 +167,13 @@ contract PermissionedDisputeGame_Test is PermissionedDisputeGame_Init {
gameProxy.move(2, Claim.wrap(0), true);
vm.stopPrank();
}
/// @dev Helper to get the required bond for the given claim index.
function _getRequiredBond(uint256 _claimIndex) internal view returns (uint256 bond_) {
(,,,,, Position parent,) = gameProxy.claimData(_claimIndex);
Position pos = parent.move(true);
bond_ = gameProxy.getRequiredBond(pos);
}
}
/// @dev Helper to change the VM status byte of a claim.
......
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