Skip to main content

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 = 1e18
  • MAX_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:

  1. Validate the recipient, referral fees, escrow (EscrowRegistry) and payment method (PaymentVerifierRegistry, active on the deposit). conversionRate must be at least the deposit's effective rate (EscrowV2.getEffectiveRate); an effective rate of zero means the pair is unavailable.
  2. 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 by groupId, or the call reverts with TakerNotWhitelisted.
    • 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 with SignatureExpired or InvalidSignature.
  3. Fix the manager fee for this intent, store the intent, and emit IntentSignaled and IntentManagerFeeSnapshotted.
  4. 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:

  1. The payment method's verifier (UnifiedPaymentVerifierV4 for every current method) checks the proof and returns the release amount, capped at the intent amount, plus the signed settlement data.
  2. EscrowV2 releases that amount to the orchestrator. Unused locked liquidity returns to the deposit.
  3. Protocol, referral and manager fees are paid from the release amount.
  4. Unless the signal policy whitelisted the taker, the settlement policy decides: pay to now, or send the net payout to StakeVaultV2 and hold it (IntentPayoutDeferred). See Stake to Take.
  5. IntentFulfilled records the recipient of the funds, the net amount and releasedBy (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​

FunctionCallerEffect
cancelIntent(intentHash)Intent ownerDeletes the intent and unlocks its funds
pruneIntents(intentHashes)Owning escrowDeletes expired intents
cleanupOrphanedIntents(intentHashes)AnyoneDeletes 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​

  • setSignalPolicy and setSettlementPolicy apply to later signals and settlements, including settlements of intents that are already open. Setting the zero address disables the policy.
  • setProtocolFee (up to 5%) and setProtocolFeeRecipient. The protocol fee is read at fulfillment.
  • setEscrowRegistry, pauseOrchestrator and unpauseOrchestrator.

Events​

  • IntentSignaled (includes groupId)
  • IntentFulfilled (includes releasedBy)
  • IntentPayoutDeferred
  • IntentPruned
  • IntentReferralFeeDistributed
  • IntentManagerFeeSnapshotted
  • SignalPolicyUpdated, SettlementPolicyUpdated
  • ProtocolFeeUpdated, 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:

  • SignalIntentParams has postIntentHook, preIntentHookData and data instead of payerCommitment and groupId, and FulfillIntentParams adds postIntentHookData.
  • 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 RelayerRegistry can hold one active intent at a time unless governance allows multiple intents.

Sources: OrchestratorV4.sol, OrchestratorV3.sol.