Skip to content

Commit

Permalink
Add new Dispute Arbitration Policy (#263)
Browse files Browse the repository at this point in the history
* add draft new arbitration policy interfaces

* add new arbitration policy errors

* add new arbitration policy skeleton

* add base integration unit tests

* update deploy helper

* fix DisputeResolved event

* fix DisputeResolve unit tests

* update Errors.sol

* add new arbitration policy updates

* interface update

* solhint fix

* update Errors.sol

* format fixes

* add new disputeAssertion function - contracts and unit tests

* DeployHelper.sol fix

* add dispute timestamp to DisputeModule.sol

* add ipOwner dispute assertion priority time window

* interface fixes

* error naming fix

* deploy helper naming fix

* add interface function

* ArbitrationPolicyUMA contract adjustments and unit tests

* comment fix

* enhance error message

* format fix
  • Loading branch information
Spablob authored Oct 19, 2024
1 parent 387b3cc commit 3ef2a99
Show file tree
Hide file tree
Showing 15 changed files with 1,314 additions and 28 deletions.
13 changes: 11 additions & 2 deletions contracts/interfaces/modules/dispute/IDisputeModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ interface IDisputeModule {
/// @notice Dispute struct
/// @param targetIpId The ipId that is the target of the dispute
/// @param disputeInitiator The address of the dispute initiator
/// @param disputeTimestamp The timestamp of the dispute
/// @param arbitrationPolicy The address of the arbitration policy
/// @param disputeEvidenceHash The hash pointing to the dispute evidence
/// @param targetTag The target tag of the dispute
Expand All @@ -14,6 +15,7 @@ interface IDisputeModule {
struct Dispute {
address targetIpId;
address disputeInitiator;
uint256 disputeTimestamp;
address arbitrationPolicy;
bytes32 disputeEvidenceHash;
bytes32 targetTag;
Expand Down Expand Up @@ -55,6 +57,7 @@ interface IDisputeModule {
/// @param disputeId The dispute id
/// @param targetIpId The ipId that is the target of the dispute
/// @param disputeInitiator The address of the dispute initiator
/// @param disputeTimestamp The timestamp of the dispute
/// @param arbitrationPolicy The address of the arbitration policy
/// @param disputeEvidenceHash The hash pointing to the dispute evidence
/// @param targetTag The target tag of the dispute
Expand All @@ -63,6 +66,7 @@ interface IDisputeModule {
uint256 disputeId,
address targetIpId,
address disputeInitiator,
uint256 disputeTimestamp,
address arbitrationPolicy,
bytes32 disputeEvidenceHash,
bytes32 targetTag,
Expand All @@ -85,16 +89,19 @@ interface IDisputeModule {
/// @param derivativeIpId The derivative ipId which was tagged
/// @param parentDisputeId The parent dispute id in which infringement was found
/// @param tag The tag of the dispute applied to the derivative
/// @param disputeTimestamp The timestamp of the dispute
event DerivativeTaggedOnParentInfringement(
address parentIpId,
address derivativeIpId,
uint256 parentDisputeId,
bytes32 tag
bytes32 tag,
uint256 disputeTimestamp
);

/// @notice Event emitted when a dispute is resolved
/// @param disputeId The dispute id
event DisputeResolved(uint256 disputeId);
/// @param data Custom data adjusted to each policy
event DisputeResolved(uint256 disputeId, bytes data);

/// @notice Dispute ID counter
function disputeCounter() external view returns (uint256);
Expand All @@ -106,6 +113,7 @@ interface IDisputeModule {
/// @param disputeId The dispute id
/// @return targetIpId The ipId that is the target of the dispute
/// @return disputeInitiator The address of the dispute initiator
/// @return disputeTimestamp The timestamp of the dispute
/// @return arbitrationPolicy The address of the arbitration policy
/// @return disputeEvidenceHash The link of the dispute summary
/// @return targetTag The target tag of the dispute
Expand All @@ -119,6 +127,7 @@ interface IDisputeModule {
returns (
address targetIpId,
address disputeInitiator,
uint256 disputeTimestamp,
address arbitrationPolicy,
bytes32 disputeEvidenceHash,
bytes32 targetTag,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@ pragma solidity 0.8.26;

/// @title Arbitration Policy Interface
interface IArbitrationPolicy {
/// @notice Executes custom logic on raising dispute.
/// @dev Enforced to be only callable by the DisputeModule.
/// @notice Executes custom logic on raising dispute
/// @dev Enforced to be only callable by the DisputeModule
/// @param caller Address of the caller
/// @param data The arbitrary data used to raise the dispute
function onRaiseDispute(address caller, bytes calldata data) external;

/// @notice Executes custom logic on disputing judgement.
/// @dev Enforced to be only callable by the DisputeModule.
/// @notice Executes custom logic on disputing judgement
/// @dev Enforced to be only callable by the DisputeModule
/// @param disputeId The dispute id
/// @param decision The decision of the dispute
/// @param data The arbitrary data used to set the dispute judgement
function onDisputeJudgement(uint256 disputeId, bool decision, bytes calldata data) external;

/// @notice Executes custom logic on disputing cancel.
/// @dev Enforced to be only callable by the DisputeModule.
/// @notice Executes custom logic on disputing cancel
/// @dev Enforced to be only callable by the DisputeModule
/// @param caller Address of the caller
/// @param disputeId The dispute id
/// @param data The arbitrary data used to cancel the dispute
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.26;

import { IArbitrationPolicy } from "../IArbitrationPolicy.sol";
import { IOOV3Callbacks } from "./IOOV3Callbacks.sol";

/// @title Arbitration Policy UMA Interface
interface IArbitrationPolicyUMA is IArbitrationPolicy, IOOV3Callbacks {
/// @notice Emitted when liveness is set
/// @param minLiveness The minimum liveness value
/// @param maxLiveness The maximum liveness value
/// @param ipOwnerTimePercent The percentage of liveness time the IP owner has priority to respond to a dispute
event LivenessSet(uint64 minLiveness, uint64 maxLiveness, uint32 ipOwnerTimePercent);

/// @notice Emitted when max bond is set
/// @param token The token address
/// @param maxBond The maximum bond value
event MaxBondSet(address token, uint256 maxBond);

/// @notice Emitted when a dispute is raised
/// @param disputeId The dispute id
/// @param caller The caller address that raised the dispute
/// @param claim The asserted claim
/// @param liveness The liveness time
/// @param currency The bond currency
/// @param bond The bond size
/// @param identifier The UMA specific identifier
event DisputeRaisedUMA(
uint256 disputeId,
address caller,
bytes claim,
uint64 liveness,
address currency,
uint256 bond,
bytes32 identifier
);

/// @notice Emitted when an assertion is disputed
/// @param assertionId The assertion id
/// @param counterEvidenceHash The counter evidence hash
event AssertionDisputed(bytes32 assertionId, bytes32 counterEvidenceHash);

/// @notice Sets the liveness for UMA disputes
/// @param minLiveness The minimum liveness value
/// @param maxLiveness The maximum liveness value
/// @param ipOwnerTimePercent The percentage of liveness time the IP owner has priority to respond to a dispute
function setLiveness(uint64 minLiveness, uint64 maxLiveness, uint32 ipOwnerTimePercent) external;

/// @notice Sets the max bond for UMA disputes
/// @param token The token address
/// @param maxBond The maximum bond value
function setMaxBond(address token, uint256 maxBond) external;

/// @notice Allows the IP that was targeted with a dispute to dispute the assertion while providing counter evidence
/// @param assertionId The identifier of the assertion that was disputed
/// @param counterEvidenceHash The hash of the counter evidence
function disputeAssertion(bytes32 assertionId, bytes32 counterEvidenceHash) external;

/// @notice Returns the maximum percentage - represents 100%
function maxPercent() external view returns (uint32);

/// @notice Returns the minimum liveness for UMA disputes
function minLiveness() external view returns (uint64);

/// @notice Returns the maximum liveness for UMA disputes
function maxLiveness() external view returns (uint64);

/// @notice Returns the percentage of liveness time the IP owner has priority to respond to a dispute
function ipOwnerTimePercent() external view returns (uint32);

/// @notice Returns the maximum bond for a given token for UMA disputes
/// @param token The token address
function maxBonds(address token) external view returns (uint256);

/// @notice Returns the assertion id for a given dispute id
/// @param disputeId The dispute id
function disputeIdToAssertionId(uint256 disputeId) external view returns (bytes32);

/// @notice Returns the dispute id for a given assertion id
/// @param assertionId The assertion id
function assertionIdToDisputeId(bytes32 assertionId) external view returns (uint256);
}
52 changes: 52 additions & 0 deletions contracts/interfaces/modules/dispute/policies/UMA/IOOV3.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.26;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/// @title IOOV3 Interface
interface IOOV3 {
struct EscalationManagerSettings {
bool arbitrateViaEscalationManager;
bool discardOracle;
bool validateDisputers;
address assertingCaller;
address escalationManager;
}

struct Assertion {
EscalationManagerSettings escalationManagerSettings;
address asserter;
uint64 assertionTime;
bool settled;
IERC20 currency;
uint64 expirationTime;
bool settlementResolution;
bytes32 domainId;
bytes32 identifier;
uint256 bond;
address callbackRecipient;
address disputer;
}

function assertTruth(
bytes memory claim,
address asserter,
address callbackRecipient,
address escalationManager,
uint64 liveness,
IERC20 currency,
uint256 bond,
bytes32 identifier,
bytes32 domainId
) external returns (bytes32 assertionId);

function disputeAssertion(bytes32 assertionId, address disputer) external;

function settleAssertion(bytes32 assertionId) external;

function getAssertion(bytes32 assertionId) external view returns (Assertion memory);

function stampAssertion(bytes32 assertionId) external view returns (bytes memory);

function burnedBondPercentage() external view returns (uint256);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.26;

/// @title IOOV3 Callbacks Interface
interface IOOV3Callbacks {
function assertionResolvedCallback(bytes32 assertionId, bool assertedTruthfully) external;

function assertionDisputedCallback(bytes32 assertionId) external;
}
62 changes: 62 additions & 0 deletions contracts/lib/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,68 @@ library Errors {
/// @notice Zero arbitration policy cooldown provided.
error DisputeModule__ZeroArbitrationPolicyCooldown();

////////////////////////////////////////////////////////////////////////////
// Arbitration Policy UMA //
////////////////////////////////////////////////////////////////////////////

/// @notice Only dispute module can call.
error ArbitrationPolicyUMA__NotDisputeModule();

/// @notice Zero address provided for Dispute Module.
error ArbitrationPolicyUMA__ZeroDisputeModule();

/// @notice Zero address provided for OOV3.
error ArbitrationPolicyUMA__ZeroOOV3();

/// @notice Zero address provided for Access Manager.
error ArbitrationPolicyUMA__ZeroAccessManager();

/// @notice Zero min liveness provided.
error ArbitrationPolicyUMA__ZeroMinLiveness();

/// @notice Zero max liveness provided.
error ArbitrationPolicyUMA__ZeroMaxLiveness();

/// @notice Liveness is too short.
error ArbitrationPolicyUMA__LivenessBelowMin();

/// @notice Liveness is too long.
error ArbitrationPolicyUMA__LivenessAboveMax();

/// @notice Min liveness is above max liveness.
error ArbitrationPolicyUMA__MinLivenessAboveMax();

/// @notice IP owner time percent is above max.
error ArbitrationPolicyUMA__IpOwnerTimePercentAboveMax();

/// @notice Bond size is above max.
error ArbitrationPolicyUMA__BondAboveMax();

/// @notice Cannot cancel.
error ArbitrationPolicyUMA__CannotCancel();

/// @notice Only OOV3 can call.
error ArbitrationPolicyUMA__NotOOV3();

/// @notice No counter evidence provided.
error ArbitrationPolicyUMA__NoCounterEvidence();

/// @notice Dispute not found.
error ArbitrationPolicyUMA__DisputeNotFound();

/// @notice Cannot dispute assertion if tag is inherited.
error ArbitrationPolicyUMA__CannotDisputeAssertionIfTagIsInherited();

/// @notice Only target IP id can dispute within time window.
error ArbitrationPolicyUMA__OnlyTargetIpIdCanDisputeWithinTimeWindow(
uint64 elapsedTime,
uint64 liveness,
address caller
);

/// @notice Not the UMA dispute policy.
error ArbitrationPolicyUMA__OnlyDisputePolicyUMA();

////////////////////////////////////////////////////////////////////////////
// Royalty Module //
////////////////////////////////////////////////////////////////////////////
Expand Down
23 changes: 20 additions & 3 deletions contracts/modules/dispute/DisputeModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,12 @@ contract DisputeModule is

address arbitrationPolicy = _updateActiveArbitrationPolicy(targetIpId);
uint256 disputeId = ++$.disputeCounter;
uint256 disputeTimestamp = block.timestamp;

$.disputes[disputeId] = Dispute({
targetIpId: targetIpId,
disputeInitiator: msg.sender,
disputeTimestamp: disputeTimestamp,
arbitrationPolicy: arbitrationPolicy,
disputeEvidenceHash: disputeEvidenceHash,
targetTag: targetTag,
Expand All @@ -219,7 +221,16 @@ contract DisputeModule is

IArbitrationPolicy(arbitrationPolicy).onRaiseDispute(msg.sender, data);

emit DisputeRaised(disputeId, targetIpId, msg.sender, arbitrationPolicy, disputeEvidenceHash, targetTag, data);
emit DisputeRaised(
disputeId,
targetIpId,
msg.sender,
disputeTimestamp,
arbitrationPolicy,
disputeEvidenceHash,
targetTag,
data
);

return disputeId;
}
Expand Down Expand Up @@ -296,10 +307,12 @@ contract DisputeModule is
if (!$.isWhitelistedArbitrationPolicy[arbitrationPolicy]) arbitrationPolicy = $.baseArbitrationPolicy;

uint256 disputeId = ++$.disputeCounter;
uint256 disputeTimestamp = block.timestamp;

$.disputes[disputeId] = Dispute({
targetIpId: derivativeIpId,
disputeInitiator: msg.sender,
disputeTimestamp: disputeTimestamp,
arbitrationPolicy: arbitrationPolicy,
disputeEvidenceHash: "",
targetTag: parentDispute.currentTag,
Expand All @@ -313,7 +326,8 @@ contract DisputeModule is
parentIpId,
derivativeIpId,
parentDisputeId,
parentDispute.currentTag
parentDispute.currentTag,
disputeTimestamp
);
}

Expand Down Expand Up @@ -341,7 +355,7 @@ contract DisputeModule is

IArbitrationPolicy(dispute.arbitrationPolicy).onResolveDispute(msg.sender, disputeId, data);

emit DisputeResolved(disputeId);
emit DisputeResolved(disputeId, data);
}

/// @notice Updates the active arbitration policy for a given ipId
Expand Down Expand Up @@ -377,6 +391,7 @@ contract DisputeModule is
/// @param disputeId The dispute id
/// @return targetIpId The ipId that is the target of the dispute
/// @return disputeInitiator The address of the dispute initiator
/// @return disputeTimestamp The timestamp of the dispute
/// @return arbitrationPolicy The address of the arbitration policy
/// @return disputeEvidenceHash The hash pointing to the dispute evidence
/// @return targetTag The target tag of the dispute
Expand All @@ -390,6 +405,7 @@ contract DisputeModule is
returns (
address targetIpId,
address disputeInitiator,
uint256 disputeTimestamp,
address arbitrationPolicy,
bytes32 disputeEvidenceHash,
bytes32 targetTag,
Expand All @@ -401,6 +417,7 @@ contract DisputeModule is
return (
dispute.targetIpId,
dispute.disputeInitiator,
dispute.disputeTimestamp,
dispute.arbitrationPolicy,
dispute.disputeEvidenceHash,
dispute.targetTag,
Expand Down
Loading

0 comments on commit 3ef2a99

Please sign in to comment.