Orchestrator
Overview
OrchestratorV4 owns the lifecycle of new intents: signal, cancel, fulfill, manual release and pruning. It locks and releases liquidity in EscrowV2, routes verification to the payment method's registered verifier, pays protocol, manager and referral fees, and applies two governance-selected policies:
- Signal policy (
IntentSignalPolicy) admits the taker. - Settlement policy (
DisputeProtectionPolicyV2) decides whether a verified payout is paid now or held for the dispute window.
OrchestratorV4 has no pre-intent or post-intent hooks. OrchestratorV3 stays registered for older clients; see OrchestratorV3.
Constants
PRECISE_UNIT = 1e18MAX_PROTOCOL_FEE = 5e16(5%)MAX_MANAGER_FEE = 5e16(5%)- Referral fees: at most 10 recipients and
5e17(50%) combined
Signal intent
signalIntent(SignalIntentParams params) accepts:
struct SignalIntentParams {
address escrow;
uint256 depositId;
uint256 amount;
address to;
bytes32 paymentMethod;
bytes32 fiatCurrency;
uint256 conversionRate;
IReferralFee.ReferralFee[] referralFees;
bytes gatingServiceSignature;
uint256 signatureExpiration;
bytes payerCommitment; // from the gating service; the signature covers it
bytes32 groupId; // group the taker signals through; zero for none
}
The call is atomic:
- Validate the recipient, referral fees, escrow (
EscrowRegistry) and payment method (PaymentVerifierRegistry, active on the deposit).conversionRatemust be at least the deposit's effective rate (EscrowV2.getEffectiveRate); an effective rate of zero means the pair is unavailable. - Call the signal policy.
IntentSignalPolicy:- If the deposit's whitelist is enabled in
WhitelistPolicyV2, the taker must be on it directly or through an allowed group named bygroupId, or the call reverts withTakerNotWhitelisted. - Requires an unexpired gating-service signature (EIP-191) over the orchestrator, escrow, deposit, amount, taker, recipient, payment method, currency, conversion rate, referral fees, expiration, chain ID and
payerCommitment. Otherwise it reverts withSignatureExpiredorInvalidSignature.
- If the deposit's whitelist is enabled in
- Fix the manager fee for this intent, store the intent, and emit
IntentSignaledandIntentManagerFeeSnapshotted. - Lock the amount in
EscrowV2.
Fulfill intent
fulfillIntent(FulfillIntentParams params) accepts:
struct FulfillIntentParams {
bytes paymentProof; // abi.encode(PaymentAttestation)
bytes32 intentHash;
bytes verificationData;
}
Anyone can submit it:
- The payment method's verifier (
UnifiedPaymentVerifierV4for every current method) checks the proof and returns the release amount, capped at the intent amount, plus the signed settlement data. EscrowV2releases that amount to the orchestrator. Unused locked liquidity returns to the deposit.- Protocol, referral and manager fees are paid from the release amount.
- Unless the signal policy whitelisted the taker, the settlement policy decides: pay
tonow, or send the net payout toStakeVaultV2and hold it (IntentPayoutDeferred). See Stake to Take. IntentFulfilledrecords the recipient of the funds, the net amount andreleasedBy(zero for a verified payment).
If the settlement policy reverts, the whole fulfillment reverts.
Manual release
releaseFundsToPayer(intentHash, releaseAmount) lets the depositor settle an intent without a payment proof, for example after checking a payment that failed verification. The depositor must release the full intent amount.
Manual releases pay to directly and skip the settlement policy. IntentFulfilled.releasedBy records the caller.
Other operations
| Function | Caller | Effect |
|---|---|---|
cancelIntent(intentHash) | Intent owner | Deletes the intent and unlocks its funds |
pruneIntents(intentHashes) | Owning escrow | Deletes expired intents |
cleanupOrphanedIntents(intentHashes) | Anyone | Deletes intents that no longer exist on their escrow |
When governance pauses the orchestrator, signalIntent and fulfillIntent stop. Cancellation, manual release and pruning keep working.
Governance
setSignalPolicyandsetSettlementPolicyapply to later signals and settlements, including settlements of intents that are already open. Setting the zero address disables the policy.setProtocolFee(up to 5%) andsetProtocolFeeRecipient. The protocol fee is read at fulfillment.setEscrowRegistry,pauseOrchestratorandunpauseOrchestrator.
Events
IntentSignaled(includesgroupId)IntentFulfilled(includesreleasedBy)IntentPayoutDeferredIntentPrunedIntentReferralFeeDistributedIntentManagerFeeSnapshottedSignalPolicyUpdated,SettlementPolicyUpdatedProtocolFeeUpdated,ProtocolFeeRecipientUpdated,EscrowRegistryUpdated
OrchestratorV3
OrchestratorV3 was retired on 2026-11-05. OrchestratorV4 is current. Once O3 is removed from OrchestratorRegistry, Escrow rejects its signal and fulfillment calls. Historical O3 intents, payments and events remain readable. The following describes its historical layout and behavior:
SignalIntentParamshaspostIntentHook,preIntentHookDataanddatainstead ofpayerCommitmentandgroupId, andFulfillIntentParamsaddspostIntentHookData.- It checks a gating signature only when the deposit's payment method names a gating service.
- It runs the deposit's optional pre-intent hook and the governance-selected lifecycle hook,
IntentLifecycleHookV1, which applies the deposit whitelist and locks taker stake when the intent is signaled. - It supports post-intent hooks.
releaseFundsToPayer(intentHash)takes no amount and releases the full intent amount.- Accounts outside
RelayerRegistrycan hold one active intent at a time unless governance allows multiple intents.
Sources: OrchestratorV4.sol, OrchestratorV3.sol.