Skip to main content

ADRResolverV3

On-chain Alternative Dispute Resolution with arbitration clause anchoring, an 11-state dispute lifecycle, evidence via hash anchors, multi-party settlement, deadline management, automated triggers, and EAS attestation integration.

Overview

ADRResolverV3 implements a complete on-chain arbitration workflow that mirrors real-world Alternative Dispute Resolution (ADR) processes. The resolver manages the full lifecycle from clause registration through dispute initiation, evidence submission, hearings, awards, compliance, and settlement -- all anchored to Integra records.

The contract spans three resolver categories simultaneously:

  • Behavioral -- Lifecycle hooks notify the resolver of record events (registration, transfer, tokenizer association). Named actions (check-conditions, check-compliance) allow callers to trigger automated evaluations.
  • Gatekeeper -- Active disputes block ownership transfers (past INITIATED state) and tokenization (any active dispute), preventing record manipulation during proceedings.
  • Automation -- Trigger conditions (payment expiry, attestation expiry, custom evaluators) can automatically initiate disputes when evaluated by keeper bots.

ADRResolverV3 also implements IContractV2 for integration with IntegraLens and off-chain services.

Key Concepts

Pattern 1: Arbitration Clause Anchor

Before any dispute can be initiated, the record must have a registered and locked arbitration clause. The clause captures the terms under which disputes will be resolved:

struct ArbitrationClause {
    bytes32 providerReference;    // External provider identifier
    bytes32 rulesHash;            // Hash of arbitration rules document
    bytes32 clauseTextHash;       // Hash of full clause text
    uint64  registeredAt;         // When the clause was first registered
    uint64  lockedAt;             // When the clause was locked (immutable after this)
    uint8   arbitratorCount;      // Number of arbitrators (must be > 0)
    bool    locked;               // Once locked, clause cannot be modified
}
FieldTypeDescription
providerReferencebytes32External provider identifier
rulesHashbytes32Hash of the arbitration rules document
clauseTextHashbytes32Hash of the full clause text
registeredAtuint64Timestamp when the clause was first registered
lockedAtuint64Timestamp when the clause was locked
arbitratorCountuint8Number of arbitrators (must be > 0)
lockedboolOnce true, clause cannot be modified

The clause lifecycle is simple: register (modifiable) then lock (immutable). Once locked, the clause cannot be changed and disputes can be initiated against the record. String fields (providerPortalURI, rulesReference, venue, governingLaw) are emitted in events only and not stored on-chain.

Pattern 2: Dispute Lifecycle State Machine

The dispute lifecycle is managed by the StateMachine library with 11 states organized into three groups:

Active states (dispute is in progress):

StateValueDescription
INITIATED1Dispute has been raised; no external case reference yet
FILED2External case reference bound; response deadline set
PENDING3Under review by the provider
HEARING4Hearing in progress
AWARDED5Transient state during recordAward -- never persists
COMPLIANCE6Award issued with compliance deadline; parties must fulfill requirements

Terminal states (dispute is resolved):

StateValueDescription
CLOSED7Dispute concluded normally (compliance confirmed or no compliance required)
SETTLED8Parties reached a multi-party settlement
WITHDRAWN9Initiator withdrew the dispute
EXPIRED10Compliance deadline passed without confirmation

Inactive:

StateValueDescription
NONE0No dispute exists for this record

State Transition Diagram

stateDiagram-v2
    [*] --> NONE
    NONE --> INITIATED : initiateDispute() / evaluateConditions()
    INITIATED --> FILED : bindCaseReference() [restricted]
    INITIATED --> WITHDRAWN : withdrawDispute()
    INITIATED --> SETTLED : confirmSettlement() [restricted]
    FILED --> PENDING : advanceState()
    FILED --> SETTLED : confirmSettlement() [restricted]
    PENDING --> HEARING : advanceState()
    PENDING --> SETTLED : confirmSettlement() [restricted]
    HEARING --> AWARDED : recordAward() [restricted, transient]
    HEARING --> SETTLED : confirmSettlement() [restricted]
    AWARDED --> COMPLIANCE : recordAward() [atomic, if deadline > 0]
    AWARDED --> CLOSED : recordAward() [atomic, if deadline == 0]
    COMPLIANCE --> CLOSED : confirmCompliance() [restricted]
    COMPLIANCE --> EXPIRED : checkCompliance() [restricted]
    COMPLIANCE --> SETTLED : confirmSettlement() [restricted]
    CLOSED --> [*]
    SETTLED --> [*]
    WITHDRAWN --> [*]
    EXPIRED --> [*]

Two-Tier Transition Model

Generic transitions (via advanceState, callable by authorized providers):

  • INITIATED to WITHDRAWN
  • FILED to PENDING
  • PENDING to HEARING

Restricted transitions (only via specific domain functions with their own authorization):

  • INITIATED to FILED -- only via bindCaseReference()
  • HEARING to AWARDED -- only via recordAward()
  • AWARDED to COMPLIANCE -- only via recordAward() (atomic)
  • AWARDED to CLOSED -- only via recordAward() (atomic)
  • COMPLIANCE to CLOSED -- only via confirmCompliance()
  • COMPLIANCE to EXPIRED -- only via checkCompliance()
  • Any active state to SETTLED -- only via confirmSettlement() when quorum is reached

The AWARDED state is transient -- it is set and immediately transitioned within the same recordAward() call, either to COMPLIANCE (if complianceDeadline > 0) or to CLOSED (if no compliance is required). It never persists between transactions.

Evidence Anchoring (HashAnchor)

Evidence is submitted as content hashes with metadata, stored via the HashAnchor library in an append-only list per dispute. Limits: up to MAX_EVIDENCE_PER_DISPUTE (500) entries per dispute, descriptions limited to MAX_EVIDENCE_DESCRIPTION (200) characters.

Multi-Party Settlement (MultiPartyConfirmation)

Settlement is a multi-party consensus mechanism. Multiple parties must confirm the same settlement document hash before the dispute transitions to SETTLED.

  1. A party calls confirmSettlement(integraHash, settlementHash).
  2. If the tracker is not initialized, it is set with the record's settlement threshold (default: 2).
  3. If the settlementHash differs from the previously confirmed hash, all prior confirmations are invalidated (nonce increments) and a 1-hour cooldown starts.
  4. Each party can only confirm once per nonce (replay protection).
  5. When the confirmation count reaches the threshold, the dispute transitions to SETTLED and is archived.

Settlement can be confirmed by parties or agents -- not providers. Maximum 5 settlement proposal changes per dispute.

Deadline Management (DeadlineTracker)

DeadlineWhen SetEffect
Response deadlineWhen bindCaseReference() is called (INITIATED to FILED), or lazily when fileResponse() is first calledfileResponse() reverts if the deadline has passed
Compliance deadlineWhen recordAward() is called with complianceDeadline > 0checkCompliance() or evaluateConditions() can expire the dispute

Default response deadline: 30 days from filing. Can be overridden by the record owner via setResponseDeadline(). Both deadlines are cleared when a dispute is archived.

Automation Triggers (IConditionEvaluator)

Three types of automated trigger conditions:

Condition TypeConstantValueDescription
Payment expiryCONDITION_PAYMENT_EXPIRY0Checks if N payment requests have expired on the Signal contract
Attestation expiryCONDITION_ATTESTATION_EXPIRY1Checks if an EAS attestation has been revoked or expired
CustomCONDITION_CUSTOM2Delegates to an external IConditionEvaluator contract

Conditions are configured per record and evaluated permissionlessly via evaluateConditions(). When a condition is met, it is deactivated (fires once) and a dispute is automatically initiated with TRIGGER_AUTOMATED type. Custom evaluators must be pre-approved by the governor via setApprovedEvaluator() and are called with a gas limit of EVALUATOR_GAS_LIMIT (50,000).

Role-Based Access

RoleConstantAuthorized ByCan
ProviderPROVIDER_ROLE = keccak256("ADR_PROVIDER")Record owner/executorAdvance dispute state, bind case references, record awards, add compliance requirements
AgentAGENT_ROLE = keccak256("ADR_AGENT")Record owner/executorAct on behalf of a principal (record party) in disputes, evidence, settlement, compliance

Agents require a principal -- a record party whom the agent represents. The principal must be validated as a record party at authorization time. Both providers and agents can be revoked, but revocation is blocked during active disputes past the INITIATED state.

Record Party Definition

A "record party" is any of:

  • The record owner
  • An authorized executor for the record
  • A token holder on the record's tokenizer (detected via ITokenParty.isTokenHolder, gas-limited to 100,000)

Contract Details

PropertyValue
Solidity0.8.28
LicenseMIT
Sourcesrc/resolvers/adr/ADRResolverV3.sol (1250 lines)
InheritsBaseResolver, AuthorizedActors, IBehavioralResolver, IGatekeeperResolver, IAutomationResolver, ADREvents, IContractV2
UsesStateMachine, MultiPartyConfirmation, HashAnchor, DeadlineTracker
UpgradeableNo
Category bitmaskCATEGORY_BEHAVIORAL | CATEGORY_GATEKEEPER | CATEGORY_AUTOMATION (14)
Version3.0.0 ((3 << 32) | (0 << 16) | 0)
State schema"ADRResolverV3"

Constructor

constructor(
    address integraRecord,      // IntegraRecordV1 contract address
    address trustedForwarder,   // ERC-2771 trusted forwarder
    address signal,             // IntegraSignalV1 contract (0x0 to disable payment triggers)
    address eas                 // EAS contract address (required, non-zero)
)

Immutables

NameTypeDescription
INTEGRA_RECORDaddressIntegraRecordV1 contract for owner/executor lookups
SIGNALaddressIntegraSignalV1 contract for payment expiry checks (address(0) if disabled)
EASIEASEthereum Attestation Service contract for attestation expiry checks

Constants (from ADRTypes.sol)

NameValueDescription
MAX_TRIGGER_CONDITIONS10Maximum trigger conditions per record
MAX_EVIDENCE_PER_DISPUTE500Maximum evidence entries per dispute (via HashAnchor)
MAX_EVIDENCE_DESCRIPTION200Maximum description length for evidence entries
MAX_COUNTERCLAIMS10Maximum counterclaims per dispute
MAX_COMPLIANCE_REQUIREMENTS20Maximum compliance requirements per dispute
MAX_PAYMENT_REQUESTS_TO_CHECK100Maximum Signal payment requests to scan per evaluation
EVALUATOR_GAS_LIMIT50,000Gas cap for external evaluator calls
DEFAULT_RESPONSE_DEADLINE30 daysDefault response filing deadline
SETTLEMENT_COOLDOWN1 hourMinimum time between settlement hash changes
MAX_SETTLEMENT_PROPOSALS5Maximum settlement proposal changes per dispute

Structs (from ADRTypes.sol)

Dispute

struct Dispute {
    bytes32 integraHash;          // Record this dispute is against
    bytes32 groundsHash;          // Hash of the dispute grounds document
    bytes32 caseReference;        // External case reference (bound by provider)
    bytes32 awardHash;            // Hash of the award document (set by provider)
    bytes32 settlementHash;       // Hash of the settlement document (set by consensus)
    address initiator;            // Address that initiated the dispute
    uint64  disputeId;            // Sequential ID for this record's disputes
    uint64  initiatedAt;          // Block timestamp of initiation
    uint64  complianceDeadline;   // Unix timestamp for compliance deadline (0 = none)
    uint8   triggerType;          // TRIGGER_PARTY, TRIGGER_AGENT, TRIGGER_AUTOMATED, TRIGGER_THIRD_PARTY
}

Response

struct Response {
    bytes32 responseHash;         // Hash of the response document
    address respondent;           // Address that filed the response
    uint64  filedAt;              // Block timestamp of filing
    bool    contestsJurisdiction; // Whether the respondent contests jurisdiction
}

Counterclaim

struct Counterclaim {
    bytes32 groundsHash;          // Hash of the counterclaim grounds document
    address claimant;             // Address that filed the counterclaim
    uint64  filedAt;              // Block timestamp of filing
}

ComplianceRequirement

struct ComplianceRequirement {
    bytes32 descriptionHash;      // Hash of the requirement description
    bytes32 evidenceHash;         // Hash of evidence satisfying the requirement (0 if unsatisfied)
    uint64  deadline;             // Optional per-requirement deadline (0 = no deadline)
    bool    satisfied;            // Whether this requirement has been satisfied
}

TriggerCondition

struct TriggerCondition {
    uint8   conditionType;        // CONDITION_PAYMENT_EXPIRY, CONDITION_ATTESTATION_EXPIRY, CONDITION_CUSTOM
    bytes32 targetReference;      // Condition-specific: attestation UID or evaluator address (as bytes32)
    uint64  threshold;            // Condition-specific: e.g., number of expired payments required
    bool    active;               // Whether this condition is active (deactivated after triggering)
}

State Bitmask Constants

uint16 constant ACTIVE_STATES_MASK = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 6);
uint16 constant TERMINAL_STATES_MASK = (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10);

Functions

Arbitration Clause Management

registerClause

function registerClause(
    bytes32 integraHash,
    bytes32 providerReference,
    bytes32 rulesHash,
    bytes32 clauseTextHash,
    uint8   arbitratorCount,
    string calldata providerPortalURI,
    string calldata rulesReference,
    string calldata venue,
    string calldata governingLaw
) external nonReentrant whenNotPaused

Access: Record owner or executor.

Description: Registers or updates an arbitration clause for a record. Can be called multiple times before locking. Emits ClauseRegistered on first registration, ClauseUpdated on subsequent calls.

Reverts: ClauseAlreadyLocked(), InvalidArbitratorCount()


lockClause

function lockClause(bytes32 integraHash) external nonReentrant whenNotPaused

Access: Record owner or executor.

Description: Locks the arbitration clause, making it immutable. A clause must be registered before it can be locked. Once locked, disputes can be initiated against the record.

Events: ClauseLocked(integraHash)

Reverts: ClauseNotFound(), ClauseAlreadyLocked()


Dispute Lifecycle

initiateDispute

function initiateDispute(
    bytes32 integraHash,
    bytes32 groundsHash,
    uint8   triggerType
) external nonReentrant whenNotPaused

Access: Record party, authorized provider, or authorized agent.

Description: Initiates a dispute. Requires a locked clause, no existing active dispute, and a non-zero grounds hash. TRIGGER_AUTOMATED (2) is rejected -- automated triggers go through evaluateConditions().

Transitions state: NONE to INITIATED.

Events: DisputeInitiated(integraHash, disputeId, triggerType, initiator, groundsHash)

Reverts: AutomatedTriggerNotAllowed(), NotRecordParty(), ClauseNotLocked(), DisputeAlreadyActive(), EmptyGroundsHash()


withdrawDispute

function withdrawDispute(bytes32 integraHash) external nonReentrant whenNotPaused

Access: Dispute initiator only.

Description: Withdraws a dispute in INITIATED state. The dispute is archived after withdrawal.

Transitions state: INITIATED to WITHDRAWN.

Events: DisputeWithdrawn(integraHash, disputeId, withdrawnBy), DisputeArchived(integraHash, disputeId, STATE_WITHDRAWN)

Reverts: NoActiveDispute(), NotDisputeInitiator(), StateMachine.InvalidTransition(fromState, toState)


advanceState

function advanceState(bytes32 integraHash, uint8 newState) external nonReentrant whenNotPaused

Access: Authorized provider.

Description: Advances the dispute state machine through generic transitions only. Restricted transitions are blocked and must go through their domain-specific functions. Archives the dispute if the new state is terminal.

Events: DisputeStateAdvanced(integraHash, disputeId, fromState, toState, actor), optionally DisputeArchived(...)

Reverts: NotAuthorizedProvider(), NoActiveDispute(), StateMachine.InvalidTransition(fromState, toState)


bindCaseReference

function bindCaseReference(bytes32 integraHash, bytes32 caseReference) external nonReentrant whenNotPaused

Access: Authorized provider.

Description: Binds an external case reference to the dispute and atomically transitions INITIATED to FILED. The case reference must be unique and non-zero. Sets the response deadline to 30 days from the current timestamp.

Transitions state: INITIATED to FILED (restricted).

Events: CaseReferenceBound(integraHash, disputeId, caseReference, provider), DisputeStateAdvanced(...)

Reverts: NotAuthorizedProvider(), InvalidCaseReference(), CaseReferenceAlreadyBound(), NoActiveDispute(), StateMachine.InvalidTransition(...)


Award and Compliance

recordAward

function recordAward(
    bytes32 integraHash,
    bytes32 awardHash,
    uint64  complianceDeadline
) external nonReentrant whenNotPaused

Access: Authorized provider.

Description: Records an arbitration award and atomically transitions the dispute:

  • With compliance (complianceDeadline > 0): HEARING to AWARDED to COMPLIANCE
  • Without compliance (complianceDeadline == 0): HEARING to AWARDED to CLOSED (archived)

Events: AwardRecorded(integraHash, disputeId, awardHash, complianceDeadline), DisputeStateAdvanced(...), optionally DisputeClosed(...) and DisputeArchived(...)

Reverts: NotAuthorizedProvider(), InvalidAwardHash(), NoActiveDispute(), StateMachine.InvalidTransition(...), ComplianceDeadlineInPast()


confirmCompliance

function confirmCompliance(bytes32 integraHash, bytes32 evidenceHash) external nonReentrant whenNotPaused

Access: Record party, authorized provider, or authorized agent.

Description: Confirms compliance and closes the dispute. All compliance requirements must be satisfied first. The dispute must be in COMPLIANCE state.

Transitions state: COMPLIANCE to CLOSED.

Events: ComplianceConfirmed(integraHash, disputeId, evidenceHash, confirmedBy), DisputeClosed(...), DisputeArchived(...)

Reverts: NoActiveDispute(), NotInComplianceState(), NotRecordParty(), ComplianceRequirementsNotMet()


checkCompliance

function checkCompliance(bytes32 integraHash) external nonReentrant

Access: Permissionless.

Description: Checks if the compliance deadline has passed and expires the dispute if so. No-op if the deadline has not yet passed.

Transitions state: COMPLIANCE to EXPIRED (only if deadline has passed).

Events: ComplianceExpired(integraHash, disputeId), DisputeArchived(...)

Reverts: NoActiveDispute(), NotInComplianceState()


addComplianceRequirement

function addComplianceRequirement(
    bytes32 integraHash,
    bytes32 descriptionHash,
    uint64  deadline
) external nonReentrant whenNotPaused

Access: Authorized provider.

Description: Adds a compliance requirement to an active dispute in COMPLIANCE state. Up to 20 requirements per dispute.

Events: ComplianceRequirementAdded(integraHash, disputeId, requirementIndex, descriptionHash)

Reverts: NotAuthorizedProvider(), NoActiveDispute(), NotInComplianceState(), MaxComplianceRequirementsReached(), ComplianceDeadlineInPast()


satisfyRequirement

function satisfyRequirement(
    bytes32 integraHash,
    uint256 index,
    bytes32 evidenceHash
) external nonReentrant whenNotPaused

Access: Record party, authorized provider, or authorized agent.

Description: Marks a compliance requirement as satisfied. Dispute must be in COMPLIANCE state.

Events: ComplianceRequirementSatisfied(integraHash, disputeId, index, evidenceHash)

Reverts: NoActiveDispute(), NotInComplianceState(), NotRecordParty(), RequirementIndexOutOfBounds(), RequirementAlreadySatisfied()


Evidence

submitEvidence

function submitEvidence(
    bytes32 integraHash,
    bytes32 evidenceHash,
    string calldata description
) external nonReentrant whenNotPaused

Access: Record party, authorized provider, or authorized agent.

Description: Submits evidence for an active dispute. Maximum 500 entries per dispute, descriptions limited to 200 characters.

Events: EvidenceSubmitted(integraHash, disputeId, evidenceHash, submitter, evidenceIndex)

Reverts: NoActiveDispute(), NotRecordParty(), HashAnchor.EmptyContentHash(), HashAnchor.StoreAtCapacity(...), HashAnchor.DescriptionTooLong(...)


Settlement

confirmSettlement

function confirmSettlement(bytes32 integraHash, bytes32 settlementHash) external nonReentrant whenNotPaused

Access: Record party or authorized agent (not providers).

Description: Records a settlement confirmation. When the required confirmations (default: 2) are reached for the same hash, the dispute transitions to SETTLED and is archived.

Events: SettlementConfirmed(integraHash, disputeId, settlementHash, confirmedBy, confirmationNumber), optionally DisputeSettled(...) and DisputeArchived(...)

Reverts: InvalidSettlementHash(), NoActiveDispute(), NotRecordParty(), MaxSettlementProposalsReached(), MultiPartyConfirmation.AlreadyConfirmed(...), MultiPartyConfirmation.CooldownActive(...)


setSettlementThreshold

function setSettlementThreshold(bytes32 integraHash, uint8 threshold) external nonReentrant whenNotPaused

Access: Record owner or executor.

Description: Sets the number of confirmations required for settlement. Must be at least 2. No active dispute allowed.

Events: SettlementThresholdSet(integraHash, threshold)

Reverts: ActiveDisputeExists(), MultiPartyConfirmation.ThresholdTooLow(threshold)


Response and Counterclaims

fileResponse

function fileResponse(
    bytes32 integraHash,
    bytes32 responseHash,
    bool    contestsJurisdiction
) external nonReentrant whenNotPaused

Access: Non-initiator record party only. One response per dispute. Dispute must be in INITIATED, FILED, or PENDING state.

Description: Files a formal response. Response deadline is enforced -- if not already set, it is computed as current time + 30 days.

Events: ResponseFiled(integraHash, disputeId, responseHash, respondent, contestsJurisdiction)

Reverts: NoActiveDispute(), EmptyResponseHash(), InvalidDisputeState(), CannotRespondToOwnDispute(), NotRecordParty(), ResponseAlreadyFiled(), ResponseDeadlinePassed()


fileCounterclaim

function fileCounterclaim(bytes32 integraHash, bytes32 groundsHash) external nonReentrant whenNotPaused

Access: Non-initiator record party only. One counterclaim per party per dispute, maximum 10 total. Dispute must be in INITIATED, FILED, or PENDING state.

Events: CounterclaimFiled(integraHash, disputeId, counterclaimIndex, groundsHash, claimant)

Reverts: NoActiveDispute(), EmptyGroundsHash(), InvalidDisputeState(), CannotRespondToOwnDispute(), NotRecordParty(), MaxCounterclaimsReached(), CounterclaimAlreadyFiled()


setResponseDeadline

function setResponseDeadline(bytes32 integraHash, uint64 deadline) external nonReentrant whenNotPaused

Access: Record owner or executor. Dispute must be in INITIATED or FILED state.

Events: ResponseDeadlineSet(integraHash, deadline)

Reverts: NoActiveDispute(), InvalidDisputeState(), DeadlineTracker.DeadlineInPast(...)


getResponse

function getResponse(bytes32 integraHash, uint64 disputeId) external view returns (Response memory)

Access: Anyone (view).


Provider and Agent Authorization

authorizeProvider

function authorizeProvider(bytes32 integraHash, address provider) external nonReentrant whenNotPaused

Access: Record owner or executor. No active dispute allowed.

Events: ActorAuthorized(PROVIDER_ROLE, integraHash, provider, address(0), authorizedBy)

Reverts: ActiveDisputeExists(), ActorAlreadyAuthorized(...), InvalidActorAddress()


revokeProvider

function revokeProvider(bytes32 integraHash, address provider) external nonReentrant whenNotPaused

Access: Record owner or executor. Blocked during active disputes past INITIATED state.

Events: ActorRevoked(PROVIDER_ROLE, integraHash, provider, revokedBy)

Reverts: ActiveDisputeExists(), ActorNotAuthorized(...)


authorizeAgent

function authorizeAgent(bytes32 integraHash, address agent, address principal) external nonReentrant whenNotPaused

Access: Record owner or executor. Principal must be a record party.

Events: ActorAuthorized(AGENT_ROLE, integraHash, agent, principal, authorizedBy)

Reverts: NotRecordParty(), ActorAlreadyAuthorized(...), InvalidActorAddress()


revokeAgent

function revokeAgent(bytes32 integraHash, address agent) external nonReentrant whenNotPaused

Access: Record owner or executor. Blocked during active disputes past INITIATED state.

Events: ActorRevoked(AGENT_ROLE, integraHash, agent, revokedBy)

Reverts: ActiveDisputeExists(), ActorNotAuthorized(...)


Automation Triggers

addTriggerCondition

function addTriggerCondition(bytes32 integraHash, TriggerCondition calldata condition) external nonReentrant whenNotPaused

Access: Record owner or executor.

Events: TriggerConditionAdded(integraHash, conditionIndex, conditionType, targetReference)

Reverts: InvalidConditionType(), MaxTriggersReached()


deactivateTrigger

function deactivateTrigger(bytes32 integraHash, uint256 index) external nonReentrant whenNotPaused

Access: Record owner or executor.

Events: TriggerConditionDeactivated(integraHash, index)

Reverts: ConditionIndexOutOfBounds()


setApprovedEvaluator

function setApprovedEvaluator(address evaluator, bool approved) external onlyRole(GOVERNOR_ROLE)

Access: Governor only.


evaluateConditions

function evaluateConditions(bytes32 integraHash)
    external nonReentrant
    returns (bool triggered, bytes32 conditionId, bytes memory data)

Access: Permissionless (designed for keeper bots).

Description: Evaluates all active trigger conditions. If any condition is met, a dispute is initiated with TRIGGER_AUTOMATED type and the condition is deactivated. Returns early on the first match. Returns (false, ...) silently if there is an active dispute or clause is not locked. Reverts if no conditions are configured or none are met.

Events: TriggerConditionMet(...), DisputeInitiated(...)

Reverts: NoConditionsConfigured(), NoConditionsMet()


activeConditionCount

function activeConditionCount(bytes32 integraHash) external view returns (uint256)

Access: Anyone (view).


Behavioral Hooks and Actions

onRegistered, onTransferred, onTokenizerAssociated

Lifecycle hooks called by IntegraRecordV1 (restricted via onlyRecord). Each emits a corresponding event (RecordRegistered, RecordTransferred, TokenizerAssociated).


executeAction

function executeAction(bytes32 integraHash, string calldata action, bytes calldata)
    external nonReentrant whenNotPaused
    returns (bool success, bytes memory result)

Access: Permissionless.

Description: Executes a named action. Supported actions:

ActionDescription
"check-conditions"Evaluates trigger conditions and initiates dispute if met
"check-compliance"Checks compliance deadline and expires dispute if passed

Returns (false, "") for unrecognized action names.


availableActions

function availableActions(bytes32) external pure returns (string[] memory)

Returns empty array. ADR actions are determined dynamically via executeAction().


Gatekeeper Functions

canOwn

function canOwn(bytes32 integraHash, address) external view returns (bool, string memory)

Blocks ownership transfers when an active dispute exists past INITIATED state.


canTokenize

function canTokenize(bytes32 integraHash, address) external view returns (bool, string memory)

Blocks tokenization when any active dispute exists.


isExpired

function isExpired(bytes32) external pure returns (bool, uint256)

Always returns (false, 0). ADR resolver does not implement expiry.


IContractV2 Functions

getRecordState

function getRecordState(bytes32 integraHash) external view returns (bytes memory)

Returns ABI-encoded: (uint8 state, bool clauseLocked, uint64 disputeId, address initiator, bytes32 awardHash).


getAvailableActions

function getAvailableActions(bytes32 integraHash, address caller) external view returns (bytes4[] memory)

Returns function selectors available to the caller based on current dispute state and authorization.


stateSchema

function stateSchema() external pure returns (string memory)

Returns "ADRResolverV3".


Events

Clause Events

EventParametersWhen Emitted
ClauseRegisteredintegraHash (indexed), providerReference, clauseTextHash, rulesHash, arbitratorCount, providerPortalURI, rulesReference, venue, governingLawClause registered
ClauseUpdatedintegraHash (indexed), providerReference, clauseTextHash, rulesHash, arbitratorCount, providerPortalURI, rulesReference, venue, governingLawClause updated (before lock)
ClauseLockedintegraHash (indexed)Clause locked (immutable)

Dispute Lifecycle Events

EventParametersWhen Emitted
DisputeInitiatedintegraHash (indexed), disputeId (indexed), triggerType, initiator, groundsHashDispute initiated
DisputeStateAdvancedintegraHash (indexed), disputeId (indexed), fromState, toState, actorState machine transition
DisputeWithdrawnintegraHash (indexed), disputeId (indexed), withdrawnByDispute withdrawn
DisputeSettledintegraHash (indexed), disputeId (indexed), settlementHashSettlement quorum reached
DisputeClosedintegraHash (indexed), disputeId (indexed)Dispute closed normally
DisputeArchivedintegraHash (indexed), disputeId (indexed), terminalStateDispute moved to history

Award and Compliance Events

EventParametersWhen Emitted
AwardRecordedintegraHash (indexed), disputeId (indexed), awardHash, complianceDeadlineAward recorded
ComplianceConfirmedintegraHash (indexed), disputeId (indexed), evidenceHash, confirmedByCompliance confirmed
ComplianceExpiredintegraHash (indexed), disputeId (indexed)Compliance deadline passed
ComplianceRequirementAddedintegraHash (indexed), disputeId (indexed), requirementIndex, descriptionHashRequirement added
ComplianceRequirementSatisfiedintegraHash (indexed), disputeId (indexed), requirementIndex, evidenceHashRequirement satisfied

Settlement Events

EventParametersWhen Emitted
SettlementConfirmedintegraHash (indexed), disputeId (indexed), settlementHash, confirmedBy, confirmationNumberParty confirms settlement
SettlementThresholdSetintegraHash (indexed), thresholdThreshold configured

Evidence Events

EventParametersWhen Emitted
EvidenceSubmittedintegraHash (indexed), disputeId (indexed), evidenceHash, submitter, evidenceIndexEvidence anchored

Provider Bridge Events

EventParametersWhen Emitted
CaseReferenceBoundintegraHash (indexed), disputeId (indexed), caseReference, providerCase reference bound

Response and Counterclaim Events

EventParametersWhen Emitted
ResponseFiledintegraHash (indexed), disputeId (indexed), responseHash, respondent, contestsJurisdictionResponse filed
CounterclaimFiledintegraHash (indexed), disputeId (indexed), counterclaimIndex, groundsHash, claimantCounterclaim filed
ResponseDeadlineSetintegraHash (indexed), deadlineResponse deadline set

Trigger Events

EventParametersWhen Emitted
TriggerConditionAddedintegraHash (indexed), conditionIndex, conditionType, targetReferenceTrigger added
TriggerConditionDeactivatedintegraHash (indexed), conditionIndexTrigger deactivated
TriggerConditionMetintegraHash (indexed), conditionIndex, groundsHashTrigger condition met

Lifecycle Hook Events

EventParametersWhen Emitted
RecordRegisteredintegraHash (indexed), ownerRecord registered with this resolver
RecordTransferredintegraHash (indexed), from, toRecord ownership transferred
TokenizerAssociatedintegraHash (indexed), tokenizerTokenizer associated with record

Errors

Clause Errors

ErrorWhen Thrown
ClauseAlreadyLocked()Attempting to register or lock an already-locked clause
ClauseNotFound()Attempting to lock a clause that has not been registered
ClauseNotLocked()Attempting to initiate a dispute without a locked clause
InvalidArbitratorCount()Arbitrator count is 0

Dispute Errors

ErrorWhen Thrown
DisputeAlreadyActive()Attempting to initiate when one is already active
NoActiveDispute()Operating on a non-existent or archived dispute
NotDisputeInitiator()Non-initiator attempting to withdraw
NotRecordParty()Caller is not a record party, provider, or agent
AutomatedTriggerNotAllowed()Passing TRIGGER_AUTOMATED to initiateDispute()
InvalidDisputeState()Operation not allowed in the current state

Response Errors

ErrorWhen Thrown
ResponseAlreadyFiled()Second response attempt
ResponseDeadlinePassed()Response deadline has elapsed
CannotRespondToOwnDispute()Initiator attempting to respond or counterclaim
EmptyResponseHash()Response hash is zero

Counterclaim Errors

ErrorWhen Thrown
MaxCounterclaimsReached()More than 10 counterclaims
EmptyGroundsHash()Grounds hash is zero
CounterclaimAlreadyFiled()Same address filing a second counterclaim

Compliance Errors

ErrorWhen Thrown
MaxComplianceRequirementsReached()More than 20 requirements
RequirementAlreadySatisfied()Requirement already satisfied
RequirementIndexOutOfBounds()Index >= requirements length
ComplianceDeadlineInPast()Deadline is not in the future
NotInComplianceState()Operation requires COMPLIANCE state
ComplianceRequirementsNotMet()Not all requirements satisfied when confirming compliance

Settlement Errors

ErrorWhen Thrown
InvalidSettlementHash()Settlement hash is zero
MaxSettlementProposalsReached()More than 5 settlement proposal changes

Provider Errors

ErrorWhen Thrown
NotAuthorizedProvider()Caller is not an authorized provider
CaseReferenceAlreadyBound()Case reference already bound to another record
ActiveDisputeExists()Attempting to revoke provider/agent during active dispute past INITIATED
InvalidCaseReference()Case reference is zero

Trigger Errors

ErrorWhen Thrown
MaxTriggersReached()More than 10 trigger conditions
ConditionIndexOutOfBounds()Index >= conditions length
NoConditionsConfigured()evaluateConditions() called with no conditions
NoConditionsMet()No triggered conditions found
InvalidConditionType()Condition type > CONDITION_CUSTOM

Award Errors

ErrorWhen Thrown
InvalidAwardHash()Award hash is zero

Other Errors

ErrorWhen Thrown
ZeroAddress()EAS address is zero in constructor

Security Considerations

  1. Clause immutability. Once locked, an arbitration clause cannot be modified. The two-step register-then-lock process allows negotiation before commitment.

  2. Dispute exclusivity. Only one dispute can be active per record at a time.

  3. Provider revocation lockout. Providers and agents cannot be revoked during active disputes past INITIATED state.

  4. Settlement cooldown. A 1-hour cooldown between settlement hash changes prevents rapid hash-switching attacks.

  5. Gas-bounded external calls. Token holder checks (100,000 gas), custom condition evaluators (50,000 gas), and payment/attestation checks (try/catch) prevent DoS from malicious external contracts.

  6. Automated trigger safety. TRIGGER_AUTOMATED cannot be passed directly to initiateDispute(). Custom evaluators must be pre-approved by the governor.

  7. Transient AWARDED state. Never persists between transactions, preventing the dispute from getting stuck.

  8. Case reference uniqueness. The caseToEntity reverse mapping ensures each case reference is bound to one record. Cleared on archive.

  9. Reentrancy protection. All state-changing functions use ReentrancyGuardTransient (EIP-1153).

  10. Archive isolation. Terminal disputes clear the active dispute, state machine, deadlines, and settlement proposal counter.

  11. Permissionless compliance expiry. checkCompliance() is permissionless, allowing keeper bots to expire overdue disputes.

On this page

OverviewKey ConceptsPattern 1: Arbitration Clause AnchorPattern 2: Dispute Lifecycle State MachineState Transition DiagramTwo-Tier Transition ModelEvidence Anchoring (HashAnchor)Multi-Party Settlement (MultiPartyConfirmation)Deadline Management (DeadlineTracker)Automation Triggers (IConditionEvaluator)Role-Based AccessRecord Party DefinitionContract DetailsConstructorImmutablesConstants (from ADRTypes.sol)Structs (from ADRTypes.sol)DisputeResponseCounterclaimComplianceRequirementTriggerConditionState Bitmask ConstantsFunctionsArbitration Clause ManagementregisterClauselockClauseDispute LifecycleinitiateDisputewithdrawDisputeadvanceStatebindCaseReferenceAward and CompliancerecordAwardconfirmCompliancecheckComplianceaddComplianceRequirementsatisfyRequirementEvidencesubmitEvidenceSettlementconfirmSettlementsetSettlementThresholdResponse and CounterclaimsfileResponsefileCounterclaimsetResponseDeadlinegetResponseProvider and Agent AuthorizationauthorizeProviderrevokeProviderauthorizeAgentrevokeAgentAutomation TriggersaddTriggerConditiondeactivateTriggersetApprovedEvaluatorevaluateConditionsactiveConditionCountBehavioral Hooks and ActionsonRegistered, onTransferred, onTokenizerAssociatedexecuteActionavailableActionsGatekeeper FunctionscanOwncanTokenizeisExpiredIContractV2 FunctionsgetRecordStategetAvailableActionsstateSchemaEventsClause EventsDispute Lifecycle EventsAward and Compliance EventsSettlement EventsEvidence EventsProvider Bridge EventsResponse and Counterclaim EventsTrigger EventsLifecycle Hook EventsErrorsClause ErrorsDispute ErrorsResponse ErrorsCounterclaim ErrorsCompliance ErrorsSettlement ErrorsProvider ErrorsTrigger ErrorsAward ErrorsOther ErrorsSecurity Considerations