Skip to main content

Pre-Intent Hooks

Overview

OrchestratorV3 supports one optional pre-intent hook per EscrowV2 deposit. It runs during signalIntent before intent state is committed or funds are locked. A hook approves by returning normally and rejects by reverting.

The pre-intent hook is distinct from the global lifecycle hook. Production's WhitelistLifecycleHook enforces Groups and direct-wallet access policies; deposit owners do not place that policy hook in the pre-intent slot.

Interface

interface IPreIntentHook {
struct PreIntentContext {
address taker;
address escrow;
uint256 depositId;
uint256 amount;
address to;
bytes32 paymentMethod;
bytes32 fiatCurrency;
uint256 conversionRate;
IReferralFee.ReferralFee[] referralFees;
bytes preIntentHookData;
}

function validateSignalIntent(PreIntentContext calldata ctx) external;
}

Source: zkp2p-contracts/contracts/interfaces/IPreIntentHook.sol

Signature gating

SignatureGatingPreIntentHook is the built-in generic hook. A configurable signer authorizes a deposit's intent parameters with an EIP-191 signature. The signed message binds the orchestrator, escrow, deposit, amount, taker, recipient, payment method, fiat currency, conversion rate, referral fees, expiration, and chain ID.

  1. The depositor or delegate calls orchestrator.setDepositPreIntentHook(escrow, depositId, hookAddress).
  2. The depositor configures the signer on the hook.
  3. The taker ABI-encodes the signature and expiration in SignalIntentParams.preIntentHookData.

Base address: 0x62D410a3d6FC766dd2192be2a67a5fc79c5c2e1F.

Groups and direct-wallet access

Current access policies do not use a second pre-intent slot. Instead:

  1. The deposit owner configures WhitelistPolicy with Public or Restricted access, direct taker wallets, and up to ten allowed Group IDs.
  2. OrchestratorV3 snapshots the governance-selected lifecycle hook when an intent is signaled.
  3. The production WhitelistLifecycleHook calls the policy from onIntentSignaled before funds are locked.
  4. A Public policy passes. A Restricted policy passes only for a directly listed taker or a current member of one of the allowed Groups.

Group membership lives in AddressGroupRegistry and is managed by each Group's curator, future curator, or resolver. Policy writes remain depositor-only.

See Access Groups for the product flow.

Legacy V2 whitelist hook

OrchestratorV2 had two deposit hook slots: generic and whitelist. Its WhitelistPreIntentHook deployment remains documented for integrations that own existing V2 deposits or intents, but it is not the current Groups access path and OrchestratorV3 does not expose setDepositWhitelistHook.

Writing a custom pre-intent hook

  1. Implement IPreIntentHook.validateSignalIntent(ctx).
  2. Revert with a specific error to reject; return normally to approve.
  3. Read ctx.preIntentHookData for request-specific validation data.
  4. Have the depositor or delegate set the contract through setDepositPreIntentHook.

Keep validation deterministic and cheap. A hook failure reverts the complete signalIntent transaction.