Smart Contracts (V3)
This page summarizes the V3 on-chain contracts and links to detailed pages for each component.
Orchestrator
- Purpose: lifecycle for intents (signal, cancel, fulfill), protocol/referral/manager fees, routing to verifiers, one per-deposit pre-intent hook, a snapshotted global lifecycle hook, and post-intent hooks.
- Key entry points
signalIntent(SignalIntentParams)- Inputs:
escrow,depositId,amount,to,paymentMethod(bytes32),fiatCurrency(bytes32),conversionRate(1e18 fixed),referralFees[](multi-recipient),gatingServiceSignature,signatureExpiration, optionalpostIntentHook(IPostIntentHookV2),preIntentHookData,data. - The deposit's optional generic pre-intent hook executes first. The active lifecycle hook then runs
onIntentSignaledbefore fund locking; a rejection reverts the whole transaction. - Manager fee is snapshotted from
EscrowV2.getManagerFee(depositId). - Emits
IntentSignaled(intentHash, escrow, depositId, paymentMethod, owner, to, amount, fiatCurrency, conversionRate, timestamp).
- Inputs:
fulfillIntent(FulfillIntentParams)- Inputs:
paymentProof(ABI-encodedPaymentAttestation),intentHash, optionalverificationData, optionalpostIntentHookData. - Routes to the configured
IPaymentVerifier, unlocks funds, distributes fees (protocol → manager → referral), and transfers net totoor post-intent hook. - Accepts verifier-authorized partial fulfillment amounts, including amounts below the deposit's signal-time minimum; unused locked liquidity returns to the deposit.
- Emits
IntentFulfilled.
- Inputs:
UnifiedPaymentVerifier
- Purpose: canonical on-chain verifier for off-chain attestations from buyer zkTLS, Buyer TEE Verification, and Seller Autopilot.
- V3 uses
UnifiedPaymentVerifierV2(0x46A58Dc65587D4D7B8198C6A25eEdf5b2535Da94). - Typed data
- Type:
PaymentAttestation(bytes32 intentHash,uint256 releaseAmount,bytes32 dataHash) - Domain: name
UnifiedPaymentVerifier, version1, chainId, verifyingContract.
- Type:
- Attestation payload
intentHash: binds the attestation to an on-chain intent.releaseAmount: token amount to release on-chain (after FX, before fees). Capped tointent.amountduring verification.dataHash: hash of thedatablob.signatures[]: witness signatures checked byAttestationVerifier.data: ABI-encoded(PaymentDetails, IntentSnapshot).metadata: optional attribution bytes. Current service responses encodebuyer-zktls,buyer-tee, orseller-tee; this field is not signed or digested.PaymentDetails:method: bytes32 (payment method, e.g., keccak256("venmo"))payeeId: bytes32 (hashed off-chain recipient id)amount: uint256 (smallest fiat unit, e.g., cents)currency: bytes32 (fiat currency code hash)timestamp: uint256 (ms)paymentId: bytes32 (hashed provider transaction id)
IntentSnapshot:intentHash,amount,paymentMethod,fiatCurrency,payeeDetails,conversionRate,signalTimestamp,timestampBuffer
Verification rules (key checks)
- EIP-712 signature validates over
(intentHash, releaseAmount, dataHash)and the domain separator. keccak256(data) == dataHashto prevent tampering.- Snapshot must match on-chain intent fields at fulfillment time.
- Nullifier:
keccak256(paymentMethod || paymentId)must be unused; it is recorded to prevent reuse. - Release capping: if
releaseAmount > intent.amount, the verifier reduces tointent.amount.
AttestationVerifier
- Purpose: witness management and threshold signature verification for the attestation digest.
- The active implementation on Base is
MultiAttestationVerifier, which supports a governed witness set with a signature threshold.SimpleAttestationVerifier(single witness, threshold 1) remains deployed but is not wired to the liveUnifiedPaymentVerifierV2.
Escrow
- EscrowV2 holds deposits and tracks payment methods + currencies per deposit.
- Supports oracle-driven rate floors, delegated rate management (RateManagerV1), dust sweeping, and third-party funded deposits (
depositTo). - Authorized Orchestrators (via OrchestratorRegistry) call into Escrow to lock/unlock and transfer funds.
OrchestratorRegistry
- Simple allowlist authorizing orchestrator contracts on EscrowV2.
addOrchestrator(address)/removeOrchestrator(address)— Owner-only.isOrchestrator(address)— Returns whether an address is authorized.- Replaces the single
orchestratoraddress used in the legacy Escrow.
RateManagerV1
- Pure rate registry for delegated rate management.
- Managers create configs (
createRateManager), set rates per deposit/method/currency. - Exposes
getRate(rateManagerId, escrow, depositId, paymentMethod, currencyCode)andgetFee(rateManagerId). - EscrowV2 enforces the effective rate floor as
max(fixedRate, oracleRate, delegatedRate). - Manager fee (capped at 5%) is snapshotted at intent signal time and distributed at fulfillment.
ChainlinkOracleAdapter
- Wraps Chainlink price feeds implementing
IOracleAdapter. getRate(normalizedConfig)→(isValid, marketRate, updatedAt).validateConfig(rawConfig)— Validates and normalizes adapter-specific config for storage.- Adapters are view-only (no state mutation) and normalize rates to 1e18 preciseUnits.
- Spread is applied by EscrowV2, not the adapter:
oracleRate = marketRate * (10_000 + spreadBps) / 10_000.
Pre-Intent Hooks
- One optional generic hook slot per deposit on OrchestratorV3.
- Runs during
signalIntentbefore state changes and can only revert to reject. SignatureGatingPreIntentHookis the built-in signature-gating implementation.- See Pre-Intent Hooks for details.
Lifecycle Hook and Access Policy
- Governance selects one lifecycle hook on OrchestratorV3, and the selected address is snapshotted onto each new intent.
- Production uses
WhitelistLifecycleHook. On signal, it reads the deposit'sWhitelistPolicy; public policies pass, while restricted policies require the taker to be directly allowed or a member of one of the deposit's allowed Groups. WhitelistPolicyis depositor-owned. It supports direct wallet addresses plus up to ten Groups fromAddressGroupRegistryper deposit.- Cancellation and settlement callbacks use the snapshotted lifecycle hook, so a later governance update does not change an existing intent's callback target.
Events (selected)
IntentSignaled,IntentFulfilled,IntentPruned,IntentReferralFeeDistributed,IntentManagerFeeSnapshottedDepositPreIntentHookSet,LifecycleHookUpdated,IntentLifecycleHookSnapshottedPaymentMethodAdded/Removed,AttestationVerifierUpdated.
Notes
- All string-like identifiers (payment method, currency code, payee id, payment id) are keccak256-hashed to bytes32 on-chain.
conversionRateuses 1e18 precision (same as PRECISE_UNIT).