Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
1436e70d
Commit
1436e70d
authored
May 08, 2023
by
Andreas Bigger
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add bond manager and associated tests.
parent
af98296b
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
656 additions
and
21 deletions
+656
-21
BondManager.sol
packages/contracts-bedrock/contracts/dispute/BondManager.sol
+177
-0
DisputeGameFactory.sol
...ontracts-bedrock/contracts/dispute/DisputeGameFactory.sol
+0
-1
IBondManager.sol
...ages/contracts-bedrock/contracts/dispute/IBondManager.sol
+14
-14
IDisputeGame.sol
...ages/contracts-bedrock/contracts/dispute/IDisputeGame.sol
+4
-1
IDisputeGameFactory.sol
...ntracts-bedrock/contracts/dispute/IDisputeGameFactory.sol
+2
-1
IFaultDisputeGame.sol
...contracts-bedrock/contracts/dispute/IFaultDisputeGame.sol
+7
-2
DisputeTypes.sol
...es/contracts-bedrock/contracts/libraries/DisputeTypes.sol
+2
-2
BondManager.t.sol
packages/contracts-bedrock/contracts/test/BondManager.t.sol
+450
-0
No files found.
packages/contracts-bedrock/contracts/dispute/BondManager.sol
0 → 100644
View file @
1436e70d
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import { GameType } from "../libraries/DisputeTypes.sol";
import { GameStatus } from "../libraries/DisputeTypes.sol";
import { SafeCall } from "../libraries/SafeCall.sol";
import { IDisputeGame } from "./IDisputeGame.sol";
import { IDisputeGameFactory } from "./IDisputeGameFactory.sol";
/**
* @title BondManager
* @notice The Bond Manager serves as an escrow for permissionless output proposal bonds.
*/
contract BondManager {
// The Bond Type
struct Bond {
address owner;
uint256 expiration;
bytes32 id;
uint256 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.
*/
IDisputeGameFactory public immutable DISPUTE_GAME_FACTORY;
/**
* @notice Instantiates the bond maanger with the registered dispute game factory.
* @param _disputeGameFactory is the dispute game factory.
*/
constructor(IDisputeGameFactory _disputeGameFactory) {
DISPUTE_GAME_FACTORY = _disputeGameFactory;
}
/**
* @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.
*/
function post(
bytes32 _bondId,
address _bondOwner,
uint256 _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;
bonds[_bondId] = Bond({
owner: _bondOwner,
expiration: expiration,
id: _bondId,
amount: 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.
*/
function seize(bytes32 _bondId) external {
Bond memory b = bonds[_bondId];
require(b.owner != address(0), "BondManager: The bond does not exist.");
require(b.expiration >= block.timestamp, "BondManager: Bond expired.");
IDisputeGame caller = IDisputeGame(msg.sender);
IDisputeGame game = DISPUTE_GAME_FACTORY.games(
GameType.ATTESTATION,
caller.rootClaim(),
caller.extraData()
);
require(msg.sender == address(game), "BondManager: Unauthorized seizure.");
require(game.status() == GameStatus.CHALLENGER_WINS, "BondManager: Game incomplete.");
delete bonds[_bondId];
emit BondSeized(_bondId, b.owner, msg.sender, b.amount);
bool success = SafeCall.send(payable(msg.sender), gasleft(), b.amount);
require(success, "BondManager: Failed to send Ether.");
}
/**
* @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.
*/
function seizeAndSplit(bytes32 _bondId, address[] calldata _claimRecipients) external {
Bond memory b = bonds[_bondId];
require(b.owner != address(0), "BondManager: The bond does not exist.");
require(b.expiration >= block.timestamp, "BondManager: Bond expired.");
IDisputeGame caller = IDisputeGame(msg.sender);
IDisputeGame game = DISPUTE_GAME_FACTORY.games(
GameType.ATTESTATION,
caller.rootClaim(),
caller.extraData()
);
require(msg.sender == address(game), "BondManager: Unauthorized seizure.");
require(game.status() == GameStatus.CHALLENGER_WINS, "BondManager: Game incomplete.");
delete bonds[_bondId];
emit BondSeized(_bondId, b.owner, msg.sender, b.amount);
uint256 len = _claimRecipients.length;
uint256 proportionalAmount = b.amount / len;
for (uint256 i = 0; i < len; i++) {
bool success = SafeCall.send(
payable(_claimRecipients[i]),
gasleft() / len,
proportionalAmount
);
require(success, "BondManager: Failed to send Ether.");
}
}
/**
* @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.
*/
function reclaim(bytes32 _bondId) external {
Bond memory b = bonds[_bondId];
require(b.owner == msg.sender, "BondManager: Unauthorized claimant.");
require(b.expiration <= block.timestamp, "BondManager: Bond isn't claimable yet.");
delete bonds[_bondId];
emit BondReclaimed(_bondId, msg.sender, b.amount);
bool success = SafeCall.send(payable(msg.sender), gasleft(), b.amount);
require(success, "BondManager: Failed to send Ether.");
}
}
packages/contracts-bedrock/contracts/dispute/DisputeGameFactory.sol
View file @
1436e70d
...
@@ -12,7 +12,6 @@ import { NoImplementation } from "../libraries/DisputeErrors.sol";
...
@@ -12,7 +12,6 @@ import { NoImplementation } from "../libraries/DisputeErrors.sol";
import { GameAlreadyExists } from "../libraries/DisputeErrors.sol";
import { GameAlreadyExists } from "../libraries/DisputeErrors.sol";
import { IDisputeGame } from "./IDisputeGame.sol";
import { IDisputeGame } from "./IDisputeGame.sol";
import { IBondManager } from "./IBondManager.sol";
import { IDisputeGameFactory } from "./IDisputeGameFactory.sol";
import { IDisputeGameFactory } from "./IDisputeGameFactory.sol";
/**
/**
...
...
packages/contracts-bedrock/contracts/dispute/IBondManager.sol
View file @
1436e70d
//
/
SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
pragma solidity ^0.8.15;
/**
/**
...
@@ -9,36 +9,36 @@ interface IBondManager {
...
@@ -9,36 +9,36 @@ interface IBondManager {
/**
/**
* @notice Post a bond with a given id and owner.
* @notice Post a bond with a given id and owner.
* @dev This function will revert if the provided bondId is already in use.
* @dev This function will revert if the provided bondId is already in use.
* @param bondId is the id of the bond.
* @param
_
bondId is the id of the bond.
* @param
o
wner is the address that owns the bond.
* @param
_bondO
wner is the address that owns the bond.
* @param minClaimHold is the minimum amount of time the owner
* @param
_
minClaimHold is the minimum amount of time the owner
* must wait before reclaiming their bond.
* must wait before reclaiming their bond.
*/
*/
function post(
function post(
bytes32 bondId,
bytes32
_
bondId,
address
o
wner,
address
_bondO
wner,
uint256 minClaimHold
uint256
_
minClaimHold
) external payable;
) external payable;
/**
/**
* @notice Seizes the bond with the given id.
* @notice Seizes the bond with the given id.
* @dev This function will revert if there is no bond at 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.
* @param
_
bondId is the id of the bond.
*/
*/
function seize(bytes32 bondId) external;
function seize(bytes32
_
bondId) external;
/**
/**
* @notice Seizes the bond with the given id and distributes it to recipients.
* @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.
* @dev This function will revert if there is no bond at the given id.
* @param bondId is the id of the bond.
* @param
_
bondId is the id of the bond.
* @param
r
ecipients is a set of addresses to split the bond amongst.
* @param
_claimR
ecipients is a set of addresses to split the bond amongst.
*/
*/
function seizeAndSplit(bytes32
bondId, address[] calldata r
ecipients) external;
function seizeAndSplit(bytes32
_bondId, address[] calldata _claimR
ecipients) external;
/**
/**
* @notice Reclaims the bond of the bond owner.
* @notice Reclaims the bond of the bond owner.
* @dev This function will revert if there is no bond at 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.
* @param
_
bondId is the id of the bond.
*/
*/
function reclaim(bytes32 bondId) external;
function reclaim(bytes32
_
bondId) external;
}
}
packages/contracts-bedrock/contracts/dispute/IDisputeGame.sol
View file @
1436e70d
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
pragma solidity ^0.8.15;
import { Claim, GameType, GameStatus, Timestamp } from "../libraries/DisputeTypes.sol";
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 { IVersioned } from "./IVersioned.sol";
import { IVersioned } from "./IVersioned.sol";
import { IBondManager } from "./IBondManager.sol";
import { IBondManager } from "./IBondManager.sol";
...
...
packages/contracts-bedrock/contracts/dispute/IDisputeGameFactory.sol
View file @
1436e70d
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
pragma solidity ^0.8.15;
import { Claim, GameType } from "../libraries/DisputeTypes.sol";
import { Claim } from "../libraries/DisputeTypes.sol";
import { GameType } from "../libraries/DisputeTypes.sol";
import { IDisputeGame } from "./IDisputeGame.sol";
import { IDisputeGame } from "./IDisputeGame.sol";
...
...
packages/contracts-bedrock/contracts/dispute/IFaultDisputeGame.sol
View file @
1436e70d
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
pragma solidity ^0.8.15;
import { Claim, ClaimHash, Clock, Bond, Position, Timestamp } from "../libraries/DisputeTypes.sol";
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 { IDisputeGame } from "./IDisputeGame.sol";
import { IDisputeGame } from "./IDisputeGame.sol";
...
@@ -60,7 +65,7 @@ interface IFaultDisputeGame is IDisputeGame {
...
@@ -60,7 +65,7 @@ interface IFaultDisputeGame is IDisputeGame {
* @param claimHash The unique ClaimHash
* @param claimHash The unique ClaimHash
* @return bond The Bond associated with the ClaimHash
* @return bond The Bond associated with the ClaimHash
*/
*/
function bonds(ClaimHash claimHash) external view returns (Bond bond);
function bonds(ClaimHash claimHash) external view returns (Bond
Amount
bond);
/**
/**
* @notice Maps a unique ClaimHash its chess clock.
* @notice Maps a unique ClaimHash its chess clock.
...
...
packages/contracts-bedrock/contracts/libraries/DisputeTypes.sol
View file @
1436e70d
...
@@ -18,9 +18,9 @@ type Claim is bytes32;
...
@@ -18,9 +18,9 @@ type Claim is bytes32;
type ClaimHash is bytes32;
type ClaimHash is bytes32;
/**
/**
* @notice A bond represents the amount of collateral that a user has locked up in a claim.
* @notice A bond
amount
represents the amount of collateral that a user has locked up in a claim.
*/
*/
type Bond is uint256;
type Bond
Amount
is uint256;
/**
/**
* @notice A dedicated timestamp type.
* @notice A dedicated timestamp type.
...
...
packages/contracts-bedrock/contracts/test/BondManager.t.sol
0 → 100644
View file @
1436e70d
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import "forge-std/Test.sol";
import "../libraries/DisputeTypes.sol";
import { IDisputeGame } from "../dispute/IDisputeGame.sol";
import { IBondManager } from "../dispute/IBondManager.sol";
import { DisputeGameFactory } from "../dispute/DisputeGameFactory.sol";
import { BondManager } from "../dispute/BondManager.sol";
contract BondManager_Test is Test {
DisputeGameFactory factory;
BondManager bm;
// DisputeGameFactory events
event DisputeGameCreated(
address indexed disputeProxy,
GameType indexed gameType,
Claim indexed rootClaim
);
// BondManager events
event BondPosted(bytes32 bondId, address owner, uint256 expiration, uint256 amount);
event BondSeized(bytes32 bondId, address owner, address seizer, uint256 amount);
event BondReclaimed(bytes32 bondId, address claiment, uint256 amount);
function setUp() public {
factory = new DisputeGameFactory(address(this));
bm = new BondManager(factory);
}
/**
* -------------------------------------------
* Test Bond Posting
* -------------------------------------------
*/
/**
* @notice Tests that posting a bond succeeds.
*/
function testFuzz_post_succeeds(
bytes32 bondId,
address owner,
uint256 minClaimHold,
uint256 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);
}
vm.deal(address(this), amount);
vm.expectEmit(true, true, true, true);
uint256 expiration = block.timestamp + minClaimHold;
emit BondPosted(bondId, owner, expiration, amount);
bm.post{ value: amount }(bondId, owner, minClaimHold);
// Validate the bond
(
address newFetchedOwner,
uint256 fetchedExpiration,
bytes32 fetchedBondId,
uint256 bondAmount
) = bm.bonds(bondId);
assertEq(newFetchedOwner, owner);
assertEq(fetchedExpiration, block.timestamp + minClaimHold);
assertEq(fetchedBondId, bondId);
assertEq(bondAmount, amount);
}
/**
* @notice Tests that posting a bond with the same id twice reverts.
*/
function testFuzz_post_duplicates_reverts(
bytes32 bondId,
address owner,
uint256 minClaimHold,
uint256 amount
) public {
vm.assume(owner != address(0));
amount = amount / 2;
vm.assume(amount != 0);
unchecked {
vm.assume(block.timestamp + minClaimHold > minClaimHold);
}
vm.deal(address(this), amount);
bm.post{ value: amount }(bondId, owner, minClaimHold);
vm.deal(address(this), amount);
vm.expectRevert("BondManager: BondId already posted.");
bm.post{ value: amount }(bondId, owner, minClaimHold);
}
/**
* @notice Posting with the zero address as the owner fails.
*/
function testFuzz_post_zeroAddress_reverts(
bytes32 bondId,
uint256 minClaimHold,
uint256 amount
) public {
address owner = address(0);
vm.deal(address(this), amount);
vm.expectRevert("BondManager: Owner cannot be the zero address.");
bm.post{ value: amount }(bondId, owner, minClaimHold);
}
/**
* @notice Posting zero value bonds should revert.
*/
function testFuzz_post_zeroAddress_reverts(
bytes32 bondId,
address owner,
uint256 minClaimHold
) public {
vm.assume(owner != address(0));
uint256 amount = 0;
vm.deal(address(this), amount);
vm.expectRevert("BondManager: Value must be non-zero.");
bm.post{ value: amount }(bondId, owner, minClaimHold);
}
/**
* -------------------------------------------
* Test Bond Seizing
* -------------------------------------------
*/
/**
* @notice Non-existing bonds shouldn't be seizable.
*/
function testFuzz_seize_missingBond_reverts(bytes32 bondId) public {
vm.expectRevert("BondManager: The bond does not exist.");
bm.seize(bondId);
}
/**
* @notice Bonds that expired cannot be seized.
*/
function testFuzz_seize_expired_reverts(
bytes32 bondId,
address owner,
uint256 minClaimHold,
uint256 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);
}
vm.deal(address(this), amount);
bm.post{ value: amount }(bondId, owner, minClaimHold);
vm.warp(block.timestamp + minClaimHold + 1);
vm.expectRevert("BondManager: Bond expired.");
bm.seize(bondId);
}
/**
* @notice Bonds cannot be seized by unauthorized parties.
*/
function testFuzz_seize_unauthorized_reverts(
bytes32 bondId,
address owner,
uint256 minClaimHold,
uint256 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);
}
vm.deal(address(this), amount);
bm.post{ value: amount }(bondId, owner, minClaimHold);
MockAttestationDisputeGame game = new MockAttestationDisputeGame();
vm.prank(address(game));
vm.expectRevert("BondManager: Unauthorized seizure.");
bm.seize(bondId);
}
/**
* @notice Seizing a bond should succeed if the game resolves.
*/
function testFuzz_seize_succeeds(
bytes32 bondId,
uint256 minClaimHold,
bytes calldata extraData
) public {
unchecked {
vm.assume(block.timestamp + minClaimHold > minClaimHold);
}
vm.deal(address(this), 1 ether);
bm.post{ value: 1 ether }(bondId, address(0xba5ed), minClaimHold);
// Create a mock dispute game in the factory
IDisputeGame proxy;
Claim rootClaim;
bytes memory ed = extraData;
{
rootClaim = Claim.wrap(bytes32(""));
MockAttestationDisputeGame implementation = new MockAttestationDisputeGame();
GameType gt = GameType.ATTESTATION;
factory.setImplementation(gt, IDisputeGame(address(implementation)));
vm.expectEmit(false, true, true, false);
emit DisputeGameCreated(address(0), gt, rootClaim);
proxy = factory.create(gt, rootClaim, extraData);
assertEq(address(factory.games(gt, rootClaim, extraData)), address(proxy));
}
// Update the game fields
MockAttestationDisputeGame spawned = MockAttestationDisputeGame(payable(address(proxy)));
spawned.setBondManager(bm);
spawned.setRootClaim(rootClaim);
spawned.setGameStatus(GameStatus.CHALLENGER_WINS);
spawned.setBondId(bondId);
spawned.setExtraData(ed);
// Seize the bond by calling resolve
vm.expectEmit(true, true, true, true);
emit BondSeized(bondId, address(0xba5ed), address(spawned), 1 ether);
spawned.resolve();
assertEq(address(spawned).balance, 1 ether);
// Validate that the bond was deleted
(address newFetchedOwner, , , ) = bm.bonds(bondId);
assertEq(newFetchedOwner, address(0));
}
/**
* -------------------------------------------
* Test Bond Split and Seizing
* -------------------------------------------
*/
/**
* @notice Seizing and splitting a bond should succeed if the game resolves.
*/
function testFuzz_seizeAndSplit_succeeds(
bytes32 bondId,
uint256 minClaimHold,
bytes calldata extraData
) public {
unchecked {
vm.assume(block.timestamp + minClaimHold > minClaimHold);
}
vm.deal(address(this), 1 ether);
bm.post{ value: 1 ether }(bondId, address(0xba5ed), minClaimHold);
// Create a mock dispute game in the factory
IDisputeGame proxy;
Claim rootClaim;
bytes memory ed = extraData;
{
rootClaim = Claim.wrap(bytes32(""));
MockAttestationDisputeGame implementation = new MockAttestationDisputeGame();
GameType gt = GameType.ATTESTATION;
factory.setImplementation(gt, IDisputeGame(address(implementation)));
vm.expectEmit(false, true, true, false);
emit DisputeGameCreated(address(0), gt, rootClaim);
proxy = factory.create(gt, rootClaim, extraData);
assertEq(address(factory.games(gt, rootClaim, extraData)), address(proxy));
}
// Update the game fields
MockAttestationDisputeGame spawned = MockAttestationDisputeGame(payable(address(proxy)));
spawned.setBondManager(bm);
spawned.setRootClaim(rootClaim);
spawned.setGameStatus(GameStatus.CHALLENGER_WINS);
spawned.setBondId(bondId);
spawned.setExtraData(ed);
// Seize the bond by calling resolve
vm.expectEmit(true, true, true, true);
emit BondSeized(bondId, address(0xba5ed), address(spawned), 1 ether);
spawned.splitResolve();
assertEq(address(spawned).balance, 0);
address[] memory challengers = spawned.getChallengers();
uint256 proportionalAmount = 1 ether / challengers.length;
for (uint256 i = 0; i < challengers.length; i++) {
assertEq(address(challengers[i]).balance, proportionalAmount);
}
// Validate that the bond was deleted
(address newFetchedOwner, , , ) = bm.bonds(bondId);
assertEq(newFetchedOwner, address(0));
}
/**
* -------------------------------------------
* Test Bond Reclaiming
* -------------------------------------------
*/
/**
* @notice Bonds can be reclaimed after the specified amount of time.
*/
function testFuzz_reclaim_succeeds(
bytes32 bondId,
address owner,
uint256 minClaimHold,
uint256 amount
) public {
vm.assume(owner != address(0));
vm.assume(owner.code.length == 0);
vm.assume(amount != 0);
unchecked {
vm.assume(block.timestamp + minClaimHold > minClaimHold);
}
assumeNoPrecompiles(owner);
// Post the bond
vm.deal(address(this), amount);
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);
if (expiration > block.timestamp) {
vm.prank(owner);
vm.expectRevert("BondManager: Bond isn't claimable yet.");
bm.reclaim(bondId);
}
// Past expiration, the owner can reclaim
vm.warp(expiration);
vm.prank(owner);
bm.reclaim(bondId);
assertEq(owner.balance, amount);
}
}
/**
* @title MockAttestationDisputeGame
* @dev A mock dispute game for testing bond seizures.
*/
contract MockAttestationDisputeGame is IDisputeGame {
GameStatus internal gameStatus;
BondManager bm;
Claim internal rc;
bytes internal ed;
bytes32 internal bondId;
address[] internal challengers;
function getChallengers() public view returns (address[] memory) {
return challengers;
}
function setBondId(bytes32 bid) external {
bondId = bid;
}
function setBondManager(BondManager _bm) external {
bm = _bm;
}
function setGameStatus(GameStatus _gs) external {
gameStatus = _gs;
}
function setRootClaim(Claim _rc) external {
rc = _rc;
}
function setExtraData(bytes memory _ed) external {
ed = _ed;
}
receive() external payable {}
fallback() external payable {}
function splitResolve() public {
challengers = [address(1), address(2)];
bm.seizeAndSplit(bondId, challengers);
}
/**
* -------------------------------------------
* Initializable Functions
* -------------------------------------------
*/
function initialize() external {
/* noop */
}
/**
* -------------------------------------------
* IVersioned Functions
* -------------------------------------------
*/
function version() external pure returns (string memory _version) {
return "0.1.0";
}
/**
* -------------------------------------------
* IDisputeGame Functions
* -------------------------------------------
*/
function createdAt() external pure override returns (Timestamp _createdAt) {
return Timestamp.wrap(uint64(0));
}
function status() external view override returns (GameStatus _status) {
return gameStatus;
}
function gameType() external pure returns (GameType _gameType) {
return GameType.ATTESTATION;
}
function rootClaim() external view override returns (Claim _rootClaim) {
return rc;
}
function extraData() external view returns (bytes memory _extraData) {
return ed;
}
function bondManager() external view override returns (IBondManager _bondManager) {
return IBondManager(address(bm));
}
function resolve() external returns (GameStatus _status) {
bm.seize(bondId);
return gameStatus;
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment