Skip to main content

Overview

The Orchestrator is the intent coordination hub of the zkp2p protocol. It manages the complete lifecycle of intents from signal to fulfillment, coordinates with the Escrow for liquidity management, and integrates with payment verifiers to validate off-chain payments.
The Orchestrator acts as the “order book” for P2P fiat-to-crypto trades, matching buyers (who signal intents) with sellers (who provide liquidity via deposits).

Key Responsibilities

  • Intent Signaling: Capture buyer commitment to pay off-chain for on-chain assets
  • Intent Verification: Validate gating service signatures and deposit parameters
  • Fulfillment Coordination: Verify payment proofs and release funds to buyers
  • Fee Management: Collect protocol fees and referrer fees
  • Hook Execution: Execute post-intent actions (bridging, swapping, etc.)

Core Data Structures

Intent Struct

Every intent signaled on the Orchestrator is represented by this comprehensive struct (from contracts/interfaces/IOrchestrator.sol:12):
Intent Immutability: Once signaled, intent parameters are frozen on-chain. This gives strong guarantees to both buyer (locked exchange rate) and seller (payment details).

SignalIntentParams

When signaling an intent, users provide these parameters (from contracts/interfaces/IOrchestrator.sol:29):

Intent Lifecycle

Signaling Intents

Buyers signal intent to purchase on-chain assets by paying off-chain (from contracts/Orchestrator.sol:102):

Signal Validation

The _validateSignalIntent() function performs extensive checks (from contracts/Orchestrator.sol:390):
  1. Multiple Intent Check: Verify user can have multiple active intents (whitelisted relayer or allowMultipleIntents == true)
  2. Address Validation: Ensure to address is not zero
  3. Fee Validation:
    • Referrer fee must be ≤ 50% (MAX_REFERRER_FEE)
    • If no referrer, fee must be 0
  4. Post-Intent Hook Validation: If set, must be whitelisted in postIntentHookRegistry
  5. Escrow Validation: Must be whitelisted or registry accepts all escrows
  6. Payment Method Validation: Must exist in paymentVerifierRegistry and be active on the deposit
  7. Currency Validation: Must be supported by the payment method with non-zero min conversion rate
  8. Conversion Rate Validation: Must meet or exceed deposit’s min conversion rate
  9. Gating Service Signature: If deposit has a gating service, validate EIP-712 signature

Intent Hash Calculation

Intent hashes are deterministically generated (from contracts/Orchestrator.sol:444):
The hash is modded by CIRCOM_PRIME_FIELD (254-bit prime) to ensure compatibility with circom-based ZK circuits.

What Happens on Signal

  1. Validate all parameters via _validateSignalIntent()
  2. Generate unique intentHash via _calculateIntentHash()
  3. Fetch deposit and payment method data from Escrow
  4. Store snapshot of deposit’s min intent amount (intentMinAtSignal)
  5. Create and store the full Intent struct
  6. Add intent hash to accountIntents[msg.sender]
  7. Increment intentCounter
  8. Emit IntentSignaled event
  9. Call IEscrow(escrow).lockFunds(depositId, intentHash, amount)
If lockFunds() on the Escrow reverts (insufficient liquidity, deposit not accepting intents, etc.), the entire transaction reverts.

Cancelling Intents

Intent owners can cancel their own intents before fulfillment (from contracts/Orchestrator.sol:161):
Process:
  1. Verify intent exists (timestamp != 0)
  2. Verify caller is intent owner
  3. Prune intent (delete from storage, remove from accountIntents)
  4. Call IEscrow(escrow).unlockFunds(depositId, intentHash) to release liquidity
  5. Emit IntentPruned event

Fulfilling Intents

Anyone can submit a fulfillment with valid payment proof (from contracts/Orchestrator.sol:184):

FulfillIntentParams

Fulfillment Flow

Payment Verification

The Orchestrator calls the payment verifier registered for the intent’s payment method (from contracts/Orchestrator.sol:194):
The verifier returns:

Min-At-Signal Enforcement

To prevent sub-minimum partial fulfillments, the Orchestrator enforces the deposit’s min intent amount at the time of signal (from contracts/Orchestrator.sol:205):
This prevents a depositor from raising their min intent amount after an intent is signaled, then getting a partial fulfillment below the original minimum.

Fee Management

Protocol Fee

The protocol charges a fee on the release amount (from contracts/Orchestrator.sol:485):
  • Max protocol fee: 10% (MAX_PROTOCOL_FEE = 1e17 at line 41)
  • Fee is in preciseUnits (1e16 = 1%)

Referrer Fee

Referrers can earn a fee for bringing users to the protocol (from contracts/Orchestrator.sol:490):
  • Max referrer fee: 50% (MAX_REFERRER_FEE = 5e17 at line 40)
  • Paid from the release amount

Net Amount Calculation

The netAmount is what the buyer receives (or is passed to the post-intent hook).

Post-Intent Hooks

Post-intent hooks enable custom actions after fulfillment, such as:
  • Bridging tokens to another chain (Across, Stargate)
  • Swapping tokens (Uniswap, 1inch)
  • Depositing to yield protocols
  • Multi-step DeFi operations

Hook Execution

If an intent has a postIntentHook set (from contracts/Orchestrator.sol:534):
Security: The hook must pull exactly netAmount from the Orchestrator. Any deviation causes the transaction to revert. This prevents hooks from leaving stranded funds or draining extra tokens.

Manual Release by Depositor

Depositors can manually release funds to the buyer in case of disputes or off-chain arrangements (from contracts/Orchestrator.sol:232):
Process:
  1. Verify caller is the depositor for the intent’s deposit
  2. Prune intent from storage
  3. Call unlockAndTransferFunds() with full intent amount (no partial)
  4. Calculate and transfer fees
  5. Transfer net amount to intent.to
  6. Emit IntentFulfilled(intentHash, to, netAmount, isManualRelease: true)
Manual releases still charge protocol and referrer fees.

Intent Pruning

Expired intents are pruned by the Escrow contract, which calls back to the Orchestrator (from contracts/Orchestrator.sol:257):
Only the Escrow that owns the intent can prune it:

Gating Service Signatures

Deposits can require buyers to obtain a signature from a gating service (KYC provider, allowlist manager, etc.) before signaling intents.

Signature Validation

The signature covers (from contracts/Orchestrator.sol:578):
The signature includes signatureExpiration to prevent replay attacks. Signatures must be used before expiry.

State Variables

Access Control

Owner (Governance)

  • Set escrow registry
  • Set protocol fee (max 10%)
  • Set protocol fee recipient
  • Set allow multiple intents
  • Set post-intent hook registry
  • Set relayer registry
  • Pause/unpause orchestrator

Users

  • Signal intents (with valid gating signature if required)
  • Cancel own intents
  • Fulfill any intent (with valid payment proof)

Depositors

  • Manually release funds to buyers

Escrows

  • Prune expired intents

Key Events

Security Features

Reentrancy Protection

fulfillIntent and releaseFundsToPayer use nonReentrant guard

Intent Immutability

Once signaled, intent parameters cannot be changed

Min-At-Signal

Prevents depositors from raising minimums after intent signal

Hook Safety

Post-intent hooks must consume exact allowance or revert