DeFi Integration
Connect swaps, vaults and settled payments to private notes. Start with the route, then handle quotes, execution and recovery.
How a DeFi action works#
A DeFi action spends private notes, calls an external contract and returns an ERC-20 asset to the Pool. For example, a USDC vault deposit returns shares. The Pool first reserves those shares for settlement, then creates the private note during finalization. Your app needs to track both steps: the vault call can succeed before the new note is spendable.
The Pool checks who can spend the input notes and whether the publisher has enabled the route. The adapter then calls its configured venue and checks the token movements. Its contract fixes the recipient and venue, so the caller cannot redirect the output, choose a different spender or change note ownership. After deploying an adapter, register its route with the Pool before offering it in the app.
Choose the output your route can return#
Choose the adapter based on what the venue delivers during the transaction. A swap or synchronous vault call returns the final token immediately. A queued redemption returns a ticket until the venue pays out. A payment route can return backing assets once its credits have settled. This choice determines the balance your app shows and the next action a user can take.
| Route type | Adapter | What the Pool receives |
|---|---|---|
| Fixed-share vault | ReviewedFixedShareAdapter | Synchronous ERC-4626 shares or underlying; transfers must be exact |
| Aave Stata | AaveV3StataAdapter | Static aToken shares on supply, USDC on redemption |
| Morpho V1 | MorphoV1SteakhouseAdapter | Steakhouse USDC V1 shares or USDC on chain 31350 |
| Dolomite | DolomiteDUSDCGuardedAdapter | dUSDC or USDC, subject to receiver and implementation checks |
| Uniswap V3 | UniswapV3ActionAdapter | Output from one pair, fee tier and swap direction |
| Action plan | FuyuPlanAdapter | Final output of up to four immutable swap or ERC-4626 steps |
| Async redemption | AsyncRedeemTicketAdapter | Tickets on request, underlying on claim, shares on refund |
| Settled payments | FuyuPaymentCreditAdapter | Backing assets redeemed 1:1 from settled credits |
Put the route and amounts in the proof#
The proof commits to the adapter, operation, input token and amount, output token, minimum output, settlement owner tag, deadline and actionData. The ordinary routes described here require actionData to be zero. The owner tag is a hash used to recover the settlement, rather than a wallet address. The Pool also stores the adapter runtime code hash under the publisher's route key.
Keep amounts in integer token units from quote to proof. USDC with 6 decimals and a vault share with 18 decimals need different conversions. Calculate minOut in the output token's units, apply the user's slippage choice and show the formatted minimum before asking them to proceed. Reject a floor that rounds to zero; these adapters require a positive output.
// Common Pool-only adapter callback.
// This interface does not authorize a private spend.
function execute(
uint8 operation,
uint256 amountIn,
uint256 minOut,
uint256 deadline,
bytes32 actionData
) external returns (address tokenOut, uint256 amountOut);Quote, prove and reconcile#
First check the chain, Pool runtime and domain, asset catalog, adapter runtime and enabled route. Save the quote's block number and hash. The API, browser worker and relay each check the route. The browser uses the selected RPC for its checks, so the API response cannot approve itself.
Refresh the private scan before selecting notes. Reserve those inputs while the operation is in progress so another tab or action cannot reuse them. Recheck the venue, output and available capacity at the head, then check quote expiry again after proving. If submission loses its response, look up the public action identifier and receipts before releasing the notes or preparing a replacement.
The default router executes Stage 1 and Stage 2 in one transaction. In a two-stage flow, ActionQueued means the output is reserved; ActionFinalized followed by a scan makes it spendable. Show those states in the app. A completed quote, a completed proof and a mined first transaction are useful progress, but each leaves work before the user can spend the output.
Check what moved#
The adapter pulls only the authorized input, uses its configured venue and sends output to the Pool. Both contracts compare balances before and after the call. An existing donation must stay outside this user's output. Reject partial pulls, transfer fees, incorrect venue return values, leftover tokens and unexpected allowances.
If the venue reverts, the deadline expires, a contract identity changes or output falls below minOut, Stage 1 rolls back and the input note remains unspent. A valid quote can still fail at inclusion because price, utilization, pause state, receiver permissions or a proxy implementation changed. Handle that failure as a retry from unspent inputs, after checking whether an earlier submission landed.
Explain visibility and the fallback exit#
External DeFi calls reveal the venue, token pair, amounts, intermediate calls and timing. Note ownership stays in Fuyu's private state under the protocol's privacy assumptions. Unusual amounts, public controllers, gas funding and network metadata can still connect activity. Show this exposure before the user generates a proof.
If a vault route is revoked, a supported share token can still leave through an ordinary screened withdrawal. The destination receives shares and handles redemption itself. Check asset admission, route admission and recipient permissions separately. For tickets, also check whether the app exposes the withdrawal path: a contract-level exit alone does not give the user that button.
Where to add the integration#
Put the callback in contracts/src/adapters, quote and relay checks in apps/privacy/runtime, and the browser's pre-proof checks in apps/privacy/src/crypto. The app calls prepareQueuedAction and proveQueuedAction through CryptoClient. These are repository APIs; there is no published general-purpose DeFi npm SDK. Version route schemas and deployment settings with the release that loads them.
Test input/output accounting, slippage failures, contract changes, allowance cleanup and recovery from a fresh private scan. Run funded fork and browser campaigns on Linux. Record the source revision, artifact hashes, fork block and receipts for the venue you are adding; the existing test files cover their own fixtures.
// Repository interfaces; args must already contain the authenticated quote,
// selected noteIds, snapshot, deployment pins and required review manifest.
import type { QueueActionPrepareArgs } from './crypto/types';
import type { CryptoClient } from './crypto/client';
export async function proveReviewedAction(
client: CryptoClient, args: QueueActionPrepareArgs,
) {
const prepared = await client.prepareQueuedAction(args);
const proven = await client.proveQueuedAction(prepared.operationId);
return proven; // Locally proven; no transaction has been submitted here.
}