Orchestrator
Overview
The Orchestrator (OrchestratorV2) manages the lifecycle of intents and fee distribution. It verifies gating signatures, runs pre-intent hooks, locks liquidity in Escrow on signal, routes attestation verification to the UnifiedPaymentVerifierV2 on fulfillment, and transfers funds net of protocol/referral/manager fees. It also supports optional post-intent hooks via the V2 hook interface.
Constants
uint256 internal constant PRECISE_UNIT = 1e18;uint256 constant MAX_REFERRER_FEE = 5e16; // 5%uint256 constant MAX_PROTOCOL_FEE = 5e16; // 5%uint256 constant MAX_MANAGER_FEE = 5e16; // 5%
Key State
uint256 immutable chainId— Deployment chain id.mapping(bytes32 => Intent) intents— Active intents by hash;mapping(address => bytes32[]) accountIntents— per-user list.mapping(bytes32 => uint256) intentMinAtSignal— Snapshot of deposit min amount at signal time for partial-release protection.mapping(bytes32 => address) intentManagerFeeRecipient— Snapshotted manager fee recipient per intent.mapping(bytes32 => uint256) intentManagerFee— Snapshotted manager fee per intent.mapping(address => mapping(uint256 => IPreIntentHook)) depositPreIntentHooks— Per-deposit generic pre-intent hook (keyed by escrow + depositId).mapping(address => mapping(uint256 => IPreIntentHook)) depositWhitelistHooks— Per-deposit whitelist hook (keyed by escrow + depositId).- Registries:
EscrowRegistry,PaymentVerifierRegistry,RelayerRegistry. - Fees:
protocolFee(1e18),protocolFeeRecipient,allowMultipleIntentsflag,intentCounter.
Signal Intent
function signalIntent(SignalIntentParams calldata params) external
SignalIntentParams
struct SignalIntentParams {
address escrow; // Escrow holding the deposit
uint256 depositId; // Deposit id
uint256 amount; // Destination token amount to lock
address to; // Recipient of released funds
bytes32 paymentMethod; // keccak256("venmo"), etc.
bytes32 fiatCurrency; // keccak256("USD"), etc.
uint256 conversionRate; // taker-proposed rate (>= deposit effective rate), 1e18
IReferralFee.ReferralFee[] referralFees; // multi-recipient referral fees
bytes gatingServiceSignature; // signature from deposit's gating service
uint256 signatureExpiration; // epoch timestamp
IPostIntentHookV2 postIntentHook; // optional V2 hook
bytes preIntentHookData; // ephemeral data for pre-intent hooks only
bytes data; // persisted in intent, forwarded as signalHookData to post-intent hook
}
ReferralFee struct (from IReferralFee):
struct ReferralFee {
address recipient;
uint256 fee; // 1e18 precision, total across all referrals <= MAX_REFERRER_FEE (5%)
}
Behavior
- Validates the deposit and method/currency support via registries.
- Executes pre-intent hooks (both generic and whitelist slots) before any state changes. Hooks can only revert to reject.
- Verifies
gatingServiceSignaturebinds(orchestrator, escrow, depositId, amount, to, paymentMethod, fiatCurrency, conversionRate, referralFeesHash, expiration, chainId). - Snapshots
intentMinAtSignalfrom the deposit's min intent amount. - Snapshots manager fee from
EscrowV2.getManagerFee(depositId)if a rate manager is set. - Locks funds on Escrow with
lockFunds(depositId, intentHash, amount). - Emits
IntentSignaledwith snapshot values.
Fulfill Intent
function fulfillIntent(FulfillIntentParams calldata params) external
FulfillIntentParams
struct FulfillIntentParams {
bytes paymentProof; // ABI-encoded PaymentAttestation
bytes32 intentHash; // intent to fulfill
bytes verificationData; // optional
bytes postIntentHookData; // optional
}
Behavior
- Decodes
paymentProofand forwards to theIPaymentVerifier(UnifiedPaymentVerifierV2) resolved via the registry/payment method. - Requires attestation validity and snapshot match; receives
releaseAmount. - Enforces
intentMinAtSignal: ifreleaseAmount < intentMinAtSignal, the fulfillment reverts. This prevents sub-minimum partial fulfillments. - Instructs Escrow to
unlockAndTransferFundsto Orchestrator, then applies fees in order:- Protocol fee
- Manager fee (snapshotted at signal time)
- Referral fees (distributed to each recipient)
- Net remainder sent to
to(or to the post-intent hook if set)
- Supports partial releases: if the attestation indicates less than the signaled amount, only that portion is released; remaining lock is returned to deposit liquidity.
Other Operations
cancelIntent(bytes32 intentHash)— Prune and unlock.releaseFundsToPayer(bytes32 intentHash)— Manual release path for the depositor under configured rules. Manager fees are also distributed on manual release.pruneIntents(bytes32[] intentIds)— Called by Escrow to prune expired intents.cleanupOrphanedIntents(bytes32[] intentHashes)— Remove intents that reference deposits no longer in the escrow (e.g., after deposit closure). Callable by anyone.
Pre-Intent Hook Management
setDepositPreIntentHook(escrow, depositId, hook)— Set the generic pre-intent hook for a deposit. Only callable by depositor or delegate.setDepositWhitelistHook(escrow, depositId, hook)— Set the whitelist hook for a deposit. Only callable by depositor or delegate.
Both hooks run during signalIntent before state changes. See Pre-Intent Hooks for details.
Events (selected)
IntentSignaled(intentHash, escrow, depositId, paymentMethod, owner, to, amount, fiatCurrency, conversionRate, timestamp)IntentFulfilled(intentHash, fundsTransferredTo, amount, isManualRelease)IntentPruned(intentHash)IntentReferralFeeDistributed(intentHash, feeRecipient, feeAmount)IntentManagerFeeSnapshotted(intentHash, feeRecipient, fee)DepositPreIntentHookSet(escrow, depositId, hook, setter)DepositWhitelistHookSet(escrow, depositId, hook, setter)ProtocolFeeUpdated(protocolFee)/ProtocolFeeRecipientUpdated(addr)
Reference: zkp2p-v2-contracts/contracts/OrchestratorV2.sol