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
Expand all
Hide 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
This diff is collapsed.
Click to expand it.
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