Arbiters
Last modified:
When a sponsor creates a compact, they assign an arbiter per chain. That arbiter is the sole account that can trigger a claim on the respective chain and determines which addresses receive the locked balances and in what amounts.
Responsibilities
- Claim verification — validate that claim conditions are met before submission.
- Claim submission — submit claims to The Compact on behalf of claimants.
- Recipient allocation — specify which accounts receive funds and their amounts.
- Witness-data validation — verify any witness data included in compacts.
- Cross-chain coordination — for multichain compacts, coordinate claims across chains.
Arbiter selection
Single and batch compacts
struct Compact {
address arbiter; // The designated arbiter for this compact
address sponsor;
uint256 nonce;
uint256 expires;
// ...
}Multichain compacts
Each element can designate a different arbiter per chain:
struct Element {
address arbiter; // Can be different per chain
uint256 chainId;
Lock[] commitments;
Mandate mandate; // Required for multichain
}Specifying claimants
Arbiters specify recipients through a Component struct that packs both the destination and the amount:
struct Component {
uint256 claimant; // Encodes both lockTag and recipient address
uint256 amount; // The amount of tokens to claim
}Claimant encoding
The claimant field packs two values:
- Upper 96 bits —
bytes12 lockTag(destination format) - Lower 160 bits —
address recipient
Destination options
The lockTag determines how claimed tokens are processed:
| Lock tag | Behaviour |
|---|---|
| Matches original lock's tag | Direct transfer — ERC6909 tokens are transferred to the recipient, preserving the same lock properties (allocator, reset period, scope). |
| Non-zero, different from original | Convert to new lock — tokens are moved into a new resource lock with different properties (allocator, reset period, or scope). |
bytes12(0) | Withdraw — ERC6909 tokens are burned and the underlying tokens (native or ERC-20) are sent to the recipient. |
:::important To prevent griefing via malicious receive hooks or intentional gas under-payment, The Compact implements a withdrawal fallback:
- Attempt the withdrawal with half the available gas.
- If that fails (and sufficient gas remains above a benchmarked stipend), fall back to a direct ERC6909 transfer to the recipient.
This ensures claims cannot be blocked through receive-hook manipulation while preserving intended withdrawal behaviour under normal conditions. Required stipends are determined by benchmarking cold-account access, typical ERC-20 transfer costs, and native-token transfer costs. The benchmark can be re-run at any time via __benchmark.
:::
Example
// Example: Arbiter specifying three different destinations
Component[] memory claimants = new Component[](3);
// Direct transfer - keep same lock properties
claimants[0] = Component({
claimant: uint256(uint160(alice)) | (uint256(originalLockTag) << 160),
amount: 100e18
});
// Convert to new lock with different allocator
claimants[1] = Component({
claimant: uint256(uint160(bob)) | (uint256(newLockTag) << 160),
amount: 50e18
});
// Withdraw to underlying token
claimants[2] = Component({
claimant: uint256(uint160(charlie)), // lockTag is 0
amount: 25e18
});Claim functions
Six claim functions cover the matrix of single-vs-batch and single-chain-vs-multichain:
Single-chain
// Single resource lock
function claim(Claim calldata claimPayload) external returns (bytes32 claimHash)
// Multiple resource locks
function batchClaim(BatchClaim calldata claimPayload) external returns (bytes32 claimHash)Multichain — notarized chain
Used when the claim is on the chain whose domain matches the EIP-712 signature:
function multichainClaim(
MultichainClaim calldata claimPayload
) external returns (bytes32 claimHash)
function batchMultichainClaim(
BatchMultichainClaim calldata claimPayload
) external returns (bytes32 claimHash)Multichain — exogenous chain
Used when the claim is on a chain other than the notarized chain:
function exogenousClaim(
ExogenousMultichainClaim calldata claimPayload
) external returns (bytes32 claimHash)
function exogenousBatchClaim(
ExogenousBatchMultichainClaim calldata claimPayload
) external returns (bytes32 claimHash)Authorization flow
When an arbiter submits a claim, The Compact verifies authorization in order:
- Arbiter is caller —
msg.sendermust match the arbiter in the compact. - Claim validity — not expired, correct nonce, etc.
- Sponsor signature — the sponsor's signature must authorize the compact (unless the compact is registered on-chain).
- Allocator authorization — the allocator must approve the claim.
Trust model
Sponsors trust arbiters to submit only valid claims, not collude with claimants, and properly verify witness data.
Claimants trust arbiters to submit claims promptly when conditions are met, not censor valid claims, and distribute resources according to compact terms.
Common patterns
Automated arbiters
Smart contracts can serve as trustless arbiters — oracle-based arbiters that verify external conditions, time-locked arbiters for scheduled releases, or multi-signature arbiters requiring multiple approvals.
Arbiter networks
Multiple arbiters can be coordinated through consensus mechanisms, reputation-based selection, or stake-based security models.
Events
event Claim(
address indexed sponsor,
address indexed allocator,
address indexed arbiter,
bytes32 claimHash,
uint256 nonce
)Errors
| Error | Meaning |
|---|---|
InvalidArbiter() | Caller is not the designated arbiter. |
ClaimExpired() | Claim has passed its expiration time. |
InvalidClaimSignature() | Sponsor's signature is invalid. |
UnauthorizedClaim() | Arbiter is not authorized for this claim. |
Security considerations
Key compromise — a compromised arbiter key can submit unauthorized claims. Sponsors should monitor for suspicious activity and consider time delays or multi-sig requirements for high-value compacts.
Censorship — arbiters can refuse to submit valid claims. Sponsors can mitigate this by using multiple arbiters, implementing replacement mechanisms, or setting appropriate expiration times.
Front-running — arbiters should consider private mempools or commit-reveal schemes for sensitive claims.