Commit efea631c authored by OptimismBot's avatar OptimismBot Committed by GitHub

Merge pull request #5939 from ethereum-optimism/feat/pops-cleanup

feat(ctb): Pull in relevant PoPs work
parents daaf917b 0a9342d5
This diff is collapsed.
......@@ -248,3 +248,21 @@
| Name | Type | Slot | Offset | Bytes | Contract |
|------|------|------|--------|-------|----------|
=======================
➡ contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory
=======================
| Name | Type | Slot | Offset | Bytes | Contract |
|--------------|-------------------------------------------------|------|--------|-------|-------------------------------------------------------------|
| _owner | address | 0 | 0 | 20 | contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory |
| gameImpls | mapping(enum GameType => contract IDisputeGame) | 1 | 0 | 32 | contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory |
| disputeGames | mapping(Hash => contract IDisputeGame) | 2 | 0 | 32 | contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory |
=======================
➡ contracts/dispute/BondManager.sol:BondManager
=======================
| Name | Type | Slot | Offset | Bytes | Contract |
|-------|---------------------------------------------|------|--------|-------|-----------------------------------------------|
| bonds | mapping(bytes32 => struct BondManager.Bond) | 0 | 0 | 32 | contracts/dispute/BondManager.sol:BondManager |
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import { GameType } from "../libraries/DisputeTypes.sol";
import { GameStatus } from "../libraries/DisputeTypes.sol";
import "../libraries/DisputeTypes.sol";
import { SafeCall } from "../libraries/SafeCall.sol";
import { IDisputeGame } from "./IDisputeGame.sol";
import { IDisputeGameFactory } from "./IDisputeGameFactory.sol";
import { IDisputeGame } from "./interfaces/IDisputeGame.sol";
import { IDisputeGameFactory } from "./interfaces/IDisputeGameFactory.sol";
import { IBondManager } from "./interfaces/IBondManager.sol";
/**
* @title BondManager
* @notice The Bond Manager serves as an escrow for permissionless output proposal bonds.
*/
contract BondManager {
contract BondManager is IBondManager {
/**
* @notice The Bond Type
*/
struct Bond {
address owner;
uint256 expiration;
bytes32 id;
uint256 amount;
uint128 expiration;
uint128 amount;
}
/**
* @notice Mapping from bondId to bond.
*/
mapping(bytes32 => Bond) public bonds;
/**
* @notice BondPosted is emitted when a bond is posted.
* @param bondId is the id of the bond.
* @param owner is the address that owns the bond.
* @param expiration is the time at which the bond expires.
* @param amount is the amount of the bond.
*/
event BondPosted(bytes32 bondId, address owner, uint256 expiration, uint256 amount);
/**
* @notice BondSeized is emitted when a bond is seized.
* @param bondId is the id of the bond.
* @param owner is the address that owns the bond.
* @param seizer is the address that seized the bond.
* @param amount is the amount of the bond.
*/
event BondSeized(bytes32 bondId, address owner, address seizer, uint256 amount);
/**
* @notice BondReclaimed is emitted when a bond is reclaimed by the owner.
* @param bondId is the id of the bond.
* @param claiment is the address that reclaimed the bond.
* @param amount is the amount of the bond.
*/
event BondReclaimed(bytes32 bondId, address claiment, uint256 amount);
/**
* @notice The permissioned dispute game factory.
* @dev Used to verify the status of bonds.
......@@ -67,6 +37,11 @@ contract BondManager {
*/
uint256 private constant TRANSFER_GAS = 30_000;
/**
* @notice Mapping from bondId to bond.
*/
mapping(bytes32 => Bond) public bonds;
/**
* @notice Instantiates the bond maanger with the registered dispute game factory.
* @param _disputeGameFactory is the dispute game factory.
......@@ -76,37 +51,30 @@ contract BondManager {
}
/**
* @notice Post a bond with a given id and owner.
* @dev This function will revert if the provided bondId is already in use.
* @param _bondId is the id of the bond.
* @param _bondOwner is the address that owns the bond.
* @param _minClaimHold is the minimum amount of time the owner
* must wait before reclaiming their bond.
* @inheritdoc IBondManager
*/
function post(
bytes32 _bondId,
address _bondOwner,
uint256 _minClaimHold
uint128 _minClaimHold
) external payable {
require(bonds[_bondId].owner == address(0), "BondManager: BondId already posted.");
require(_bondOwner != address(0), "BondManager: Owner cannot be the zero address.");
require(msg.value > 0, "BondManager: Value must be non-zero.");
uint256 expiration = _minClaimHold + block.timestamp;
uint128 expiration = uint128(_minClaimHold + block.timestamp);
bonds[_bondId] = Bond({
owner: _bondOwner,
expiration: expiration,
id: _bondId,
amount: msg.value
expiration: expiration,
amount: uint128(msg.value)
});
emit BondPosted(_bondId, _bondOwner, expiration, msg.value);
}
/**
* @notice Seizes the bond with the given id.
* @dev This function will revert if there is no bond at the given id.
* @param _bondId is the id of the bond.
* @inheritdoc IBondManager
*/
function seize(bytes32 _bondId) external {
Bond memory b = bonds[_bondId];
......@@ -131,10 +99,7 @@ contract BondManager {
}
/**
* @notice Seizes the bond with the given id and distributes it to recipients.
* @dev This function will revert if there is no bond at the given id.
* @param _bondId is the id of the bond.
* @param _claimRecipients is a set of addresses to split the bond amongst.
* @inheritdoc IBondManager
*/
function seizeAndSplit(bytes32 _bondId, address[] calldata _claimRecipients) external {
Bond memory b = bonds[_bondId];
......@@ -168,9 +133,7 @@ contract BondManager {
}
/**
* @notice Reclaims the bond of the bond owner.
* @dev This function will revert if there is no bond at the given id.
* @param _bondId is the id of the bond.
* @inheritdoc IBondManager
*/
function reclaim(bytes32 _bondId) external {
Bond memory b = bonds[_bondId];
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import "../libraries/DisputeTypes.sol";
import "../libraries/DisputeErrors.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { ClonesWithImmutableArgs } from "@cwia/ClonesWithImmutableArgs.sol";
import { Claim } from "../libraries/DisputeTypes.sol";
import { Hash } from "../libraries/DisputeTypes.sol";
import { GameType } from "../libraries/DisputeTypes.sol";
import { NoImplementation } from "../libraries/DisputeErrors.sol";
import { GameAlreadyExists } from "../libraries/DisputeErrors.sol";
import { IDisputeGame } from "./IDisputeGame.sol";
import { IDisputeGameFactory } from "./IDisputeGameFactory.sol";
import { IDisputeGame } from "./interfaces/IDisputeGame.sol";
import { IDisputeGameFactory } from "./interfaces/IDisputeGameFactory.sol";
/**
* @title DisputeGameFactory
......@@ -25,7 +21,7 @@ contract DisputeGameFactory is Ownable, IDisputeGameFactory {
using ClonesWithImmutableArgs for address;
/**
* @notice Mapping of `GameType`s to their respective `IDisputeGame` implementations.
* @inheritdoc IDisputeGameFactory
*/
mapping(GameType => IDisputeGame) public gameImpls;
......@@ -45,16 +41,7 @@ contract DisputeGameFactory is Ownable, IDisputeGameFactory {
}
/**
* @notice Retrieves the hash of `gameType . rootClaim . extraData`
* to the deployed `DisputeGame` clone.
* @dev Note: `.` denotes concatenation.
* @param gameType The type of the DisputeGame.
* Used to decide the implementation to clone.
* @param rootClaim The root claim of the DisputeGame.
* @param extraData Any extra data that should be provided to the
* created dispute game.
* @return _proxy The clone of the `DisputeGame` created with the
* given parameters. `address(0)` if nonexistent.
* @inheritdoc IDisputeGameFactory
*/
function games(
GameType gameType,
......@@ -65,15 +52,7 @@ contract DisputeGameFactory is Ownable, IDisputeGameFactory {
}
/**
* @notice Creates a new DisputeGame proxy contract.
* @notice If a dispute game with the given parameters already exists,
* it will be returned.
* @param gameType The type of the DisputeGame.
* Used to decide the proxy implementation.
* @param rootClaim The root claim of the DisputeGame.
* @param extraData Any extra data that should be provided
* to the created dispute game.
* @return proxy The clone of the `DisputeGame`.
* @inheritdoc IDisputeGameFactory
*/
function create(
GameType gameType,
......@@ -89,8 +68,7 @@ contract DisputeGameFactory is Ownable, IDisputeGameFactory {
}
// Clone the implementation contract and initialize it with the given parameters.
bytes memory data = abi.encodePacked(rootClaim, extraData);
proxy = IDisputeGame(address(impl).clone(data));
proxy = IDisputeGame(address(impl).clone(abi.encodePacked(rootClaim, extraData)));
proxy.initialize();
// Compute the unique identifier for the dispute game.
......@@ -107,23 +85,7 @@ contract DisputeGameFactory is Ownable, IDisputeGameFactory {
}
/**
* @notice Sets the implementation contract for a specific `GameType`.
* @param gameType The type of the DisputeGame.
* @param impl The implementation contract for the given `GameType`.
*/
function setImplementation(GameType gameType, IDisputeGame impl) external onlyOwner {
gameImpls[gameType] = impl;
emit ImplementationSet(address(impl), gameType);
}
/**
* @notice Returns a unique identifier for the given dispute game parameters.
* @dev Hashes the concatenation of `gameType . rootClaim . extraData`
* without expanding memory.
* @param gameType The type of the DisputeGame.
* @param rootClaim The root claim of the DisputeGame.
* @param extraData Any extra data that should be provided to the created dispute game.
* @return _uuid The unique identifier for the given dispute game parameters.
* @inheritdoc IDisputeGameFactory
*/
function getGameUUID(
GameType gameType,
......@@ -160,4 +122,12 @@ contract DisputeGameFactory is Ownable, IDisputeGameFactory {
mstore(pointerOffset, tempC)
}
}
/**
* @inheritdoc IDisputeGameFactory
*/
function setImplementation(GameType gameType, IDisputeGame impl) external onlyOwner {
gameImpls[gameType] = impl;
emit ImplementationSet(address(impl), gameType);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import { IDisputeGame } from "./IDisputeGame.sol";
/**
* @title IAttestationDisputeGame
* @notice The interface for an attestation-based DisputeGame meant to contest output
* proposals in Optimism's `L2OutputOracle` contract.
*/
interface IAttestationDisputeGame is IDisputeGame {
/**
* @notice A mapping of addresses from the `signerSet` to booleans signifying whether
* or not they have authorized the `rootClaim` to be invalidated.
* @param challenger The address to check for authorization.
* @return _challenged Whether or not the `challenger` has challenged the `rootClaim`.
*/
function challenges(address challenger) external view returns (bool _challenged);
/**
* @notice The signer set consists of authorized public keys that may challenge
* the `rootClaim`.
* @param addr The address to check for authorization.
* @return _isAuthorized Whether or not the `addr` is part of the signer set.
*/
function signerSet(address addr) external view returns (bool _isAuthorized);
/**
* @notice The amount of signatures required to successfully challenge the `rootClaim`
* output proposal. Once this threshold is met by members of the `signerSet`
* calling `challenge`, the game will be resolved to `CHALLENGER_WINS`.
* @custom:invariant The `signatureThreshold` may never be greater than the length
* of the `signerSet`.
* @return _signatureThreshold The amount of signatures required to successfully
* challenge the `rootClaim` output proposal.
*/
function frozenSignatureThreshold() external view returns (uint256 _signatureThreshold);
/**
* @notice Returns the L2 Block Number that the `rootClaim` commits to.
* Exists within the `extraData`.
* @return _l2BlockNumber The L2 Block Number that the `rootClaim` commits to.
*/
function l2BlockNumber() external view returns (uint256 _l2BlockNumber);
/**
* @notice Challenge the `rootClaim`.
* @dev - If the `ecrecover`ed address that created the signature is not a part of
* the signer set returned by `signerSet`, this function should revert.
* - If the `ecrecover`ed address that created the signature is not the
* msg.sender, this function should revert.
* - If the signature provided is the signature that breaches the signature
* threshold, the function should call the `resolve` function to resolve
* the game as `CHALLENGER_WINS`.
* - When the game resolves, the bond attached to the root claim should be
* distributed among the signers who participated in challenging the
* invalid claim.
* @param signature An EIP-712 signature committing to the `rootClaim` and
* `l2BlockNumber` (within the `extraData`) from a key that exists
* within the `signerSet`.
*/
function challenge(bytes calldata signature) external;
}
......@@ -6,6 +6,32 @@ pragma solidity ^0.8.15;
* @notice The Bond Manager holds ether posted as a bond for a bond id.
*/
interface IBondManager {
/**
* @notice BondPosted is emitted when a bond is posted.
* @param bondId is the id of the bond.
* @param owner is the address that owns the bond.
* @param expiration is the time at which the bond expires.
* @param amount is the amount of the bond.
*/
event BondPosted(bytes32 bondId, address owner, uint256 expiration, uint256 amount);
/**
* @notice BondSeized is emitted when a bond is seized.
* @param bondId is the id of the bond.
* @param owner is the address that owns the bond.
* @param seizer is the address that seized the bond.
* @param amount is the amount of the bond.
*/
event BondSeized(bytes32 bondId, address owner, address seizer, uint256 amount);
/**
* @notice BondReclaimed is emitted when a bond is reclaimed by the owner.
* @param bondId is the id of the bond.
* @param claiment is the address that reclaimed the bond.
* @param amount is the amount of the bond.
*/
event BondReclaimed(bytes32 bondId, address claiment, uint256 amount);
/**
* @notice Post a bond with a given id and owner.
* @dev This function will revert if the provided bondId is already in use.
......@@ -17,7 +43,7 @@ interface IBondManager {
function post(
bytes32 _bondId,
address _bondOwner,
uint256 _minClaimHold
uint128 _minClaimHold
) external payable;
/**
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import { Claim } from "../libraries/DisputeTypes.sol";
import { GameType } from "../libraries/DisputeTypes.sol";
import { GameStatus } from "../libraries/DisputeTypes.sol";
import { Timestamp } from "../libraries/DisputeTypes.sol";
import "../../libraries/DisputeTypes.sol";
import { IVersioned } from "./IVersioned.sol";
import { IBondManager } from "./IBondManager.sol";
......@@ -21,8 +18,6 @@ interface IDisputeGame is IInitializable, IVersioned {
*/
event Resolved(GameStatus indexed status);
/// @notice Returns the timestamp that the DisputeGame contract was created at.
/**
* @notice Returns the timestamp that the DisputeGame contract was created at.
* @return _createdAt The timestamp that the DisputeGame contract was created at.
......@@ -42,21 +37,21 @@ interface IDisputeGame is IInitializable, IVersioned {
* i.e. The game type should indicate the security model.
* @return _gameType The type of proof system being used.
*/
function gameType() external view returns (GameType _gameType);
function gameType() external pure returns (GameType _gameType);
/**
* @notice Getter for the root claim.
* @dev `clones-with-immutable-args` argument #2
* @return _rootClaim The root claim of the DisputeGame.
*/
function rootClaim() external view returns (Claim _rootClaim);
function rootClaim() external pure returns (Claim _rootClaim);
/**
* @notice Getter for the extra data.
* @dev `clones-with-immutable-args` argument #3
* @return _extraData Any extra data supplied to the dispute game contract by the creator.
*/
function extraData() external view returns (bytes memory _extraData);
function extraData() external pure returns (bytes memory _extraData);
/**
* @notice Returns the address of the `BondManager` used.
......@@ -73,4 +68,19 @@ interface IDisputeGame is IInitializable, IVersioned {
* @return _status The status of the game after resolution.
*/
function resolve() external returns (GameStatus _status);
/**
* @notice A compliant implementation of this interface should return the components of the
* game UUID's preimage provided in the cwia payload. The preimage of the UUID is
* constructed as `keccak256(gameType . rootClaim . extraData)` where `.` denotes
* concatenation.
*/
function gameData()
external
pure
returns (
GameType _gameType,
Claim _rootClaim,
bytes memory _extraData
);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import { Claim } from "../libraries/DisputeTypes.sol";
import { GameType } from "../libraries/DisputeTypes.sol";
import "../../libraries/DisputeTypes.sol";
import { IDisputeGame } from "./IDisputeGame.sol";
......@@ -75,4 +74,19 @@ interface IDisputeGameFactory {
* @param impl The implementation contract for the given `GameType`.
*/
function setImplementation(GameType gameType, IDisputeGame impl) external;
/**
* @notice Returns a unique identifier for the given dispute game parameters.
* @dev Hashes the concatenation of `gameType . rootClaim . extraData`
* without expanding memory.
* @param gameType The type of the DisputeGame.
* @param rootClaim The root claim of the DisputeGame.
* @param extraData Any extra data that should be provided to the created dispute game.
* @return _uuid The unique identifier for the given dispute game parameters.
*/
function getGameUUID(
GameType gameType,
Claim rootClaim,
bytes memory extraData
) external pure returns (Hash _uuid);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import { Clock } from "../libraries/DisputeTypes.sol";
import { Claim } from "../libraries/DisputeTypes.sol";
import { Position } from "../libraries/DisputeTypes.sol";
import { Timestamp } from "../libraries/DisputeTypes.sol";
import { ClaimHash } from "../libraries/DisputeTypes.sol";
import { BondAmount } from "../libraries/DisputeTypes.sol";
import "../../libraries/DisputeTypes.sol";
import { IDisputeGame } from "./IDisputeGame.sol";
......@@ -33,12 +28,6 @@ interface IFaultDisputeGame is IDisputeGame {
*/
event Defend(ClaimHash indexed claimHash, Claim indexed pivot, address indexed claimant);
/**
* @notice State variable of the starting timestamp of the game, set on deployment.
* @return The starting timestamp of the game
*/
function gameStart() external view returns (Timestamp);
/**
* @notice Maps a unique ClaimHash to a Claim.
* @param claimHash The unique ClaimHash
......
// SPDX-License-Identifier: BSD
pragma solidity ^0.8.15;
// solhint-disable
/**
* @title Clone
* @author zefram.eth, Saw-mon & Natalie, clabby
* @notice Provides helper functions for reading immutable args from calldata
* @dev Original: https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args/blob/105efee1b9127ed7f6fedf139e1fc796ce8791f2/src/Clone.sol
* @dev MODIFICATIONS:
* - Added `_getArgDynBytes` function.
*/
// solhint-enable
contract Clone {
uint256 private constant ONE_WORD = 0x20;
/**
* @notice Reads an immutable arg with type address
* @param argOffset The offset of the arg in the packed data
* @return arg The arg value
*/
function _getArgAddress(uint256 argOffset) internal pure returns (address arg) {
uint256 offset = _getImmutableArgsOffset();
assembly {
arg := shr(0x60, calldataload(add(offset, argOffset)))
}
}
/**
* @notice Reads an immutable arg with type uint256
* @param argOffset The offset of the arg in the packed data
* @return arg The arg value
*/
function _getArgUint256(uint256 argOffset) internal pure returns (uint256 arg) {
uint256 offset = _getImmutableArgsOffset();
assembly {
arg := calldataload(add(offset, argOffset))
}
}
/**
* @notice Reads an immutable arg with type bytes32
* @param argOffset The offset of the arg in the packed data
* @return arg The arg value
*/
function _getArgFixedBytes(uint256 argOffset) internal pure returns (bytes32 arg) {
uint256 offset = _getImmutableArgsOffset();
assembly {
arg := calldataload(add(offset, argOffset))
}
}
/**
* @notice Reads a uint256 array stored in the immutable args.
* @param argOffset The offset of the arg in the packed data
* @param arrLen Number of elements in the array
* @return arr The array
*/
function _getArgUint256Array(uint256 argOffset, uint64 arrLen)
internal
pure
returns (uint256[] memory arr)
{
uint256 offset = _getImmutableArgsOffset() + argOffset;
arr = new uint256[](arrLen);
assembly {
calldatacopy(add(arr, ONE_WORD), offset, shl(5, arrLen))
}
}
/**
* @notice Reads a dynamic bytes array stored in the immutable args.
* @param argOffset The offset of the arg in the packed data
* @param arrLen Number of elements in the array
* @return arr The array
*/
function _getArgDynBytes(uint256 argOffset, uint64 arrLen)
internal
pure
returns (bytes memory arr)
{
uint256 offset = _getImmutableArgsOffset() + argOffset;
arr = new bytes(arrLen);
assembly {
calldatacopy(add(arr, ONE_WORD), offset, arrLen)
}
}
/**
* @notice Reads an immutable arg with type uint64
* @param argOffset The offset of the arg in the packed data
* @return arg The arg value
*/
function _getArgUint64(uint256 argOffset) internal pure returns (uint64 arg) {
uint256 offset = _getImmutableArgsOffset();
assembly {
arg := shr(0xc0, calldataload(add(offset, argOffset)))
}
}
/**
* @notice Reads an immutable arg with type uint8
* @param argOffset The offset of the arg in the packed data
* @return arg The arg value
*/
function _getArgUint8(uint256 argOffset) internal pure returns (uint8 arg) {
uint256 offset = _getImmutableArgsOffset();
assembly {
arg := shr(0xf8, calldataload(add(offset, argOffset)))
}
}
/**
* @return offset The offset of the packed immutable args in calldata
*/
function _getImmutableArgsOffset() internal pure returns (uint256 offset) {
assembly {
offset := sub(calldatasize(), shr(0xf0, calldataload(sub(calldatasize(), 2))))
}
}
}
......@@ -5,8 +5,8 @@ import "forge-std/Test.sol";
import "../libraries/DisputeTypes.sol";
import { IDisputeGame } from "../dispute/IDisputeGame.sol";
import { IBondManager } from "../dispute/IBondManager.sol";
import { IDisputeGame } from "../dispute/interfaces/IDisputeGame.sol";
import { IBondManager } from "../dispute/interfaces/IBondManager.sol";
import { DisputeGameFactory } from "../dispute/DisputeGameFactory.sol";
......@@ -45,23 +45,21 @@ contract BondManager_Test is Test {
function testFuzz_post_succeeds(
bytes32 bondId,
address owner,
uint256 minClaimHold,
uint256 amount
uint128 minClaimHold,
uint128 amount
) public {
vm.assume(owner != address(0));
vm.assume(owner != address(bm));
vm.assume(owner != address(this));
// Create2Deployer
vm.assume(owner != address(0x4e59b44847b379578588920cA78FbF26c0B4956C));
vm.assume(amount != 0);
unchecked {
vm.assume(block.timestamp + minClaimHold > minClaimHold);
}
amount = uint128(bound(amount, 1, type(uint128).max));
minClaimHold = uint128(bound(minClaimHold, 0, type(uint128).max - block.timestamp));
vm.deal(address(this), amount);
vm.expectEmit(true, true, true, true);
uint256 expiration = block.timestamp + minClaimHold;
uint128 expiration = uint128(block.timestamp + minClaimHold);
emit BondPosted(bondId, owner, expiration, amount);
bm.post{ value: amount }(bondId, owner, minClaimHold);
......@@ -69,9 +67,9 @@ contract BondManager_Test is Test {
// Validate the bond
(
address newFetchedOwner,
uint256 fetchedExpiration,
bytes32 fetchedBondId,
uint256 bondAmount
uint128 fetchedExpiration,
uint128 bondAmount
) = bm.bonds(bondId);
assertEq(newFetchedOwner, owner);
assertEq(fetchedExpiration, block.timestamp + minClaimHold);
......@@ -85,15 +83,13 @@ contract BondManager_Test is Test {
function testFuzz_post_duplicates_reverts(
bytes32 bondId,
address owner,
uint256 minClaimHold,
uint256 amount
uint128 minClaimHold,
uint128 amount
) public {
vm.assume(owner != address(0));
amount = amount / 2;
vm.assume(amount != 0);
unchecked {
vm.assume(block.timestamp + minClaimHold > minClaimHold);
}
amount = uint128(bound(amount, 1, type(uint128).max));
minClaimHold = uint128(bound(minClaimHold, 0, type(uint128).max - block.timestamp));
vm.deal(address(this), amount);
bm.post{ value: amount }(bondId, owner, minClaimHold);
......@@ -108,8 +104,8 @@ contract BondManager_Test is Test {
*/
function testFuzz_post_zeroAddress_reverts(
bytes32 bondId,
uint256 minClaimHold,
uint256 amount
uint128 minClaimHold,
uint128 amount
) public {
address owner = address(0);
vm.deal(address(this), amount);
......@@ -123,10 +119,10 @@ contract BondManager_Test is Test {
function testFuzz_post_zeroAddress_reverts(
bytes32 bondId,
address owner,
uint256 minClaimHold
uint128 minClaimHold
) public {
vm.assume(owner != address(0));
uint256 amount = 0;
uint128 amount = 0;
vm.deal(address(this), amount);
vm.expectRevert("BondManager: Value must be non-zero.");
bm.post{ value: amount }(bondId, owner, minClaimHold);
......@@ -152,16 +148,14 @@ contract BondManager_Test is Test {
function testFuzz_seize_expired_reverts(
bytes32 bondId,
address owner,
uint256 minClaimHold,
uint256 amount
uint128 minClaimHold,
uint128 amount
) public {
vm.assume(owner != address(0));
vm.assume(owner != address(bm));
vm.assume(owner != address(this));
vm.assume(amount != 0);
unchecked {
vm.assume(block.timestamp + minClaimHold + 1 > minClaimHold);
}
amount = uint128(bound(amount, 1, type(uint128).max));
minClaimHold = uint128(bound(minClaimHold, 0, type(uint128).max - block.timestamp));
vm.deal(address(this), amount);
bm.post{ value: amount }(bondId, owner, minClaimHold);
......@@ -176,16 +170,15 @@ contract BondManager_Test is Test {
function testFuzz_seize_unauthorized_reverts(
bytes32 bondId,
address owner,
uint256 minClaimHold,
uint256 amount
uint128 minClaimHold,
uint128 amount
) public {
vm.assume(owner != address(0));
vm.assume(owner != address(bm));
vm.assume(owner != address(this));
vm.assume(amount != 0);
unchecked {
vm.assume(block.timestamp + minClaimHold > minClaimHold);
}
amount = uint128(bound(amount, 1, type(uint128).max));
minClaimHold = uint128(bound(minClaimHold, 0, type(uint128).max - block.timestamp));
vm.deal(address(this), amount);
bm.post{ value: amount }(bondId, owner, minClaimHold);
......@@ -200,12 +193,10 @@ contract BondManager_Test is Test {
*/
function testFuzz_seize_succeeds(
bytes32 bondId,
uint256 minClaimHold,
uint128 minClaimHold,
bytes calldata extraData
) public {
unchecked {
vm.assume(block.timestamp + minClaimHold > minClaimHold);
}
minClaimHold = uint128(bound(minClaimHold, 0, type(uint128).max - block.timestamp));
vm.deal(address(this), 1 ether);
bm.post{ value: 1 ether }(bondId, address(0xba5ed), minClaimHold);
......@@ -255,12 +246,10 @@ contract BondManager_Test is Test {
*/
function testFuzz_seizeAndSplit_succeeds(
bytes32 bondId,
uint256 minClaimHold,
uint128 minClaimHold,
bytes calldata extraData
) public {
unchecked {
vm.assume(block.timestamp + minClaimHold > minClaimHold);
}
minClaimHold = uint128(bound(minClaimHold, 0, type(uint128).max - block.timestamp));
vm.deal(address(this), 1 ether);
bm.post{ value: 1 ether }(bondId, address(0xba5ed), minClaimHold);
......@@ -316,15 +305,16 @@ contract BondManager_Test is Test {
function testFuzz_reclaim_succeeds(
bytes32 bondId,
address owner,
uint256 minClaimHold,
uint256 amount
uint128 minClaimHold,
uint128 amount
) public {
vm.assume(owner != address(factory));
vm.assume(owner != address(bm));
vm.assume(owner != address(this));
vm.assume(owner != address(0));
vm.assume(owner.code.length == 0);
vm.assume(amount != 0);
unchecked {
vm.assume(block.timestamp + minClaimHold > minClaimHold);
}
amount = uint128(bound(amount, 1, type(uint128).max));
minClaimHold = uint128(bound(minClaimHold, 0, type(uint128).max - block.timestamp));
assumeNoPrecompiles(owner);
// Post the bond
......@@ -332,7 +322,7 @@ contract BondManager_Test is Test {
bm.post{ value: amount }(bondId, owner, minClaimHold);
// We can't claim if the block.timestamp is less than the bond expiration.
(, uint256 expiration, , ) = bm.bonds(bondId);
(, , uint256 expiration, ) = bm.bonds(bondId);
if (expiration > block.timestamp) {
vm.prank(owner);
vm.expectRevert("BondManager: Bond isn't claimable yet.");
......@@ -351,7 +341,7 @@ contract BondManager_Test is Test {
* @title MockAttestationDisputeGame
* @dev A mock dispute game for testing bond seizures.
*/
contract MockAttestationDisputeGame is IDisputeGame {
contract MockAttestationDisputeGame {
GameStatus internal gameStatus;
BondManager bm;
Claim internal rc;
......@@ -419,11 +409,11 @@ contract MockAttestationDisputeGame is IDisputeGame {
* -------------------------------------------
*/
function createdAt() external pure override returns (Timestamp _createdAt) {
function createdAt() external pure returns (Timestamp _createdAt) {
return Timestamp.wrap(uint64(0));
}
function status() external view override returns (GameStatus _status) {
function status() external view returns (GameStatus _status) {
return gameStatus;
}
......@@ -431,7 +421,7 @@ contract MockAttestationDisputeGame is IDisputeGame {
return GameType.ATTESTATION;
}
function rootClaim() external view override returns (Claim _rootClaim) {
function rootClaim() external view returns (Claim _rootClaim) {
return rc;
}
......@@ -439,7 +429,21 @@ contract MockAttestationDisputeGame is IDisputeGame {
return ed;
}
function bondManager() external view override returns (IBondManager _bondManager) {
function gameData()
external
pure
returns (
GameType,
Claim,
bytes memory
)
{
assembly {
revert(0, 0)
}
}
function bondManager() external view returns (IBondManager _bondManager) {
return IBondManager(address(bm));
}
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import "forge-std/Test.sol";
import { ClonesWithImmutableArgs } from "@cwia/ClonesWithImmutableArgs.sol";
import { Clone } from "../libraries/Clone.sol";
contract ExampleClone is Clone {
uint256 argOffset;
constructor(uint256 _argOffset) {
argOffset = _argOffset;
}
function addressArg() public view returns (address) {
return _getArgAddress(argOffset);
}
function uintArg() public view returns (uint256) {
return _getArgUint256(argOffset);
}
function fixedBytesArg() public view returns (bytes32) {
return _getArgFixedBytes(argOffset);
}
function uintArrayArg(uint64 arrLen) public view returns (uint256[] memory) {
return _getArgUint256Array(argOffset, arrLen);
}
function dynBytesArg(uint64 arrLen) public view returns (bytes memory) {
return _getArgDynBytes(argOffset, arrLen);
}
function uint64Arg() public view returns (uint64) {
return _getArgUint64(argOffset);
}
function uint8Arg() public view returns (uint8) {
return _getArgUint8(argOffset);
}
}
contract ExampleCloneFactory {
using ClonesWithImmutableArgs for address;
ExampleClone public implementation;
constructor(ExampleClone implementation_) {
implementation = implementation_;
}
function createAddressClone(address arg) external returns (ExampleClone clone) {
bytes memory data = abi.encodePacked(arg);
clone = ExampleClone(address(implementation).clone(data));
}
function createUintClone(uint256 arg) external returns (ExampleClone clone) {
bytes memory data = abi.encodePacked(arg);
clone = ExampleClone(address(implementation).clone(data));
}
function createFixedBytesClone(bytes32 arg) external returns (ExampleClone clone) {
bytes memory data = abi.encodePacked(arg);
clone = ExampleClone(address(implementation).clone(data));
}
function createUintArrayClone(uint256[] memory arg) external returns (ExampleClone clone) {
bytes memory data = abi.encodePacked(arg);
clone = ExampleClone(address(implementation).clone(data));
}
function createDynBytesClone(bytes memory arg) external returns (ExampleClone clone) {
bytes memory data = abi.encodePacked(arg);
clone = ExampleClone(address(implementation).clone(data));
}
function createUint64Clone(uint64 arg) external returns (ExampleClone clone) {
bytes memory data = abi.encodePacked(arg);
clone = ExampleClone(address(implementation).clone(data));
}
function createUint8Clone(uint8 arg) external returns (ExampleClone clone) {
bytes memory data = abi.encodePacked(arg);
clone = ExampleClone(address(implementation).clone(data));
}
function createClone(bytes memory randomCalldata) external returns (ExampleClone clone) {
clone = ExampleClone(address(implementation).clone(randomCalldata));
}
}
contract Clones_Test is Test {
function testFuzz_clone_addressArg_succeeds(uint256 argOffset, address param) public {
ExampleClone implementation = new ExampleClone(argOffset);
ExampleCloneFactory factory = new ExampleCloneFactory(implementation);
ExampleClone clone = factory.createAddressClone(param);
address fetched = clone.addressArg();
assertEq(fetched, param);
}
function testFuzz_clone_uintArg_succeeds(uint256 argOffset, uint256 param) public {
ExampleClone implementation = new ExampleClone(argOffset);
ExampleCloneFactory factory = new ExampleCloneFactory(implementation);
ExampleClone clone = factory.createUintClone(param);
uint256 fetched = clone.uintArg();
assertEq(fetched, param);
}
function testFuzz_clone_fixedBytesArg_succeeds(uint256 argOffset, bytes32 param) public {
ExampleClone implementation = new ExampleClone(argOffset);
ExampleCloneFactory factory = new ExampleCloneFactory(implementation);
ExampleClone clone = factory.createFixedBytesClone(param);
bytes32 fetched = clone.fixedBytesArg();
assertEq(fetched, param);
}
function testFuzz_clone_uintArrayArg_succeeds(uint256 argOffset, uint256[] memory param)
public
{
ExampleClone implementation = new ExampleClone(argOffset);
ExampleCloneFactory factory = new ExampleCloneFactory(implementation);
ExampleClone clone = factory.createUintArrayClone(param);
uint256[] memory fetched = clone.uintArrayArg(uint64(param.length));
assertEq(fetched, param);
}
function testFuzz_clone_dynBytesArg_succeeds(uint256 argOffset, bytes memory param) public {
ExampleClone implementation = new ExampleClone(argOffset);
ExampleCloneFactory factory = new ExampleCloneFactory(implementation);
ExampleClone clone = factory.createDynBytesClone(param);
bytes memory fetched = clone.dynBytesArg(uint64(param.length));
assertEq(fetched, param);
}
function testFuzz_clone_uint64Arg_succeeds(uint256 argOffset, uint64 param) public {
ExampleClone implementation = new ExampleClone(argOffset);
ExampleCloneFactory factory = new ExampleCloneFactory(implementation);
ExampleClone clone = factory.createUint64Clone(param);
uint64 fetched = clone.uint64Arg();
assertEq(fetched, param);
}
function testFuzz_clone_uint8Arg_succeeds(uint256 argOffset, uint8 param) public {
ExampleClone implementation = new ExampleClone(argOffset);
ExampleCloneFactory factory = new ExampleCloneFactory(implementation);
ExampleClone clone = factory.createUint8Clone(param);
uint8 fetched = clone.uint8Arg();
assertEq(fetched, param);
}
}
......@@ -6,7 +6,7 @@ import "../libraries/DisputeErrors.sol";
import { Test } from "forge-std/Test.sol";
import { DisputeGameFactory } from "../dispute/DisputeGameFactory.sol";
import { IDisputeGame } from "../dispute/IDisputeGame.sol";
import { IDisputeGame } from "../dispute/interfaces/IDisputeGame.sol";
contract DisputeGameFactory_Test is Test {
DisputeGameFactory factory;
......
......@@ -31,6 +31,8 @@ contracts=(
contracts/legacy/L1ChugSplashProxy.sol:L1ChugSplashProxy
contracts/universal/OptimismMintableERC20.sol:OptimismMintableERC20
contracts/universal/OptimismMintableERC20Factory.sol:OptimismMintableERC20Factory
contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory
contracts/dispute/BondManager.sol:BondManager
)
dir=$(dirname "$0")
......
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