# Connect to Fuyu Open a private account, connect a wallet and check which approvals you need. Source: https://docs.fuyu.xyz/quickstart/connect ## Before you start Your Fuyu account holds the secrets used to find notes and prove that you own them. An Ethereum wallet handles public transactions and, if configured, extra spending approvals. Connecting that wallet does not open your private account or authorize every payment. Open the app and check the selected network. Its Pool, receiving directory and proof files must come from the same deployment. Use a supported development deployment for this walkthrough. > **Development keys**: The protocol uses development proof keys. Production key generation, an independent audit and mainnet support are still outstanding. ## Open an account Choose a passkey or paper recovery. A passkey uses your browser's authenticator to open the account; paper recovery uses your recovery words. Accounts registered independently can also have optional recovery through their original wallet. Save and test your recovery method before adding funds. Keep paper words offline. Use the access test to make sure your passkey opens the account you expect, then connect a wallet when a transaction needs it. ![Open an account diagram](https://docs.fuyu.xyz/diagrams/recovery.svg) ## Which key does what? | Authority | What it does | When you need it | | --- | --- | --- | | Passkey or paper words | Opens your private account keys | Find notes, prove spends and recover history | | Original wallet A, when configured | Controls the public account record and optional recovery | Update the account record or recover through that wallet | | Spending wallet B, when configured | Approves spends of controlled notes | Collect EOA, Safe or supported ERC-1271 approval | | Relayer or your transaction wallet | Submits the transaction | Settle the prepared operation onchain | ## Before adding funds Check the receiving address and make sure your funding wallet is on the same network. If the account uses a spending controller, check who can approve it now. Recovering your account keys will not remove that approval requirement. Next, follow Get Funds. Send a small payment first and check that the recipient can recover its note. --- # Get Funds Deposit supported assets from a wallet or receive them through a Portal. Source: https://docs.fuyu.xyz/quickstart/get-funds ## Choose a deposit method Fuyu records your private balance as notes backed by assets in the Pool. Create a note through the app's deposit flow or a verified deposit Portal. Do not send a plain token transfer to the shared Pool: that transfer carries no note commitment to identify your deposit. Use the assets listed for your deployment. Check contract addresses and token decimals, even when you recognize the symbol. A test token can have the same name as a mainnet asset. ![Choose a deposit method diagram](https://docs.fuyu.xyz/diagrams/asset.svg) ## Deposit from a wallet Select an asset and amount. Check the public funding wallet and private receiving account, then approve the requested token allowance and deposit transaction. The deposit reveals its sending wallet, asset and amount onchain. Wait for confirmation, then let the account sync its history. A Pending deposit may need coverage under the current source policy before an ordinary screened spend can use it. The wallet losing tokens is only the first part of this process; you also need to recover the note. - Use the token amount and network shown in the deposit review. - Keep the transaction hash until the account recovers its note. - Track confirmation, Pending-note eligibility and spendable balance separately. ## Receive a plain transfer Use a deposit address from the receiving flow for an exchange withdrawal or a wallet that only supports token transfers. Its Portal associates the incoming transfer with an invoice and encrypted recipient delivery. A keeper or another caller then credits it to the Pool. Before paying, check that the Portal is deployed and that the token and amount fit its invoice. Address prediction alone is not enough. Save the recovery file if the flow provides one so you can finish the payment after an interruption. ## Check your private balance Sync account history and look for the recovered note matching the credit. If collection or recovery is still pending, check that payment's status before starting another deposit. The sponsored keeper pays collection gas. You still pay the network fee for your external transfer or your exchange's withdrawal fee. If you complete collection from your own wallet, you pay its gas and that wallet appears publicly as the submitter. --- # Send Your First Payment Send a private payment and check the recipient's note and your change. Source: https://docs.fuyu.xyz/quickstart/first-payment ## Choose a recipient Open Send and enter the recipient's private receiving address or another receiving route the app supports. The private address includes the public keys needed to encrypt the recipient's new note. They can recover it when they next open their account. For an unregistered 0x wallet, choose the claim-link or public payment flow. Those flows use different approvals and reveal different information from a payment to a private address. ![Choose a recipient diagram](https://docs.fuyu.xyz/diagrams/payment.svg) ## Review the payment Check the asset, amount and destination, including the fee and any controller approval. The browser selects your notes and proves that you own them, that they belong to the note tree and that the payment conserves value. It creates the recipient's output and your change without sending note secrets to the relayer. Each input note is spent in full. If you pay only part of its value, the remainder becomes a new change note. Leave the browser open while it proves, and save the operation's recovery state before sharing its authorization. ## Submit and wait for confirmation Send the prepared operation through the relayer or a direct-wallet path supported by the app. The Pool checks the proof and approvals, records the consumed nullifiers and appends the outputs. The receiving account decrypts the delivery and checks that its note matches the recorded commitment. Check the transaction receipt and account history after submission. If HTTP times out, look up the original transaction and its nullifiers before retrying. The transaction may already have succeeded. ## Check the result Look for your change note and the recipient's payment note. Their private openings hide the recipient and amounts, but the transaction still publishes commitments, nullifiers and submission timing. For your first test, use two accounts you control on the same development deployment. Open the recipient in a fresh browser and check that it finds the payment without using the sender's local data. > **Keep the original authorization**: Cancelling in the UI does not revoke a proof you have already shared. Check whether it can still execute before preparing another payment from the same input notes. --- # Networks & Environments Choose a network, connect your wallet and check which Fuyu deployment you're using. Source: https://docs.fuyu.xyz/quickstart/networks ## Choose your environment Start by choosing a Fuyu deployment. The wallet's EVM support is only part of the setup: you also need the chain ID, Pool address and domain, contract runtime hashes, receiving directory, account registry, allowed assets, approved routes and proving files for that deployment. Check that these settings belong together before preparing a transaction. Ethereum Sepolia is the public development environment. For integration work, the protocol repository also includes a disposable fork of Ethereum mainnet state. That fork copies a historical snapshot into a private chain with its own funds and receipts. Transactions you submit there stay on the fork. The public API currently lists Sepolia as its only supported chain and provides no public local-fork endpoint. | Environment | Chain ID | Use | Availability | | --- | --- | --- | --- | | Ethereum Sepolia | 11155111 · 0xaa36a7 | Public development payments, accounts and configured DeFi routes | Public API configuration observed on 2026-10-02; development keys | | Disposable mainnet-state fork | 31350 | Application and adapter tests against a repeatable fork | Run on Linux; read addresses from the generated config | | Sepolia-state fork | Read the harness output | Test a Sepolia deployment against copied venue state | Private test setup on a separate chain | | Ethereum mainnet | 1 | Production Ethereum assets | Mainnet is unavailable in the current app profiles | | Other EVM testnets and L2 networks | Deployment-specific | Port with its own contract and venue checks | No supported Fuyu profile or contract list in this release | ## Check which deployment the app uses The API and source use different Pools in the 2026-10-02 snapshot. The [public configuration](https://api.fuyu.xyz/api/queue/config) returns `0x83CE32c83913c4637A635c997B161ecCA732c97B`. The source revision used for these guides selects `0x8AF98425649a9b9581eAA1E70F25Bab18b2E79Ce` for its active Sepolia profile. We found contract code at both addresses through an independent RPC. Each Pool has its own domain, directory and account registry. The public app's build metadata returned source SHA `ced91a5aba786d76c92c17b7718a6048e8a4ee94` during the check. The new source profile therefore isn't enough to tell you what the hosted app is using. Compare the two sets in the [contract address reference](/infrastructure/contract-addresses). Before funding or signing, check that the app's compiled settings match the configuration it receives. > **Keep the deployment settings together**: Check more than the chain ID. The directory, registry, adapters, deployment bundle and recovery files must belong to the selected Pool. If the app rejects a configuration, find the mismatch and use a matching release before continuing. ## Add Sepolia to a wallet Add Sepolia with your wallet's Ethereum network settings, then switch to it. EIP-1193 requests use a hexadecimal chain ID; most wallet settings show the decimal value. Sepolia uses ETH with 18 decimals to pay gas, whichever token you deposit into Fuyu. The app's network setup uses independent public RPC providers. For ordinary wallet use, a provider needs recent balances, receipts and transaction submission. Account recovery also needs historical contract logs, canonical block hashes and state starting at the deployment block. Check historical access before choosing a recovery node: an endpoint that works for a wallet transaction may restrict older data. ```typescript await ethereum.request({ method: 'wallet_addEthereumChain', params: [{ chainId: '0xaa36a7', chainName: 'Ethereum Sepolia', nativeCurrency: { name: 'Sepolia Ether', symbol: 'ETH', decimals: 18 }, rpcUrls: ['https://ethereum-sepolia-rpc.publicnode.com'], blockExplorerUrls: ['https://sepolia.etherscan.io'], }], }); await ethereum.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: '0xaa36a7' }], }); ``` ## RPC providers and recovery The app source lists the public endpoints below. Each provider sets its own quotas and may block requests from some networks. Tenderly worked during the documentation check. Three other listed providers returned HTTP 403 from the verification machine; check them from your own browser before deciding whether you need another endpoint. Scan historical events in small log ranges and limit your retries. Before validating a deployment, record the chain ID and anchor block. Check the anchor hash again after the scan. If the chain reorganized, reconcile the affected notes or settlements before treating them as final. Your RPC operator can see the addresses and block ranges in these requests. | Endpoint | Source use | Operational consideration | | --- | --- | --- | | https://ethereum-sepolia-rpc.publicnode.com | Wallet network setup | Recent wallet state; provider limits apply | | https://rpc.sepolia.ethpandaops.io | Wallet setup and recovery | Listed in the app for historical recovery reads | | https://sepolia.gateway.tenderly.co | Recovery | Independent reads succeeded on 2026-10-02 | | https://11155111.rpc.thirdweb.com | Recovery | Use smaller log ranges for history scans | | https://api.fuyu.xyz/rpc | Hosted app RPC gateway | Use an independent node when recovering during an outage | ## Handle a network or Pool change Use the chain ID and Pool address in cache keys for notes, prepared operations, checkpoints and receiving records. A proof is bound to its Pool domain, and the balance you recover belongs to that Pool. Keep this separation even when a user opens accounts on both Pools with the same access method. Pause the review if the connected wallet switches networks. Reload the selected configuration and check its contracts, then request a new quote if the route needs one. Keep any authorization you've already released with its original intent and deployment so you can reconcile it there. Switching networks must not rewrite an authorization that could still execute on the original Pool. ![Handle a network or Pool change diagram](https://docs.fuyu.xyz/diagrams/architecture.svg) ## Porting to another network The core deployment script accepts EVM network profiles. To serve a new public deployment, you'll also need an app build that accepts it, runtime admission checks, artifact hosting, a source-policy schedule, a relayer signer and reviews of the external venues. Check every network's token addresses and proxy implementations; matching symbols don't make mainnet, Sepolia and L2 contracts interchangeable. Create a fresh deployment manifest for each port and run its contract, runtime and browser acceptance checks. Publish the chain settings and recovery bundle before opening it to integrations. Ethereum's [network reference](https://ethereum.org/developers/docs/networks/) explains which testnets suit application development and which suit validator testing. You'll still need a Fuyu deployment on the network you choose. --- # Use the Sepolia Testnet Get test funds, check your Sepolia deployment and send a private payment. Source: https://docs.fuyu.xyz/quickstart/testnet ## Prepare a test account Use Ethereum Sepolia, chain ID `11155111`, for public Fuyu development. Open the app and compare its selected Pool with the API configuration and contract reference. Follow the deployment difference described on the Networks page and confirm that the app and API agree before funding a new account. Create a private Fuyu account using one of the available passkey or recovery methods. Save its recovery material and test that you can reopen the account before adding funds. Your connected external wallet funds or submits public transactions. Your private account holds the secrets used to discover notes and prepare proofs. You'll use both during this test. Set up two Fuyu accounts for a private-payment test. After settlement, recover the receiving account in another browser session. That lets you check encrypted delivery and history recovery without relying on the sender's cache. > **Development setup**: This configuration uses test-only proof keys, an empty deny-list source classification and single-owner development governance Safes. Use test assets when trying the flows below. ## Get Sepolia ETH for gas Request test ETH for the external wallet that will submit deposits or direct withdrawals. Wait for the faucet transaction to confirm, then use the app to deposit into Fuyu. Until you make that deposit, the ETH remains in the external wallet and won't appear as a private balance. Find Sepolia faucets in the [Ethereum network reference](https://ethereum.org/developers/docs/networks/). Options include [Alchemy](https://www.alchemy.com/faucets/ethereum-sepolia), [Google Cloud](https://cloud.google.com/application/web3/faucet/ethereum/sepolia) and the [Sepolia PoW faucet](https://sepolia-faucet.pk910.de/). Each provider has its own eligibility rules and rate limits. Google Cloud asks you to sign in, and the PoW faucet requires computational work. Check the provider's current page before requesting funds; avoid building a fixed faucet amount into your integration. Leave enough ETH outside the Pool to pay for your next wallet transaction. A private ETH note cannot pay the gas of a transaction sent by your external wallet. Supported relay operations can have their submission gas sponsored. If you submit directly, your wallet needs a public ETH balance for gas. ## Identify test assets by address The hosted configuration checked on 2026-10-02 lists native ETH, Aave test USDC, Aave test WETH and a static Aave WETH share. Fuyu identifies native ETH with the zero address; it has no ERC-20 contract. Independent chain reads found code for the other assets, with hashes matching the configuration. This release uses Aave's Sepolia WETH test token at `0xC558…9a3c`. The earlier generic Sepolia profile uses WETH9 at `0xfFf9…6B14`. Read the full address in the selected deployment before funding. The symbol WETH won't tell you which token you have, and a mainnet or different Sepolia USDC token isn't automatically accepted. | Asset | Sepolia identity | Decimals | How to obtain or use it | | --- | --- | --- | --- | | ETH | Native currency · protocol sentinel 0x0000000000000000000000000000000000000000 | 18 | Sepolia ETH faucet; fund gas or use the app's native deposit | | USDC | [0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8](https://sepolia.etherscan.io/address/0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8) | 6 | Request from the Aave Sepolia faucet, then check the token address | | WETH | [0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c](https://sepolia.etherscan.io/address/0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c) | 18 | Request from the Aave Sepolia faucet; this is the release's wrapped asset | | stataEthWETH | [0x162B500569F42D9eCe937e6a61EDfef660A12E98](https://sepolia.etherscan.io/address/0x162B500569F42D9eCe937e6a61EDfef660A12E98) | 18 | Use the approved Aave share route; its underlying is the WETH above | ## Get the supported ERC-20 test tokens Open [the Aave interface](https://app.aave.com), enable testnet mode and choose the Sepolia V3 market. Use its Faucet tab to request the asset you need, as described in Aave's [testing guide](https://www.aave.com/docs/aave-v3/smart-contracts/testing-and-debugging). Once the request confirms, check the token's contract address and balance in your wallet. After getting tokens, check the route you plan to use. A faucet can mint tokens while a vault has no room for more deposits or a swap lacks liquidity. Request a current quote and read the preflight result. The older USDC static-aToken deployment plan recorded zero deposit capacity; use the active WETH route's settings rather than substituting that USDC venue. ## Verify the network before funding Read the configuration and compare it with the chain before sending a transaction. This example uses the protocol repository's ethers version to check the chain ID, runtime hash and Pool domain against the API response. Also compare those values with the release manifest or app build you trust; the API must not get to choose your trusted contracts by itself. Tenderly supplied the independent RPC reads for the documentation check. Expect public endpoints to throttle some requests. Limit your retries, and stop to resolve a failed read instead of skipping the contract check. ```javascript import { ethers } from 'ethers'; // repository: ethers 5.8.0; run as an ES module const config = await fetch('https://api.fuyu.xyz/api/queue/config') .then(response => { if (!response.ok) throw new Error('Configuration unavailable'); return response.json(); }); const provider = new ethers.providers.JsonRpcProvider( 'https://sepolia.gateway.tenderly.co' ); const network = await provider.getNetwork(); if (network.chainId !== 11155111 || config.chainId !== network.chainId) throw new Error('Wrong chain'); const block = await provider.getBlockNumber(); const code = await provider.getCode(config.poolAddress, block); if (code === '0x' || ethers.utils.keccak256(code) !== config.poolRuntimeCodeHash) throw new Error('Pool runtime mismatch'); const pool = new ethers.Contract(config.poolAddress, [ 'function domain() view returns (uint256)', 'function VK_HASH() view returns (bytes32)' ], provider); if ((await pool.domain({ blockTag: block })).toString() !== config.domain) throw new Error('Pool domain mismatch'); console.log({ chainId: network.chainId, pool: config.poolAddress, block }); // Next: compare every identity with your trusted release manifest. ``` ## Test a deposit, payment and withdrawal Start with a small deposit through the app. For an ERC-20, check and approve the requested spender and allowance before depositing. If you are testing a plain transfer, use the Portal flow and verify its address and invoice. A regular token transfer to the shared Pool won't create the private note you need. Wait for the deposit transaction and history scan. Check that your note has been recovered and can be spent under the source policy. Send it to your second private account and confirm the sender's change. Open the receiving account independently to check the credited note. Then withdraw to an external wallet and compare the public token amount with the amount you expected. Keep the transaction hashes and operation records until recovery finishes. If submission times out, look up the original transaction and nullifiers before retrying. An HTTP success tells you the request was accepted; you still need to check the mined transaction and recover the private balance. ![Test a deposit, payment and withdrawal diagram](https://docs.fuyu.xyz/diagrams/payment.svg) ## Troubleshoot testnet setup Find the step that failed, then check the corresponding state below. Look up an existing deposit or payment before starting another one so a recovery delay doesn't become a duplicate transfer. | Symptom | Check | Next action | | --- | --- | --- | | Wallet asks for another network | eth_chainId and selected app chain | Switch to Sepolia and reopen the review | | Token balance is absent | Token contract address and decimals | Get the token listed by the selected deployment | | Deposit mined, private balance pending | Recovered note and effective policy coverage | Sync the original operation and follow its pending state | | Quote unavailable | Allowed route, capacity, liquidity and contract settings | Resolve the quote error before proving | | RPC history read fails | Log-range limits and deployment-block access | Use a suitable independent RPC with smaller ranges | | Deployment mismatch | Pool, domain, runtime hash and artifact manifest | Match the app and configuration before funding | --- # Passkeys and backup access Add a second passkey, test it, and remove a lost credential without leaving earlier funds exposed. Source: https://docs.fuyu.xyz/quickstart/passkeys ## What your passkey opens A Fuyu passkey decrypts the seed of your private account. Every added passkey opens that same account, address, balance and retained earlier keys. To unlock it, the browser asks you to verify yourself and uses the WebAuthn PRF extension to derive a decryption key. The passkey belongs to the website where you registered it and the provider that stores it. A credential created on one host may not open the account on another. Keep the account's 24 Fuyu recovery words separately and test that backup before you rely on it. Choosing a phone or security key in the browser tells it your preference; it does not certify that device's compatibility. ![What your passkey opens diagram](https://docs.fuyu.xyz/diagrams/recovery.svg) ## Add a backup passkey Open Account settings → Passkeys after unlocking a published account. Save the backup on a different device or with another passkey manager when you can. That way, losing your everyday device need not lock you out. - Choose a phone or tablet, security key, or this device and its passkey manager. Give it a name you will recognize. - Confirm an existing passkey. If you opened with paper recovery, enter the account's recovery words. Fuyu checks the account and earlier keys. - Create the credential, then verify yourself again with that new passkey. Wait for Fuyu to confirm it opens the same keys. - Review the passkey name and the wallet saving the update. Save with the required wallet or Safe approval, then check the saved list. ## Save the account update Creating a credential in your passkey manager is the first step. It starts working with the account after you save the encrypted account update. If you discard a checked draft, the manager may still show its credential. Delete that unused entry in the manager yourself. If the wallet declines before broadcast, you can keep the checked draft and try saving it again, or discard it. If submission is uncertain, check that update before sending anything else. Another device may have changed the account in the meantime; reopen its latest record before adding access. A Safe-owned record needs its owner approvals, and configured wallet B still has to approve. | State | What to do | | --- | --- | | Verified, unsaved | Save the checked draft or discard it | | Safe approval pending | Continue collecting approvals for this update | | Submission uncertain | Check the existing update before another write | | Recovered with wallet A | Set a replacement passkey, then add a spare | | Saved | Test it; no transaction is needed | ## Test a passkey and give it a name Choose Test a passkey and select a saved credential in the browser. Fuyu checks that it opens this account and every retained earlier key. The test sends no transaction and keeps your account open. Selecting the wrong credential fails the test without switching accounts. Names in the Fuyu list are saved in this browser. The chosen name also appears in the provider's registration prompt, but it is never published onchain. Another browser may show neutral names. The encrypted wraps determine access, not the labels. An account can hold at most 16 wraps; a long key history can lower that limit because the full profile must fit within 2,048 bytes. ## Remove a passkey and protect earlier funds Removal changes the private key and receiving address. Check each remaining passkey, write the new 24 recovery words and complete the word checks. Then save the removal with the account's required approvals. The new words also recover earlier keys, so replace your paper copy before continuing. Update wallet-address receiving if it points to the old key, replace old receive links and portals, and choose Protect earlier funds. This privately moves available notes to the new key. A Safe must approve those moves at its owner threshold. Waiting settlements, unreadable history or earlier funds that have not moved keep the task unfinished. Fuyu keeps the last passkey; add another before removing it. > **Replace old receiving instructions**: Removing a passkey cannot erase keys it already learned or old ciphertext. It may still read earlier activity. Money sent to an old address needs another move to the new key, so share the new address and replace old links and portals. ## If a passkey does not work If the browser or authenticator lacks PRF support, try another compatible combination or use paper recovery. Some authenticators return PRF only when you sign in, so a second prompt immediately after creation is normal. If you chose a credential for another account, cancel and select the saved one you intended. Keep browser data if local storage or the saved removal record cannot be read. Resolve that problem before making another access change. After a reload, open with a remaining passkey or the new words and resume Protect earlier funds. A payment arriving at an old key can reopen that task after an earlier check finished. --- # Build on Fuyu Add private payments, asset operations and recovery to your application. Source: https://docs.fuyu.xyz/build ## What you can build Fuyu stores funds in a shared Pool. Your client proves spends and encrypts recipient notes; the chain settles them. Applications can also use approved adapters for public venue calls while keeping the result in private notes. The protocol checks note ownership and value conservation. Your application handles its service logic and interface, chooses a deployment and stores the data needed to resume interrupted operations. ![What you can build diagram](https://docs.fuyu.xyz/diagrams/architecture.svg) ## Choose a starting point | Feature | Use it for | Result | | --- | --- | --- | | Private payments | Pay a private receiving account | A recipient note and any private change | | Payment links | Get paid from external or unregistered wallets | Portal credit or a controlled claim | | Batch payments | Payroll, multi-recipient sends and consolidation | Spends that each authorize their own inputs and outputs | | Asset operations | Use approved swap and vault routes | A measured output note or private ticket | | Disclosure | Let a holder choose to prove an account fact | A verified answer to a supported question | | Recovery | Change devices or finish an interrupted operation | Recovered state and the original authorization | | Swaps and Earn | Hold tokens or shares through approved venues | The tokens or shares actually returned | | Migration | Withdraw from a source into Fuyu | A new note on the same chain, with public linkage | ## Show the next action Track drafts, prepared proofs and pending approvals through submission, confirmation and note recovery. If a submission times out, show that its outcome is unknown. Two-stage actions also need a reserved-output state and a way to finalize it. A payment status view can use public transaction records. Keep private witnesses on the holder's device; the backend does not need a plaintext account history to report transaction status. ## Start with one payment Choose one supported asset and deployment. Send a payment, confirm its transaction and recover the recipient's note in another browser. Once that works, add controllers, more routes or service billing. Use the guides below to check what each flow needs. An adapter's presence in the repository is not a supported route on every network; availability comes from the deployment you are integrating. --- # Private Payments Pay a private receiving address and return any remaining value as change. Source: https://docs.fuyu.xyz/build/private-payments ## How a payment works A private payment spends existing notes and creates new ones. Each note has a commitment to its asset, amount and owner, along with the fields that define its spending rules. The proof shows that the sender knows the openings of notes in an accepted note-tree root and that the outputs preserve their value. The Pool records a nullifier for each spent input. It can reject a second spend without revealing which commitment was consumed. The sender encrypts each new note for its recipient, who can find it later in public delivery data. ![How a payment works diagram](https://docs.fuyu.xyz/diagrams/payment.svg) ## What the proof authorizes The proof covers the payment the user reviewed, including its destination, outputs, fee and public execution context. Someone else can submit that proof, but cannot use it to change the recipient or redirect the fee. Save the prepared request and controller signatures for retries. The existing proof remains bound to its original chain and deployment. If you switch deployments, prepare a new payment and collect its approval before submission. ## Inputs and change A spend supports at most two input notes and two output notes. It uses one asset, and its inputs must share a controller. A payment can use two notes when one is too small. If the balance is split across more notes, consolidate them or build an ordered router sequence first. Display the token amount alongside any USD estimate. Prices can change what the interface shows and what the relay charges. The spend still accounts for the actual token units. | Data | Where to keep it | | --- | --- | | Note openings and spend secrets | The holder's device or encrypted backup | | Proof and public inputs | Relay submission and onchain verification | | Encrypted output delivery | Public history that the client authenticates | | Plaintext private balance | The holder's recovered account state | ## What is public Note openings stay private under the protocol's cryptographic assumptions. Observers can still see proof submissions, commitments, nullifiers, timing and any nonzero public fields. A payment submitted directly from the payer's wallet also reveals that wallet as its sender. Deposits and withdrawals publish additional information. Controller calls and network traffic can add links too. Describe those facts in the payment flow so users know what the private transfer hides. --- # Payment Links Get paid from an external wallet or send a claim link to an unregistered recipient. Source: https://docs.fuyu.xyz/build/payment-links ## Choose a link type A receiving link helps a payer create a destination for their transfer. A Portal checkout collects that transfer into a private account. A claim link instead contains a secret for a controlled note that a named wallet can claim. Check the network and contract route encoded in the link before asking for funds. Its label or display name cannot tell you whether the destination has the setup required to collect a payment. ![Choose a link type diagram](https://docs.fuyu.xyz/diagrams/payment.svg) ## Open a wallet checkout A Portal link includes its chain, Pool, Portal, invoice domain and setup signer. Before making a wallet request, the browser checks the deployed Portal against its original setup and current invoice, including the token and allowed amount range. Wallet requests use ERC-681 token-transfer syntax. An optional amount is an integer in atomic token units. Opening that URI asks the wallet to review a transfer; the payer must still approve it. ```javascript const { utils } = require("ethers"); const token = utils.getAddress(tokenAddress); const portal = utils.getAddress(verifiedPortalAddress); const amountAtomic = utils.parseUnits("12.50", tokenDecimals).toString(); const uri = `ethereum:${token}@${verifiedChainId}/transfer?address=${portal}&uint256=${amountAtomic}`; // Only display after authenticating the Portal, invoice and asset. console.log(uri); ``` ## Claim or refund a payment A claim note commits to a controller descriptor. Before its deadline, the named recipient wallet can authorize the spend with an ECDSA or ERC-1271 signature the controller accepts. From the deadline, the sender's one-time refund signer can authorize its refund. Keep the claim secret out of analytics, support logs and screenshots. Read the note's balance from authenticated Pool history when reviewing a payout; an amount written in the link is only a hint. ## Finish an interrupted payment For a Portal, distinguish the transfer arriving at the address, its credit reaching the Pool and the account recovering its note. Anyone with the published invoice data can complete that credit. The sponsored keeper normally does it for the user. For a claim paid to a public wallet, save the approved gross balance, payout, fee and recipient together with the proof and signature in encrypted recovery storage. If submission times out, check the claim window and resume that saved authorization. --- # Batch Payments Pay several recipients or combine small notes in one router transaction. Source: https://docs.fuyu.xyz/build/batch-payments ## When to batch Payroll or a multi-recipient payment can need several spends. The router submits them in order without taking custody. Each spend carries its own proof and authorization for its inputs and outputs. You can also use a sequence to combine small notes of one asset into fewer, larger notes. This makes a fragmented balance easier to use for the next payment. ![When to batch diagram](https://docs.fuyu.xyz/diagrams/payment.svg) ## Build the proof sequence A later proof can use the root created by an earlier spend in the bundle. Read and authenticate the starting chain state, then calculate each append in order when building those proofs. Older accepted roots do not make a wrongly calculated future root valid. Refresh chain state before constructing the sequence, and use the recorded output commitments when recovering its result. ## Submission and partial progress The router can execute its sequence atomically in one EVM transaction. Once you share the bundle, however, anyone who sees it can submit a component proof separately because the Pool accepts each valid spend on its own. Design every component to be safe on its own. Do not rely on publication forcing the whole bundle to land together. Recovery must identify the components that already executed and those still pending. ## Review and recover a batch Before proving, show each recipient and amount, the recipient count, total value and controller approvals. Show progress for multiple proof steps, then save the bundle before submitting it. If submission times out, check the component nullifiers and recovered outputs. Continue only from the steps the chain has not consumed. - Give the batch one stable operation reference. - Store each component proof and its transaction hash. - Check that each spend's inputs use the required asset and controller. - Recover the final change and the outputs for every recipient. --- # Asset Operations Swap assets or enter vaults through approved routes, then recover the output in private notes. Source: https://docs.fuyu.xyz/build/asset-operations ## Call a public venue An action sends private value through an approved adapter and sets the private owner of the result. A swap can return another token; a vault deposit can return shares. The venue call and its amounts are public. The Pool measures the tokens returned and checks the minimum in the proof. Before proving, show the input amount and route, along with the expected output and the least output the user agrees to accept. ![Call a public venue diagram](https://docs.fuyu.xyz/diagrams/asset.svg) ## When the output becomes spendable The immediate entrypoint runs the action and appends its output note in one transaction. The two-stage path reserves the output first and lets anyone finalize its note later. Both paths execute the same authorized action. Show reserved value as pending until its note is appended. If the action succeeds but finalization stops, offer Complete settlement using the receipt from authenticated public history. ## Add a route The publisher admits tokens and routes. A route fixes the adapter, operation and asset pair. Before enabling it, review the adapter code, external dependencies and proxy implementations, including how the tokens transfer and any venue restrictions. The repository has specific Uniswap, Aave Stata, Morpho, Dolomite and ERC-4626 integrations. Other vaults need their own review. Native-token DeFi and arbitrary adapters are outside these routes. | Position | What the account holds | What to show | | --- | --- | --- | | Vault share note | Share-token units | Underlying value is an estimate; redemption depends on the venue | | Asynchronous ticket note | A transferable ticket claim | When harvest or redemption is available | | Reserved action output | Value waiting for finalization | It becomes spendable after note finalization | ## Withdrawal and recovery Test ordinary withdrawal of the held token or shares separately from the venue's redeem call. Removing permission for new actions should not remove the holder's original Pool exit. Async ticket adapters have their own harvest and refund steps. Show the venue's pending state and how to continue from it. A ticket can represent a later claim even when underlying assets cannot be withdrawn immediately. --- # Swaps Use an approved Uniswap route and receive the returned tokens as a private note. Source: https://docs.fuyu.xyz/build/swaps ## How a swap works The adapter takes private input and calls the public swap venue. The action sets who owns the resulting private note. The Pool measures the returned tokens and reverts if they fall below the user's minimum. The repository includes Uniswap V3 adapters for individual directions and multi-step plans. The default historical fork routes swap USDC and WETH. Look up your deployment's catalog to find which pairs and Uniswap versions it actually serves. ![How a swap works diagram](https://docs.fuyu.xyz/diagrams/asset.svg) ## Review the quote Choose the input amount, output token and an admitted route. The quote reads one canonical block and checks the router, factory, pool and token identities against the route's configuration. Show its expected output separately from the minimum that the proof will enforce. Price and liquidity may move after quoting. If the minimum cannot be met, execution reverts and the input stays unspent. Getting a new quote does not revoke a proof you already shared. | Review item | Check | | --- | --- | | Input | Atomic amount and token address | | Output | Supported token and display precision | | Route | Admitted adapter, operation and swap direction | | Minimum | The output floor approved after choosing slippage | | Fees | The authorized relay fee and any venue fee | | Account | Private result owner and any controller | ## What the adapter can call The V3 adapter accepts an exact-input swap only from its Pool. Deployment fixes its direction, router and pair; users cannot pass arbitrary router calldata. The adapter returns tokens to the Pool, clears the temporary allowance and checks the balance changes. The WETH route swaps an ERC-20. It does not add native ETH, LP provision or arbitrary pool selection. A new pair or dependency needs publisher review and admission. ## Recover the output Immediate settlement appends the measured output within the swap transaction. For two-stage settlement, finish the reserved receipt's append before showing the result as spendable. Recover the output note from authenticated history. The quoted amount and venue event help explain the swap, but the account needs its own validated note before it can spend the result. ## If route identity changes Stop submission if the router, adapter or token no longer matches the approved configuration, or if the route is no longer admitted. Keep the original notes available. Changing venues requires another user review. Test withdrawal of the output token separately from swapping it back. WETH can leave the Pool as WETH without reverse-swap liquidity, subject to the token working and the chain processing the withdrawal. --- # Earn & Vault Positions Supply assets to a vault, track your private shares and use its redemption path. Source: https://docs.fuyu.xyz/build/earn ## Hold vault shares A vault action exchanges an underlying ERC-20 for fixed-unit shares. The Pool measures the shares received and creates a note of that asset. The note records the share quantity; the amount of underlying it can redeem depends on the vault. Show estimated underlying value separately. Share prices and redemption capacity can change even though the number of shares in the note stays the same. ![Hold vault shares diagram](https://docs.fuyu.xyz/diagrams/asset.svg) ## Supported vault adapters The repository has an Aave Stata route, a curated synchronous ERC-4626 path and adapters for specific Morpho and Dolomite venues. Each route identifies its asset pair, contract code and dependencies. A vault needs admission even if it implements ERC-4626. The fixed-share adapter requires synchronous output and fixed units. It rejects arbitrary calls, rebasing shares, fee-on-transfer tokens and asynchronous withdrawals that cannot return measured tokens before execution ends. | Position | Held asset | Before redeeming | | --- | --- | --- | | Aave Stata or fixed-share vault | Nonrebasing share-token units | Check liquidity, receiver rules and current dependencies | | Fuyu Earn Flex | fyFLEX vault shares | Check yield fee and share price | | Fuyu Earn Term | fyTERM shares until withdrawal request | Request withdrawal into the applicable ticket series | | Pending async redemption | Private fungible tickets | Wait for harvested value or refundable shares under the adapter rules | ## Fuyu Earn Flex and Term FuyuEarnVault uses its configured venue in two ways. Flex is an ERC-4626 share with a yield fee above its high-water mark. Term receives the configured boost and uses tickets for timed withdrawals. Returns depend on the venue and its accounting rules. A Term withdrawal burns shares for fixed-value tickets in one of eight weekly series. The documented window starts four to five weeks after the request and lasts three weeks. Missing it means waiting for the next cycle. Check your deployment's timers and backing before requesting a withdrawal. ## Supply, redeem or withdraw shares The proof covers the supply or redeem route, amount, minimum and private result owner. Use operations admitted by the publisher and backed by a separately reviewed manifest. Quote checks, the proof worker and relay must all use that same route configuration. An ordinary withdrawal gives the public recipient share tokens. To receive underlying assets, they must redeem those shares with the venue. Removing a Pool redeem route should leave the original share-token exit available. ## Before enabling a vault Check for venue upgrades, pauses and available liquidity. A preview from an earlier block cannot tell you what can redeem now. Test the full Pool transaction as well as any maxRedeem check. The integration reports cover test or disposable-fork deployments. A production listing still needs venue review and acceptance on the deployment that will hold the funds. > **Show what the account holds**: List shares, tickets, estimated underlying value and redemption timing separately. Only describe an amount as immediately withdrawable when the corresponding redemption is available. --- # Withdrawals & Exits Withdraw to a public wallet and recover any private change after confirmation. Source: https://docs.fuyu.xyz/build/withdrawals ## Withdraw private notes A withdrawal spends notes into a public recipient. Its proof covers the payout asset and amount, any private change and the relay fee. The Pool checks ownership and value conservation before sending the funds. The payout asset, amount and recipient are visible onchain. If you submit from your own wallet, that wallet is also visible as the transaction sender. ![Withdraw private notes diagram](https://docs.fuyu.xyz/diagrams/payment.svg) ## Review the net payout Check the chain and recipient, token amount, fee and change. With vault shares, this sends shares to the public recipient; redemption into underlying assets is a separate operation. Controlled notes need their controller's current approval. For a full-balance withdrawal, the payout and fee must fit the note's value. Show the net amount the recipient will receive before signing. ## Submit from a wallet The direct withdrawal module runs without the relay API. It takes a locally checked proof and the user's approved terms, then checks the chain, deployment block, Pool code and verifier. It also checks the root, nullifiers and reserves and simulates the calldata before returning a wallet transaction plan. Save the proof and a durable operation marker before the wallet prompt. Once the wallet returns a hash, keep the marker until you reconcile that transaction and recover any private change. | Path | What you need | | --- | --- | | Relayed ordinary payout | Current relay fee policy and transaction status checks | | Direct wallet payout | Wallet gas, simulation of the submitted calldata and a saved attempt marker | | Controlled-note payout | Current EOA, Safe or supported ERC-1271 approval | | Share-token exit | A checked public recipient and working token transfers | ## Reveal a Pending deposit's source This exit consumes one whole Pending deposit and publishes its original source and amount. The holder chooses the payout recipient separately; it need not be the depositor. Source disclosure carries no regulatory verdict. The path uses a separate proof layout and requires the user to acknowledge the disclosure. Offer it as a choice, not an automatic fallback for an ordinary screened withdrawal. ## If submission times out Check the original transaction against authenticated Pool history. Seeing unspent nullifiers now does not always mean a submitted transaction can never land. Retain its authorization until reconciliation resolves the attempt. The direct module is a test path. To recover without the service, you also need the current deployment identity and authenticated static app and proof files. Check those before relying on this route during an outage. --- # Migrate to Fuyu Withdraw from another privacy protocol into a new Fuyu note on the same chain. Source: https://docs.fuyu.xyz/build/migration ## How migration works Migration withdraws assets to a receiving contract, which deposits them for your selected Fuyu account. It creates a new note. Source commitments, keys and proof systems remain with the source protocol, and its anonymity set stays separate from Fuyu's. The source withdrawal and Fuyu deposit are publicly linkable. They must settle on the same chain. A mainnet withdrawal cannot fund a Sepolia destination through this flow. ![How migration works diagram](https://docs.fuyu.xyz/diagrams/asset.svg) ## Source routes The catalog contains tuples for Tornado Classic, Privacy Pools v1 and v2, current zk.money Oxide and legacy zk.money or Aztec Connect. Each tuple describes a particular source deployment. Check whether its client can execute the intended withdrawal before offering the route. Availability is checked per route. Native assets, token denominations and source fees need different receipt checks. Async releases must reach Ethereum first, and historical wrapper shares need handling in their own units. | Source family | Check before withdrawal | | --- | --- | | Tornado Classic | The denomination and authorized recipient and fee | | Privacy Pools | The version's processor, proof files and receipt checks | | Current zk.money Oxide | Whether its executor can release the intended asset | | Legacy Aztec Connect | Whether the historical client and recovery work and value reaches Ethereum | | Wrapper-share outputs | Share units and support for any separate underlying conversion | ## Prepare the destination Select the Fuyu account and final asset. Review the net value, source fees, gas, public linkage and recovery address. Save an intent identifying the destination Pool, owner commitment, receiver terms and block used for that review. Deploy the receiver and verify its creation receipt before displaying its address to the source client. Keep source notes and credentials in that client; the Fuyu API should not receive them. ## Complete the deposit Follow the source transaction until its assets arrive at the receiver. Complete the Fuyu deposit, check its profile, policy and note events, then wait for the selected account to recover the note. That recovery marks completion. Save the full journal before any wallet prompt. Wrong tokens, late transfers, cancellations and remainders must remain recoverable through the receiver's saved terms. They can go only to the fixed recovery address or private account specified there. ## Before offering a route Live source-funded acceptance is still incomplete. Each source route needs a compatible Fuyu destination, a deployed receiver factory and a successful withdrawal through the actual source client, followed by Fuyu note recovery. If a prerequisite is missing, explain it before asking the user to withdraw. A protocol name in the catalog alone is not enough to enable migration. > **Check the receiver before withdrawing**: Verify the deployed receiver and its destination terms before using its address in the source wallet. Opening that wallet submits nothing; the flow finishes when the Fuyu account recovers the deposited note. --- # Multi-step Action Plans Combine approved swap and vault steps into one action with a final output minimum. Source: https://docs.fuyu.xyz/build/action-plans ## How a plan works A plan adapter executes a deployed sequence of external steps under one private action. It can combine supported swaps and vault conversions. The Pool authorizes the plan through its input asset, final output asset and adapter. Plans are curated test routes. Their targets and calldata choices are set at deployment; the caller cannot build an arbitrary route at runtime. ![How a plan works diagram](https://docs.fuyu.xyz/diagrams/asset.svg) ## What deployment fixes Deployment sets the ordered steps, token chain, targets, market identities and guards. planDigest commits to that configuration. The publisher admits its adapter, operation and asset tuple with the adapter's runtime hash. The proof covers the input amount, final minimum and output owner. A relayer must use the deployed steps; it cannot replace an intermediate market. ## Supported steps A plan has at most four steps. They can be Uniswap V3 exact-input single-hop or bounded multihop swaps, or ERC-4626 deposits and redemptions. Tokens throughout the path are distinct. Each step must consume and return the quantities the adapter measures. The user approves one final output floor. If later steps are deterministic vault conversions, the adapter can work backwards from it to derive earlier floors. For other intermediates, the final output check determines whether the action succeeds. | Step type | Measure | | --- | --- | | V3 exact-input swap | Output tokens returned by the configured path | | ERC-4626 deposit | Shares minted for the next step | | ERC-4626 redeem | Underlying assets returned to the next step | | Final step | Output received directly by the Pool | ## If a step fails A failure reverts the entire action, including reserve changes and consumed nullifiers. The adapter reports which step failed because of short output, changed identity, a missing floor or a venue revert. Before returning successfully, it checks its starting balances, Pool token deltas, cleared allowances and contract identities. The output then follows immediate or two-stage note settlement. ## Quote a plan Approve the manifest's digest through a separate review, not by trusting the same API response that serves it. Quote and proof preparation must check every dependency and capacity at a consistent block and use the final minimum the user approved. All venue calls and intermediate amounts are public. Executing them in one transaction helps with atomicity; it does not hide the market activity. --- # Selective Disclosure Prove a supported fact about your account without sharing its private history. Source: https://docs.fuyu.xyz/build/disclosure ## Choose a question The holder imports an FPL question about their notes or spend records. The audit compiler turns it into a plan, then the holder's device generates a proof. Private account data stays on that device. The current backend proves positive upward claims, such as holding at least an amount or participating in matching transactions. The compiler rejects questions it cannot prove. A local preview can help the holder review a question, but it is not a verified answer. ![Choose a question diagram](https://docs.fuyu.xyz/diagrams/disclosure.svg) ## Ask the holder to review Before proving, show the question itself, its subject and snapshot, asset, filters, threshold and expiry. The holder decides whether to answer. Importing a question does not give its author continuing access to the account. The current holder-run flow has no server auditor session or viewing-key service. FPL can describe standing grants, but that language feature is separate from this per-program consent flow. ## Verify the answer independently The auditor uses their own trusted deployment data and verification keys. They rebuild notes, spent nullifiers and spend records from complete finalized history, compile the same program and check the holder's proof chain. Start reconstruction at the deployment block and continue through the selected finalized snapshot. A wallet scan checkpoint may omit history and cannot serve as the auditor's source of truth. | Claim | What the proof says | | --- | --- | | Holdings at least a threshold | Owned unspent notes meet the amount and filters at the snapshot | | Received or deposited amount at least a threshold | Matching notes meet a supported positive bound | | Trade or withdrawal participation | The account owned an input to matching transactions; amounts are their public totals | | Complete ancestry or exhaustive history | The current audit compiler rejects these questions | ## Read what the proof says Questions in one program share an account tag, which tells the verifier that their answers concern the same subject. A different program uses a different nonce-bound tag. Within its supported capacity, the proof hides the selected note commitments and nullifiers. A spend-record proof shows that the account participated in the transaction. It does not attribute the transaction's entire public amount to that account. Keep that qualification in results and exported reports. > **Test keys**: These audit relations use test-only keys. Production keys and independent security review are still required. --- # Account & Payment Recovery Reopen your account or finish an interrupted payment using its saved authorization. Source: https://docs.fuyu.xyz/build/recovery ## What you can recover Account recovery restores the keys that find and spend your notes. Payment recovery restores an unfinished operation's request, proof and approvals. You may need both after changing devices or losing browser storage. Public history contains transactions that reached the chain. Keep encrypted local or service backups for drafts and signatures that have not been published; the chain cannot reconstruct them. ![What you can recover diagram](https://docs.fuyu.xyz/diagrams/recovery.svg) ## Reopen an account Use a saved passkey, paper recovery words or the optional original-wallet recovery configured for the account. The latest profile includes earlier key generations, so rotating a key does not require moving all old notes. To add a passkey, first confirm existing access. Create a different credential, test it with a fresh assertion and save the account update. To remove one, complete revocation; deleting its browser label leaves the credential's access unchanged. ## Continue a saved operation Load the saved operation and check its transaction, nullifiers, controller and expected outputs. Finalize a reserved action receipt. For an unbroadcast claim, restore the saved proof and signature before the user chooses to retry. After a timeout, keep the original request available until you know its chain status. Avoid preparing another spend of the same notes while the first could still execute. | State | Next step | | --- | --- | | No transaction and retained draft | Review and continue the saved request | | Submitted hash, no final receipt | Check that transaction and its chain state | | Input nullifiers spent | Recover outputs rather than resubmitting | | Action receipt reserved | Finalize its recorded output | | Required spending controller unavailable | Restore controller access; account keys cannot replace its approval | ## Use your own recovery tools The recovery design uses a static bundle whose hash identifies its contents, plus your choice of RPC. Keep the app and proving files with the deployment data and account recovery material. That gives you the tools to reopen the account during a service outage. If you submit directly from a wallet, it pays gas and appears publicly as the transaction sender. Explain that cost and wallet link before offering direct completion or exit. --- # Safe Treasuries Use private notes that also require approval from your Safe. Source: https://docs.fuyu.xyz/build/safe-treasury ## Proof and Safe approval A Safe-controlled note requires a private spend proof and the Safe's approval. The note commitment includes its controller, and the Pool checks the controller when the spend executes. Account access alone cannot authorize it. The Safe's own rules determine the required owners and threshold. Fuyu adds no minimum owner count or threshold of its own. ![Proof and Safe approval diagram](https://docs.fuyu.xyz/diagrams/architecture.svg) ## Fund and approve a spend Use the supported Safe funding flow. Check the Safe address, token, amount, receiving account and deployment. Prepare the proof on the holder's device, then collect the owner approvals for that request. Owners should see the destinations, amounts, route and fees before signing. Show their quorum status separately from wallet connection and account recovery so users know which approval is still missing. ## Check the current Safe rules Safe owners, thresholds and modules can change. Check the current authorization at execution and keep the original request while co-signers are reviewing it. A signature collected before a policy change may no longer work. Check the operation's chain state and show which approvals are needed under the new policy. ## Recover a controlled account Back up account keys and operation drafts in addition to owner signatures. A fresh browser should find the same controlled notes, then obtain whatever approval the Safe currently requires to spend them. The repository reports software flows tested on disposable forks. Test the hardware, mobile browser and deployed Safe you intend to support as well. - Show recovered note ownership and Safe approval as separate states. - Test direct funding, co-signing and recovery on your deployment. - Check a pending profile update before asking owners to approve a replacement. --- # Fuyu features Find the guides for account setup, payments, DeFi, approvals and recovery. Source: https://docs.fuyu.xyz/build/features ## Start with your private account Open a Fuyu account to scan its notes and prepare proofs in the browser. The account holds encrypted access material and receiving keys for one Pool. Your funding wallet, recovery wallet and spending controller each have a separate job. When someone connects a wallet, keep the private account they already opened. The same notes can fund a payment, a swap or an Earn deposit. What happens next depends on the asset: receiving vault shares gives you shares, and you redeem them separately to get the underlying token. Recovering account keys restores access to notes. You still need to pass source checks, meet venue conditions and collect any controller approvals. ![Start with your private account diagram](https://docs.fuyu.xyz/diagrams/architecture.svg) ## Choose a guide Start with the task you want to build. Then check that your network enables the required assets, routes and contracts, and that your app build allows transactions. | Task | Feature | What to check | | --- | --- | --- | | Open or recover an account | Passkeys, paper words and optional wallet A recovery | Choose account access separately from funding and spending approval | | Receive payments | Full private addresses, configured names and wallet receiving registration | Look up the descriptor and check it again before sending | | Pay someone without a Fuyu account | Recipient-bound claim link | Use the named wallet and explain the deadline and public claim terms | | Pay several people | Private sends, batch payments and Combine | Check input limits and save pending authorizations | | Use DeFi | Swaps, Earn, enabled vault routes and action plans | External calls are public; check settlement before crediting outputs | | Require another approval | Wallet B or the supported Safe-controller flow | Ask the controller to approve this operation under its owner policy | | Reconcile activity | Authenticated timeline and encrypted recovery files | Check history coverage; a suffix is not a complete ledger | | Answer an audit request | Holder-run proofs and independent verification | Get the holder's consent and finalized evidence for a supported positive claim | ## All feature guides The feature IDs below come from the product specifications. They cover account setup, receiving, payments, DeFi, approvals and recovery. Each link opens the guide for that task, including the network requirements and what to do when a step cannot continue. | Feature IDs | Task | Guide and requirements | | --- | --- | --- | | ACC-01, ACC-08 | Account settings and saved operations | [Account recovery](/build/recovery) · check the account revision and pending update | | ACC-02, ACC-03, ACC-04 | Passkeys, paper recovery and key rotation | [Passkeys and backup access](/quickstart/passkeys) · move earlier funds after changing keys | | ACC-05, ACC-06, ACC-07 | Account recovery, accounts without wallet A and earlier accounts | [Recovery](/build/recovery) · choose the account and keep its earlier keys | | ACC-09 | Browser wallet and WalletConnect | [Connect to Fuyu](/quickstart/connect) · keep account access and wallet roles separate | | APR-01 | Approval wallet B | [Spending approvals](/build/spending-approvals) · use B's EOA or supported contract signature | | APR-02, APR-04, APR-05 | Safe owner review, passkey owners and saved proposals | [Safe approvals](/build/spending-approvals) · use a supported Safe deployment and owner types | | APR-03 | Safe treasury funding | [Safe treasury](/build/safe-treasury) · check allowance, account and owner threshold | | RCV-01, RCV-02 | Receiving names and wallet-address registration | [Receiving](/build/receiving) · configure a name registry; 0x registration is public | | RCV-03, RCV-04 | Reusable deposit addresses and deposit options | [Receiving](/build/receiving) / [Get funds](/quickstart/get-funds) · check portal limits and recovery terms | | PAY-01, PAY-02 | Send and claim a recipient-bound link | [Claim links](/build/claim-links) · use the named wallet, respect its deadline and save recovery | | PAY-03 | Public escrow for an unregistered recipient | [Claim-link alternatives](/build/claim-links#public-escrow-alternative) · requires a separate escrow deployment; all payment terms are public | | PAY-04, PAY-05 | Batch payments and Combine | [Batch payments](/build/batch-payments) / [Asset operations](/build/asset-operations) · check router support and input limits | | PAY-06 | Send options and contacts | [Private payments](/build/private-payments) · check the recipient; contacts stay in this browser | | DEFI-01, DEFI-02, DEFI-03 | Earn venues, Flex/Term and tickets | [Earn](/build/earn) · check routes, share tokens and claim windows | | DEFI-04 | Async vaults and tickets | [Asset operations](/build/asset-operations) · check whether this test-only route is enabled | | DEFI-05 | Ordered action plans | [Action plans](/build/action-plans) · use the fixed adapter and final output minimum | | DEFI-06 | Swaps | [Swaps](/build/swaps) · check pair, quote, fee and minimum output | | DEFI-07 | Two-step action settlement | [Asset operations](/build/asset-operations) · finalize reserved outputs after execution | | WDR-01, WDR-03 | Wallet withdrawals and their options | [Withdrawals](/build/withdrawals) · check the public recipient, token and net payout | | WDR-02 | Source-revealing exit | [Withdrawals](/build/withdrawals) · the deposit source becomes public | | OPS-01, OPS-02, OPS-03, OPS-04 | Earlier operations, interrupted sends and attention states | [History and reconciliation](/build/history) · check the original operation before retrying | | CMP-01 | Source screening | [Get funds](/quickstart/get-funds) · wait for deposit age and publisher coverage | | CMP-02, CMP-03, PRF-01, PRF-02, PRF-03 | Audit questions, programs, answers and verification | [Disclosure](/build/disclosure) · use supported holder-run proofs and the matching request | | SYS-01 | Encrypted backups | [Recovery files](/build/recovery-files) · saves history and included pending journals | | SYS-02, SYS-03 | RPC setup and recovery without the service | [Infrastructure recovery](/infrastructure/recovery) · use a checked RPC and the deployment's recovery artifacts | | SYS-04 | Exit an earlier Pool | [Recovery](/build/recovery) · older accounts can restrict funding and new actions | | V5-not-live | Unavailable pages and design placeholders | [Deployment checks](#check-your-deployment) · a visible page does not mean bridge, borrowing, membership or equity transactions work | ## Set up access and receiving The app can create a Passkey plus paper-recovery account, a paper-only account, or an account with optional wallet recovery when the deployment supports it. Several passkeys can open the same account and earlier keys. Removing one requires a key change and moves to protect earlier funds. Include new receiving instructions and late payments to old keys in your recovery flow. The full private address works without a name. Names need a configured registry, while receiving through a 0x wallet address requires a public registration. Reusable deposit addresses accept ordinary wallet or exchange transfers under fixed invoice terms. Choose the method that fits the payer, and explain what it publishes and how uncredited money is recovered. ## Build payments, streaming and DeFi Private send creates encrypted outputs for the recipient. Claim links let a named wallet claim before a deadline, even if its owner has no Fuyu account. Batch payments put several proved steps into the configured router flow. [Payment-session streaming](/integrate/streaming) uses signed cumulative vouchers and the session-payment core. If your app schedules private sends instead, it must handle timing, balances and approval for each send. For DeFi, choose an enabled adapter and the input/output asset pair it supports. The proof includes the input, minimum output, execution context and controller. A two-stage action needs a later append of its reserved outputs; a one-transaction action settles them together. Check route admission, liquidity and withdrawal windows before offering a venue. An adapter in the repository may still be disabled on your network. ## Recover interrupted work and review disclosure Save pending authorizations in encrypted storage before they leave the browser. If a wallet, relay or page stops responding, look up the original operation in authenticated history. Keep checking an unknown result. A second proof can leave two authorizations able to spend the same inputs. Audit answers need a separate review. The holder reads the questionnaire, checks what it reveals and generates supported proofs locally. A payment, receiving name or balance does not grant access to private history. Anyone receiving an exported answer should verify it against the request and finalized snapshot. ## Check your network before funding Open the contracts and testnet guide. Match the chain ID, Pool address, domain, deployment block, runtime code and proof artifacts. Check token support, action routes, name registry, relay fees and Safe support for that Pool. These guides cover the client and protocol implementation. Feature availability is set by the deployment: a read-only preview cannot transact, a disposable fork is a test environment, and a feature may need additional configuration on the public app. Mainnet deployment, physical-authenticator certification and independent audit status need their own release records. Check those records before choosing a production environment. --- # Receiving names and addresses Choose a private address, name, registered wallet address or deposit portal for your payer. Source: https://docs.fuyu.xyz/build/receiving ## Choose how you want to receive Open Receive to copy your full Fuyu address or an available receiving name. The address contains the public descriptor a sender needs to encrypt a payment to you. It gives no spending access. Show its address check so the payer can compare it with you through another trusted channel. A private address belongs to one Pool domain and key generation. Sharing it reveals a receiving identity, but not your balance or owned-note list. Wait until the account and recovery record are ready before sharing. After a key change, share the new address and keep access to earlier keys for payments already on their way. | Method | Use it for | What becomes public | | --- | --- | --- | | Full fuyu1 address | Another Fuyu sender | The descriptor and any identity you connect to it | | Configured @name | A name people can read and share | Name ownership, descriptor and address updates | | Registered 0x wallet address | A payer who knows your wallet | The wallet's permanent association with its receiving descriptor | | Reusable deposit address | An exchange or ordinary wallet transfer | Source, token, value and portal terms | ## Choose a receiving name This client reads names from an immutable onchain registry configured in the frontend. It checks the chain, Pool, domain, registry runtime, deployment block and settlement-token code. If the registry is missing from the manifest, names are unavailable. There is no HTTP-directory fallback; you can still use your full address. Choose an available two-word name or a handle made of letters and digits. Two everyday words are free. One rare word costs $2 and two cost $10. Handles cost $10 for 7–20 characters, $50 for 5–6 and $300 for 4. Shorter or reserved names are unavailable. These prices exclude transaction gas. Check the deployment's quote before buying. > **Names need a registry on your network**: The client implements onchain name registration. To enable it, a network needs a deployed registry and its configuration in the frontend manifest. A fork setup or older offchain-directory guide cannot confirm that names work on another network. ## Register a name and finish its checkout The app commits your name claim, waits until it can be revealed and checks the registration result. Your connected wallet confirms the registry transactions and pays gas. Paid checkout uses the configured USDC settlement asset and any eligible onchain name credit. Check the name, address descriptor, fee and escrow before paying. The app saves checkout before releasing an authorization. When you reopen it, it reads the purchase from the registry and checks the original payment. It will not send a replacement automatically. If the purchase becomes credit, or a delayed payment reaches its closed escrow, continue recovery and check your credit balance before choosing another name. ## Receive through your 0x wallet address Wallet-address receiving lets a Fuyu sender look up your 0x address and get a private receiving descriptor. Check its registration first. Registering, changing or revoking it needs the owner's typed signature and an onchain transaction. The app provides the ordinary EOA-owner path. The contract can verify other signatures, but the app has no Safe registration interface for this step. Registration permanently connects your public wallet to the descriptor and its controller. Revocation stops new lookups; earlier records stay public, and someone who saved an old address can still pay it. Keep recovery for those earlier keys and check for late payments. RPC providers can see lookups. Use a full Fuyu address if you do not want to publish a wallet association. ## Receive from an exchange or ordinary wallet Create a reusable deposit portal with a token, invoice amount limits, a finite invoice sequence and a fixed public fallback address. Check that you can access it before sharing its Ethereum address. Money transferred to the portal becomes a private note only after an eligible invoice is credited into the Pool. Publish later invoice material if you want someone else to credit payments while you are offline. A wrong token, out-of-range amount, exhausted invoice sequence or disabled token needs the portal recovery flow. Public recovery reveals the fallback address and permanently closes private crediting for that portal. Stop sharing it once it is closed. ## Check the recipient again before sending A name payment page looks up the receiving record when it opens. A pinned link also fixes the management identity, chain, Pool, address check and revision. Before preparing a proof and again before sending it, the controller checks that the record has not changed. If it changed or the lookup failed, review a fresh record. A name identifies where to send money. It does not verify a person's identity, provide account recovery or prove a balance. If the name is unavailable, ask for the full private address through a trusted channel. If registration or payment is uncertain, check the original operation before repeating checkout. --- # Pay wallets with claim links Send to someone without a Fuyu account, set a claim deadline and recover a claim that was interrupted. Source: https://docs.fuyu.xyz/build/claim-links ## Pay someone before they create an account A claim link sends a private note under terms that name a recipient wallet and deadline. Its owner can inspect the payment or claim a public payout without a Fuyu account. Before the deadline, only that named wallet can approve a claim. From the deadline onward, the sender's one-time refund key can authorize a refund. Send the link privately and keep the original. It contains the material needed to inspect the payment and recover an encrypted claim authorization. The app puts it in a URL fragment, which is not included in an ordinary HTTP request. Anyone you give the full link to can still read the payment information it contains, although spending requires the right approval. ![Pay someone before they create an account diagram](https://docs.fuyu.xyz/diagrams/payment.svg) ## Create and send a claim link Open Claim links in your private account. Choose an eligible non-native asset, enter the recipient's full wallet address and set a deadline. Review the amount, change, claim terms and any wallet approval needed. The send accepts at most two input notes. Use Combine first if your amount needs more. Generate the proof, collect wallet B or Safe approval if configured, and submit once. Wait for the app to confirm the payment from Pool history before sending the link. The sender flow requires at least a one-hour margin before the deadline. Copy the funded link to the recipient and keep the sent-link record so you can check it or refund after expiry. ## Check the payment and choose where it goes Open the link in the configured app and connect the named recipient wallet. Choose Check payment in the Pool. The app reads authenticated history to find the funded note; the asset and amount written in the link are only hints. If nothing is found, check whether the sender's transaction has landed, whether you opened the right deployment, or whether the note was already used. Choose a public wallet payout or receipt into an open Fuyu account. A public payout reveals the token, amount and wallet and may deduct a relay fee. Private receipt keeps the output amount private and is sponsored. Public receipt needs a positive net payout. If a fee-tier calculation leaves an extra remainder, you must separately agree to pay it as fee. | Destination | Before claiming | What you receive | | --- | --- | --- | | Named public wallet | Connect and sign with the named wallet | The public net payout after its fee | | Private Fuyu account | Open the destination account and sign with the named wallet | A private note in that account | | Sender refund after expiry | Open the sender's refund authority | The app returns funds privately under the original terms | ## Sign the claim and check its result The browser prepares the proof, then the named wallet signs a typed approval for that claim. The relay can deploy the claim controller and submit it, so the recipient wallet signs without paying those gas costs. Before deployment or submission, the app stores the signed authorization in encrypted local storage. Deploying the controller publishes the recipient wallet, Pool, deadline and one-time refund address. The refund address is not the sender's funding wallet. Recipient and amount stay hidden at the initial private send. Claiming into a private account keeps the output value private; paying a public wallet publishes it. ## Leave time to claim The app refuses a new claim in the last ten minutes before its deadline, leaving time to prove, sign and relay. Retrying a saved authorization requires at least sixty seconds. After the deadline, the recipient cannot claim and the sender can use the refund flow. A claim spends the whole claim note at once, with no change note. After expiry, the sender's refund key can authorize a destination without the original account's wallet B. Explain that authority change if you create claim links from a controlled account. ## Use public escrow when the payment can be public Some deployments also provide a public escrow for an unregistered 0x recipient. It uses money in the connected public wallet rather than private notes. Token allowance, opening, claiming and refunding are ordinary public transactions. The funding wallet, recipient, amount, token, deadline and fixed refund wallet are all public. Only the recipient can claim before the deadline. From the deadline onward, anyone can trigger a refund to the fixed refund address. Keep the payment reference and check chain receipts if opening is uncertain. This flow needs its own deployed escrow, transaction-enabled build and wallet gas. Use a private claim link when you need its privacy properties. ## Recover a claim that stopped midway If submission is uncertain, choose Check claim or refund onchain. Keep checking before making another proof: the original authorization may still execute. The saved-claim review can resubmit its original proof and signature with the same destination, amount and fee. It checks the claim window, controller, Pool and relay fee first. To continue on another device, keep the private link and an exported encrypted pending-claim backup, or enable the optional encrypted backup service. Chain history cannot restore a signature that was never broadcast. If the saved fee no longer covers the relay requirement, the app refuses to retry. It will not change the proof or ask for a replacement signature without a new review. --- # History and reconciliation Read account activity, check pending operations and understand what a history export contains. Source: https://docs.fuyu.xyz/build/history ## Read your activity Activity combines the account's authenticated private scan with public Pool events. It lists deposits, received notes, sends, in-account combines, Swap and Earn actions, and public withdrawals. The app rebuilds the timeline from recovered records, so it need not trust a list of transactions saved in one browser. A send and Combine look the same onchain. Recovered sender and recipient records tell the app which happened. Change belongs to the operation that created it, so the timeline does not show it again as income. An external action's settlement output appears in its action row rather than a second Receive row. ## Check status before counting funds A deposit can appear before it finishes the minimum-age and source-policy checks. An excluded deposit cannot be spent normally. An external action can be confirmed while its settlement output is still waiting to be appended. A saved authorization can still execute after you close its editor. Reconcile with atomic token amounts, not USD estimates. Prices can change even when no note moves. Match the first nullifier or transaction identity to the reserved inputs, public event and recovered outputs. Keep submitted, confirmed and available as separate states in your application. | State | What happened | Next check | | --- | --- | --- | | Deposit checking | Funding landed; eligibility is still being checked | Refresh deposit age and policy coverage | | Action executed, unfinalized | The route ran; outputs have not been appended | Read the receipt and finalize the reserved outputs | | Sender recovery needs attention | The spend is known; its private sender record is missing | Recover keys and history before producing a full-ledger report | | Outcome unknown | The original operation may still execute | Read its saved authorization and chain state | | Spent | The note's nullifier was consumed | Count its replacement output or payout, not the old input | ## Use the public-history cache The queue runtime returns history status and logs for bounded block ranges. It requests every event in a range; it needs no owner, viewing key or list of private notes. Before replaying cached logs, the browser compares them with its canonical RPC response. It falls back to RPC if the cache fails or disagrees. Include spends that create no outputs. A matching note root or block hash cannot tell you whether one of those spends was omitted. Choosing an independent browser RPC bypasses the default same-origin history service. After a reorg, return to a matching canonical anchor and replay the changed suffix. ```http GET /api/queue/public-history/v1/status GET /api/queue/public-history/v1/logs?fromBlock=100&toBlock=199 # Use ranges appropriate to the selected Pool deployment. # Authenticate every returned range against your canonical RPC. ``` ## Know how much history was restored A compact checkpoint saves a canonical tree frontier and absolute counters. The restored public arrays may contain only events after that checkpoint. Check historyCoverage before reading them. A checkpoint-tail array is a suffix, so its length is not the account's lifetime transaction count. The app can display an authenticated private-history projection after refreshing the chain. A consumer that needs complete history, including audit compilation, must request full replay or refuse incomplete coverage. If an earlier key generation is missing, recover it rather than counting its unknown balance as zero. Keep the checkpoint scope, digest, block anchor and key lineage together. ## Export a backup or an audit answer Export encrypted backup file saves scan state and included pending-operation journals so you can continue on another device. The file is encrypted; it is not a public account statement. Audit answer JSON is a separate export for the questions and snapshot you approved. Give the verifier the matching request. The app has no general CSV accounting export, and an arbitrary row list does not prove a complete ledger. If you build a report, say which history it covers and use verified records. Keep token address, atomic amount, transaction hash, block and status in each row. Share private output openings only when the holder approves that disclosure; keep account secrets out of reports. ## If activity and balance disagree Check the account, chain, Pool and key generation first. Refresh canonical history and inspect pending journals. For an executed action, read its measured output and finalization status rather than the old quote. For an uncertain send, check its original first nullifier before preparing another spend. Keep browser storage and export an encrypted recovery file before clearing caches or changing devices. A failed RPC read, unreadable sender capsule or missing earlier key leaves history incomplete. Show the problem and continue recovery. Do not drop the missing rows or mark the account reconciled. --- # Token balances and USD values Keep token amounts precise, separate checking funds and show USD estimates without hiding missing prices. Source: https://docs.fuyu.xyz/build/balances ## Keep balances in token units For each asset, the balance is the sum of recovered unspent notes. Its contract address and decimals define the units. Use integer strings or bigint for selecting inputs, proving and reconciling transactions. Format decimal and USD values when displaying them. A symbol alone cannot identify an asset. Two tokens with the same symbol can have different contracts, policies and redemption rules. Read the deployment's asset metadata and code checks, then use that token's decimals. In the app model, the zero address identifies native ETH. WETH uses its own contract address and remains a separate asset. ```typescript // USDC has 6 decimals in the reviewed asset metadata. const amountAtomic = 12_345_678n; const unit = 10n ** 6n; const whole = amountAtomic / unit; const fraction = (amountAtomic % unit).toString().padStart(6, '0'); const tokenText = `${whole}.${fraction} USDC`; // Keep amountAtomic for transaction logic; tokenText is display only. ``` ## Separate available and checking funds The app shows total, available and checking funds. A known note can still be waiting for deposit age, source-policy coverage or settlement. Checking funds count once in the total, but cannot yet be spent. Also respect the inputs reserved for saved operations when you choose a new spend. A price update changes the USD total without changing token quantities. Finishing a check makes a note available without changing total holdings. Tell the user which happened. An excluded-source deposit needs its documented exit flow; knowing its amount does not make it spendable. ## Where USD estimates come from The display assigns $1 to configured dollar-denominated symbols such as USDC. For ETH and WETH, it reads the configured Chainlink USD feed when that chain has a known feed entry. It rejects zero, negative or nonfinite prices, invalid timestamps and rounds older than two days. Completed display prices are cached for one minute. On a chain without a configured feed, the client can use an eligible USD/WETH swap pair for a spot-price fallback. It will not replace a missing known Chainlink feed with a test pair's price. Yield shares can use convertToAssets when the underlying asset has a price. If the share-rate read fails, that share may remain unpriced. > **USD values are estimates**: Displaying USDC at $1 does not guarantee it will keep that market price. Feeds, pair prices and share rates estimate holdings. Transaction quotes, minimum outputs and fee schedules are separate values; the estimate is not a promise of cash redemption. ## Show missing prices as missing If a positive holding has no valid price, the aggregate USD total is unavailable. The token amount still appears. Otherwise a partial total could hide real money. A zero account with valid reads can show $0; a failed price or unreadable balance must have a different state. Apply this rule in your dashboard: add USD values only when every positive holding included in the total has a price. Show the token or feed that needs attention and let the user refresh. Keep unknown shares in the asset list, preserve their atomic balance and avoid presenting the stablecoin subtotal as the whole account. ## Name the asset the recipient will receive The interface can group ETH-family holdings for display. Transactions still use the selected native or wrapped asset and a supported route. Withdrawing WETH pays WETH unless the route unwraps it. An ETH-equivalent total cannot combine different assets into one spend on its own. Earn shares, Term shares and ticket series are separate tokens with their own decimals and redemption rules. Sending shares gives the recipient shares. Show the venue and token address when needed, and explain how to redeem them, any liquidity requirement and the claim window before approval. ## If the balance looks wrong Refresh the scan and check your Pool and earlier keys. Look at deposit status, pending actions and reserved inputs. A public action may have run before its settlement note is appended. A payment arriving after key rotation can belong to an earlier generation and need recovery or a move to the new key. If only the USD value is missing, check price reads without changing token quantities. Relay fees use the published fee policy; swaps use the execution minimum you approved. Neither uses the dashboard's live display price. Show holdings, price availability and operation status separately. --- # Disclosure consent and policies Review an audit request, share a supported proof and understand what policy grants can do. Source: https://docs.fuyu.xyz/build/disclosure-grants ## The holder decides what to answer To request an audit, supply a readable program with questions about an account at a finalized snapshot. The holder imports it, reads the questions and public effects, then chooses whether to generate supported proofs. A receiving address or control of a service gives you no permission to read private history. The app uses this holder-run audit flow. Its outputs have zero policy attachments, and its audit interface cannot issue, save or revoke disclosure grants. If your application needs standing permissions, the reference policy language describes them separately. Do not show a grant-management workflow as an available app feature. > **Use the holder-run audit flow**: This is the app's supported disclosure flow. Reference policy compilation and historical grant code do not provide a live grant service, automatic history access or a revocation screen. ![The holder decides what to answer diagram](https://docs.fuyu.xyz/diagrams/disclosure.svg) ## Review the audience, questions and snapshot A request names its audience, optional subject, finalized snapshot, expiry and optional nonce. Its questions are closed formulas, not a request to upload unrestricted history. Before answering, check the subject and deployment, then read what each answer reveals under the chosen effect manifest. The audit relations can prove supported positive ownership and spend-history predicates within their limits. If a program contains an unsupported question, the compiler refuses the program instead of answering only part of it. Show Yes or proven, No answer, Refused and verification failure separately. No answer does not mean the predicate is false. ## Generate an answer and share it with the request Open the intended account and finish canonical history recovery before compiling a questionnaire that needs full coverage. Check the finalized block and deployment scope. Run the supported proof plan locally, review the exported answer and share it with the original request. The independent verifier checks the request, proof relation, verification artifacts and snapshot. A proof of a lower bound at an earlier block says nothing about today's balance. It also does not disclose or prove an unrestricted full history. Show the proved claim and its snapshot alongside the verification result. ## How reference policies describe permission In the reference language, a policy gives standing consent. Each permit names one auditor, the capabilities they may ask about and an effect manifest listing the public facts an answer can reveal. Each question must fit one grant. The evaluator cannot take the audience from one grant and the permissions from another. Policies and queries compile into separate plans and digests. A note attachment can bind a policy digest to a per-note secret salt and deployment scope while keeping it opaque onchain. A zero attachment grants no questions in that interpretation. The Pool stores the attachment as bytes; an attachment alone does not admit a request or provide a proof backend. | Artifact or step | What it tells you | | --- | --- | | Reference policy plan | Audience, capabilities, effects and policy digest | | Query plan | Predicates, certification requirements and evidence needed | | Holder audit | The holder consents; the compiler produces a supported plan or refuses | | Independent verification | Whether the answer and snapshot pass checks for that request | ## When the holder changes their mind The holder can decline the next request or stop sharing answers. A recipient may still keep an answer already delivered and the facts it reveals. Check the request's expiry and nonce in the verifier according to its supported rules. Those checks do not promise deletion of a delivered answer. The app has no standing-grant revocation interface. A historical revocation contract may not belong to your release. If you add a policy service, document how its attachments work with proofs, how it checks audiences and stores state, and how revocation is enforced by the independent verifier before offering grants to users. ## Ask for a small, useful proof Ask only for the predicates your product needs and explain why each matters. Let the holder check the audience, subject, snapshot and public effects before generating proofs. Keep the original program with its answer, and provide independent verification to the recipient. If a question is unsupported or history is incomplete, show why it was refused and what can resolve it. A screenshot, self-reported JSON or partial checkpoint cannot replace the required proof. Continue to the disclosure guide for syntax, examples and verifier commands. --- # Spending wallets and Safe approvals Set up wallet B or Safe approvals and resume an operation without changing what was signed. Source: https://docs.fuyu.xyz/build/spending-approvals ## Separate account access from spend approval Account keys let you discover notes and prepare ownership proofs. A spending controller adds an approval requirement when you execute them. Recovering the keys cannot remove that requirement. Decide who approves each operation before asking for signatures. A registered wallet-A recovery account can fix an approval wallet B: an EOA, Safe or another supported ERC-1271 wallet. The app also has a separate Safe-controller workflow that collects Safe owner signatures itself. Choose the flow for your account type; they use different account records and approval collection. | Flow | Account type | How approvals are collected | | --- | --- | --- | | Approval wallet B | Registered account with recovery wallet A | Fuyu accepts B's final EOA or contract-wallet signature | | Safe controller | Notes controlled by a supported Safe | Fuyu shares private review material and imports owner signatures | | No extra controller | Account access authorizes its notes | The holder approves the operation and its submission path | ## Approve with wallet B Choose B while setting up wallet-A recovery. Its address is fixed once setup starts. B approves account configuration, recovery-record updates and spends from controlled notes. The funding wallet supplies deposits. B approves later spending without receiving private account keys. Use the connected wallet, a separate WalletConnect session or an imported signature to approve. The connected wallet must be B. If B is a Safe, its own tools collect owner approvals and supply a final contract signature; this flow does not collect the owners inside Fuyu. Read the app's operation review before signing, since the wallet prompt may show hashes instead of payment details. ## Sign the operation you reviewed The approval covers the Pool and chain, controller, proof, ordered public signals, request, sender capsule and verification-key hash. A different recipient, minimum output, fee or proof needs a different approval. Signing one operation gives no blanket account access. The app encrypts and saves the pending operation before sending a signature request. If remote backup is enabled, it also needs the acknowledgement required by that recovery flow. It checks the signer and contract-wallet rules before continuing. After an interruption, restore the original authorization and inspect it before asking for another signature. ```typescript // The app constructs SafeSpend EIP-712 approval data with this helper. import { prepareSafeSpendApproval } from './safe-approval.ts'; const approval = prepareSafeSpendApproval(reviewedProofContext); // reviewedProofContext includes the exact proof, 39 public signals, // request, sender capsule, chain, Pool and verification-key hash. // Independently verify its private output review before signing. const { domain, types, message, digest } = approval; ``` ## Collect Safe owner approvals For a Safe-controlled account, the initiator prepares a proof and gives owners a private review file or fragment link. The file opens private outputs so owners can check recipients and amounts themselves. Their browser verifies the proof, replays finalized Pool and Safe state and signs its digest. Share the review only with the owners who need it. Import the signatures and check the Safe's owner threshold before submitting. This client supports specified owner types, including plain EOAs and its supported contract-owner paths. Other contract or delegated-code owners may not count. Every batch step needs enough approvals from owners still in the Safe. A removed owner's signature stops counting. ## Check Safe and route support The Safe-controller tools support their configured Safe 1.4.1 contracts on chain 1 and disposable fork chain 31350. They refuse a Sepolia Pool without a supported Safe deployment. Recognizing chain 1 in this code is separate from releasing Fuyu on mainnet. Wallet B uses another external-wallet flow; do not apply the Safe-controller interface's assumptions to it. A route must give co-signers enough material to check its external calls independently. If a route is refused for Safe-controlled notes, choose a supported route. The client offers creation of a Safe passkey signer only on the disposable fork. Other networks and physical devices need separate rollout and compatibility checks. ## Resume a proposal that is still pending A shared proof with enough approvals can execute while its inputs are unspent and its controller and time checks pass. Closing the editor or keeping the proposal does not revoke shared signatures. Its inputs stay reserved; you can use unrelated notes for other operations. If submission is uncertain, check Pool history and Safe state. A changed fee schedule may cause the relay to refuse the original fee without spending the inputs. Do not automatically generate another proof. A canceled local wait, signed authorization and confirmed revert mean different things. Keep the encrypted journal until you know what happened to the original operation. --- # Encrypted recovery files Save history and pending operations, restore them on another device and handle backup conflicts. Source: https://docs.fuyu.xyz/build/recovery-files ## What a recovery file saves An encrypted recovery file saves authenticated scan state and the operation journals present when you export it. It helps another browser resume recovery, approvals or an operation with an unknown result. You still need a passkey, paper words or wallet recovery to open the account. The bundle includes its deployment scope, checkpoints for the active and earlier keys, scan anchors and a public-checkpoint digest. It can also contain separately encrypted Safe proposals, ordinary pending authorizations and account operations. After restoring it, refresh the canonical chain and run the usual controller checks before spending. ![What a recovery file saves diagram](https://docs.fuyu.xyz/diagrams/recovery.svg) ## Export a backup Open the account and finish a verified history scan. Choose Export encrypted backup file in the backup tools. The download is named fuyu-encrypted-recovery.json. Read the saved-backup summary to see whether it includes history, Safe approvals, pending authorizations or account updates. Export again after preparing an important pending operation. An older file cannot contain a later signature or unbroadcast transaction. Store recovery words separately and keep useful older copies until you have checked the new backup. Keep browser storage while an operation still needs reconciliation. ## Restore on another device Open the same account on the same chain and Pool with its access method. If the file includes account operations, select the registered account. For Safe or ordinary pending authorizations, open the matching recovery workflow. Then import the encrypted JSON file; it must fit the importer's size limit. Restore checks the schema, scope, generation identities, encrypted chunks and checkpoint digest. It authenticates and merges journals instead of replacing them with an unchecked approval list. The app checks the unlock-session epoch around asynchronous work, so switching accounts stops the restore. Refresh the canonical chain after importing before using notes or submitting a saved operation. | File contains | What to do after restoring | | --- | --- | | History checkpoint | Check canonical block, contract code and newer events | | Safe proposals and approvals | Open Safe recovery, merge journals and check owners | | Ordinary signed operations | Open their recovery flow and check the original inputs | | Registered-account operations | Select the account and check its registry revision | | Missing earlier generation | Recover the keys and finish replay | ## Use an encrypted backup service Configure a workspace-service URL and choose Enable encrypted backup if you want remote copies. You can host the service yourself. The host sees your IP address, an opaque backup ID, size and update times. It cannot decrypt account recovery state without its keys. Inspect the remote version before restoring or replacing it. When another version needs review, the app reports a conflict and leaves it unchanged. Compare local and remote anchors and pending journals, then choose which state to use. Turning off remote backup does not cancel signed operations or remove copies already held by another device. ## Back up signatures that have not been sent Chain history can recover an operation that landed. It cannot recover the proof and signature of one that never left the browser. Save the encrypted journal before requesting a controller signature, deploying a claim controller or releasing a relay submission. With remote backup enabled, the app can require its acknowledgement before continuing. A restored authorization keeps its proof, destination, amount, fee and original identity. Its inputs stay reserved until the result is checked. Retrying runs the execution checks again. A changed relay fee or expired claim window may prevent submission; restoring a backup does not create a replacement proof. ## If a backup will not restore A scope error usually means the file belongs to another chain, Pool, account or deployment. Open the right account and configuration rather than editing the JSON. Do not bypass a failed digest or malformed encrypted chunk. Keep the original file and use the supported chain-recovery flow if needed. Resolve missing earlier keys, unreadable journals and conflicts between tabs before another write. Open the matching journal recovery, check known outcomes and continue the original operation. If a public checkpoint no longer matches its canonical block, the reader falls back to replay. An imported file still needs that chain check before its state can be used. --- # Gas sponsorship and fee reviews See who pays gas, which operations are sponsored and how fees affect a public payout. Source: https://docs.fuyu.xyz/build/gas-sponsorship ## Who pays gas A relay can submit a Pool operation and pay network gas. A sponsored operation proves a zero relay fee, so receiving a relayed private payment needs no gas balance. Funding, account updates and receiving-directory changes may instead use a connected wallet. Its transaction prompt shows the network fee. The submitting wallet pays gas; the proof identifies where any fee goes. Someone else submitting the proof cannot redirect that fee. A signature is also different from a transaction: a claim recipient signs approval while the relay can pay for controller deployment and settlement. ## Check the fee for your operation The service-fee policy sponsors ordinary private sends, Combine, batches, claim-link sends, private claims and private refunds. Public withdrawals, source-revealing exits and external actions may charge a service fee plus gas in the spent asset. A claim paid to a public wallet uses the withdrawal fee policy. The disposable fork sponsors operations by default when no fee policy is published. A deployment that charges publishes its complete schedule in queue configuration. Read that schedule for your Pool. A fork default or example price is not a quote for the public app. Show both service fee and gas component before asking for approval. | Operation | Fee policy | What it reveals | | --- | --- | --- | | Private send and Combine | Sponsored under the service policy | A zero fee leaves the asset out of fee signals | | Batch and private claim/refund | Sponsored under the service policy | Output values stay private | | Withdrawal or source exit | Tier plus gas when priced | Payout already publishes asset and amount | | Swap, Earn or plan action | Tier plus gas when priced | The input used by the route is public | | Deposit or receiving registration | No Pool principal fee; wallet gas may apply | Funding or registration is public | ## Calculate the fee in the client The client calculates fees with integers and rational values. The example policy charges $2 through $1,000, $10 through $10,000, $50 through $100,000 and $300 above that. Each upper limit is inclusive. Gas is added separately, and the fee rounds upward to whole atomic units of the spent asset. Fee calculations use the schedule's reference prices, not the live USD estimates on the balance screen. For an unpriced share input, a supported action can use its proved minimum output to calculate value. An unpriced withdrawal can be sponsored. Publishing the whole schedule avoids asking the relay about a private asset before the proof exists. ## Show the amount, fee and payout Before proving or signing, show the fee in atomic units and token units, its payee and the net payout. A whole-note withdrawal must satisfy payout plus fee equals note balance. A public claim also spends its whole note and needs a positive payout. The recipient can choose private receipt instead. Near a fee-tier edge, the largest affordable payout can leave more than the schedule's minimum fee. The claim review displays this remainder and asks for separate consent to pay it as an extra fee. Opening the review or choosing a destination does not approve that additional charge. ## What a paid fee reveals The proof includes fee asset and amount in public signals. A nonzero fee on a private spend would publish that asset and fee even though recipient and payment value stay private. The service policy keeps those ordinary private operations at zero. The source also has a test-only per-operation quote path. If you use it in development, check its scope, sponsored flag, cap and stated information exposure, and recompute the fee from the quote inputs. Keep this test interface separate from the production service policy. A paid private fee cannot hide its asset. ## If the fee changes before submission A saved proof may reach the relay after its fee policy changes. The relay can return FEE_TOO_LOW when the saved fee is insufficient. The proof may still be executable through an allowed path; a relay refusal does not spend the notes or cancel every copy of the authorization. Check the original operation and inputs first. Keep its encrypted journal and use the retry or recovery review. Do not automatically prove the same inputs again or alter a fee someone already signed. Tell the user whether you are checking confirmation, retrying the saved operation or asking them to review a new one. --- # Integrate Fuyu Add funded payment rails and service accounting to your application. Source: https://docs.fuyu.xyz/integrate ## What the SDK handles The payment SDK manages funded rails, their lifecycle and a durable payment ledger. You can purchase service credit in increments, charge prepaid periods, reserve a spending ceiling for later capture or distribute settled earnings. Your application supplies resource IDs and prices, computes request digests and carries messages over HTTP or a stream. It also executes the work, handles retries and defines what happens when service delivery fails. ![What the SDK handles diagram](https://docs.fuyu.xyz/diagrams/rails.svg) ## Choose a rail | Rail | Use it for | Authorization | | --- | --- | --- | | Session | Incremental requests and streaming segments | A cumulative purchase voucher and separate signed requests | | Subscription | Prepaid service periods | Onchain charges with paid-through access | | Authorization | Work with a cost known after execution | A signed ceiling, confirmed hold and cumulative capture | | Splitter | Distribute settled earnings | Immutable beneficiaries and cumulative release accounting | ## Choose a funding path A public backend opens a payment from its payer wallet after the user approves the required token allowance. For private funding, the driver predicts an immutable escrow address. The holder separately authorizes a Pool withdrawal to fund it. The rail still publishes its budget, merchant and lifecycle state. The Pool proof protects the funding note, while relaying choices, timing and network traffic can affect how the withdrawal is linked. ## Start with a funded session Give buyer and merchant durable ledgers and configure the chain, contract, asset, merchant, signing authority and budget. Define the request digest codec. The buyer prepares authorizations; the merchant recomputes the requested content and price before accepting them. Add settlement monitoring and restart recovery before serving paid work. The SDK accounts for purchases but leaves provider execution and job deduplication to your application. Use Streaming & Usage Billing for a continuous service. To add an external venue, follow the adapter author guide and submit its route manifest for independent review. > **Bring your own transport**: The SDK has no HTTP 402, Tempo/MPP or vendor adapter. Build your transport around the exported payment interfaces. --- # Payment Sessions Buy service credit in increments and sign each resource request. Source: https://docs.fuyu.xyz/integrate/payment-sessions ## Purchase and request signatures A purchase voucher authorizes cumulative merchant earnings for the session. The merchant claims it to settle onchain. A SessionRequest signature authorizes one resource request, with its ID, digest, price and deadline. Claimed vouchers become public and anyone can relay them. Require the separate request signature to authenticate the customer; seeing a voucher is not proof that a caller can use their credit. ![Purchase and request signatures diagram](https://docs.fuyu.xyz/diagrams/streaming.svg) ## Configure the funded session Session terms identify chainId, core, asset, merchant, voucherSigner, sessionId and maxDeposit. Manager policy sets the service budget, purchase increment, request TTL, expiry and settlement behavior. Each operation checks funded state against that configuration. Use decimal strings in the asset's base units. The budget must fit maxDeposit. Request preparation only creates authorizations and records accounting; token approval, funding and transaction submission happen separately. ## Prepare and accept a request Configure the buyer and merchant managers first. Compute a digest of the resource and request body, then calculate the price from the server's billing rules. Keep the same request ID when retrying the same work. ```javascript // buyer and merchant are createSessionManager(...) instances. const bundle = await buyer.prepare({ requestId: "job-42", requestDigest, amount: "10", }); const receipt = await merchant.receive(bundle, { requestId: "job-42", requestDigest: serverComputedDigest, amount: serverComputedPrice, }); // Use the application's own durable job ledger before executing work. // A repeated debit receipt should resume or return the same job result. ``` ## Settle a voucher The merchant can settle its highest accepted voucher directly or let the manager worker do it. Once closing starts, stop new requests. Existing earned vouchers can still be claimed during the contract's close window. At final closure, unclaimed deposit value goes back to the payer. Signing a purchase authorizes merchant earnings during that claim window. Unused purchased service credit follows the application's refund policy. ## Fund the session For public funding, call openSession on a payer-connected createEthersBackend with merchant, voucherSigner, amount and a fresh salt. Approve token allowance first. The transaction sender is the payer; plain transfers to the rail contract do not open or top up a session. For private funding, use the driver for the deployed factory. Its prepare result gives the withdrawal recipient and amount. Authorize that Pool withdrawal separately, wait for arrival and activate the escrow. Attach the driver to a manager with matching rail, session ID, authority and budget; the SDK does not build the withdrawal witness. ## Save the manager policy Save policy when configuring the session, then reload those values after a restart. expiresAt stops application acceptance. Voucher claimability is governed separately by the core's close window. Each purchase increment authorizes cumulative earnings. For a large reservation where only the measured cost should be captured later, use the Authorization rail. Signed Session purchases do not automatically refund unused service. ```javascript // Example for a reviewed six-decimal asset. Persist this policy once. const policy = { budget: "1000000", // 1 display unit of service purchases purchaseStep: "100000", // purchase in 0.1-unit increments requestTtl: "60", expiresAt: String(configuredAt + 3600), settlementInterval: "30", broadcastTimeout: "300", autoClose: false, autoFinalize: true, }; // terms.maxDeposit must cover policy.budget, and the session must be funded. ``` ## Track purchases and usage The buyer records its signed purchases and reserves budget for prepared requests. The merchant records accepted purchases, debited requests and available service credit. The chain records deposits, claims and closure. Keep those amounts visible with their own meanings. A prepared request keeps its buyer reservation even if it is never delivered. A merchant debit also remains after a provider failure. Store the application job and decide whether to resume it, return cached output or apply your refund policy. ## Claim before the close window ends Stop accepting new work when closing starts. Claim the latest accepted voucher before closeAt. After that boundary, final closure refunds the unclaimed deposit, including signed value the merchant failed to claim in time. Closing cannot revoke earnings already settled. Claims are cumulative: a higher voucher settles only the amount above earlier claims. Check rail state when a competing relayer succeeds; its claim has already changed what remains payable. ## Restart and retry Reopen both original durable stores and recover the managers. Reuse the job ID, content digest and price for the same request. Changed content under that ID fails; an expired request can receive a renewed signature while policy still permits it. The payment ledger deduplicates debits. Your application must also deduplicate provider work. Commit a stable job record and use provider idempotency or cached output for repeated requests, keeping that job associated with its payment receipt. --- # Streaming & Usage Billing Bill a stream in segments and settle its purchases periodically. Source: https://docs.fuyu.xyz/integrate/streaming ## How streaming payments work The application sells service credit in increments and consumes it in units such as tokens, bytes or time slices. The buyer signs increasing cumulative purchase amounts. The merchant periodically claims its highest accepted voucher. The contract needs transactions to settle; it does not send money by itself every second. Your application measures usage and executes the service. A payment does not prove that a model response or other provider work completed. ![How streaming payments work diagram](https://docs.fuyu.xyz/diagrams/streaming.svg) ## Choose a billing unit Define your unit, digest codec and price in the server's billing rules. Give each segment or batch a stable request ID. Its request signature authorizes that resource separately from the purchase voucher. If the unit price is smaller than one atomic token unit, carry the remainder and round at purchase boundaries. Rounding each unit upward overcharges the stream. Signed payment amounts must remain unsigned integers in atomic units. | Record | What it tells you | | --- | --- | | Provider usage receipt | The provider's measured usage claim | | Signed SessionRequest and debit | One resource unit was authorized and debited | | Purchase Voucher | Cumulative earnings authorized for the merchant | | Settled Credit | Value settled and backed by the payment rail | | Pool settlement receipt | Returned assets reserved for a private note | ## Pause and reconnect Pause new billable segments when credit runs out, policy expires or closing starts. Ask for another purchase authorization. If capacity is too small, wait for a separately approved top-up to confirm first. On SSE reconnect, reuse the accepted segment's billing identity. Resume its job from cached output or a saved cursor so a connection failure does not create another charge. ## Accept a segment Wrap the buyer and merchant managers in your transport. The example accounts for one segment. Your application still computes the digest, checks server pricing and keeps a job ledger to prevent repeated execution. ```javascript const requestId = `${streamId}:segment:${segmentIndex}`; const bundle = await buyer.prepare({ requestId, requestDigest: segmentDigest, amount: segmentPrice, }); const debit = await merchant.receive(bundle, { requestId, requestDigest: independentlyComputedSegmentDigest, amount: independentlyComputedSegmentPrice, }); // Commit or resume the durable segment job, then deliver cached/new bytes. // A debit receipt is not proof that delivery succeeded. ``` ## Monitor settlement Leave time to claim before the close window ends, accounting for stale RPC reads, confirmation lag and worker outages. All transports serving one merchant session must share its accounting ledger, including request deduplication records. The SDK has no HTTP/SSE gateway or Tempo/MPP adapter. If you need those protocols, implement and test their challenges, credentials and receipts against the payment backend. Changing a contract address alone will not make them compatible. ## Save the stream state Before the first segment, configure a funded session and saved manager policy, then create a durable stream job. Its ID and segment indices or batch boundaries must survive reconnects. Store the digest and price for each boundary. The buyer authorizes a segment and the merchant checks its content and price before delivery. After the debit commits, save a resumable job state. If delivery then fails, resume that segment rather than assigning it another billing ID. | Phase | Payment state | Application state | | --- | --- | --- | | Ready | A funded open session with saved policy | The stream job is saved | | Prepared | Buyer budget reserved and authorization saved | Content and price set for the segment | | Accepted | Merchant debit committed once | The segment job can run or resume | | Delivered | No additional debit | Output and delivery cursor saved | | Paused | Credit ran out, policy expired or closing began | New billable segments stop | | Settled | The highest accepted voucher was claimed | The service receipt is kept separately | ## Carry fractional charges Meter sub-atomic prices in an agreed finer scale, keeping the remainder until a purchase boundary produces an integer payable amount. Include that scale in the service terms and the request data the server checks. The read-only function below shows that arithmetic. The SDK requires positive SessionRequest amounts, so collect a large enough batch before authorizing it; a zero-priced result from the function cannot be sent as a request. ```javascript function meterBatch({ units, priceNumerator, priceDenominator, remainder = 0n }) { if (units < 0n || priceNumerator < 0n || priceDenominator <= 0n) { throw new Error("Invalid agreed billing scale"); } const scaled = units * priceNumerator + remainder; return { amountAtomic: scaled / priceDenominator, remainder: scaled % priceDenominator, }; } // 3 units at 1/10 atomic unit each retain 3/10 as a remainder. const first = meterBatch({ units: 3n, priceNumerator: 1n, priceDenominator: 10n }); // A later 7-unit batch reaches exactly one atomic unit. const next = meterBatch({ units: 7n, priceNumerator: 1n, priceDenominator: 10n, remainder: first.remainder, }); console.log(next.amountAtomic.toString(), next.remainder.toString()); ``` ## Record usage and purchase terms A provider receipt can include the session, service-terms digest, cumulative units, price and issuer. Its signature confirms the provider's billing claim. The payer still needs to authorize the purchase, and the receipt cannot prove the output was correct. Apply the customer's configured budget and refund terms before each increment. Track unused service credit separately from unclaimed funding. Once a Voucher settles, it is merchant revenue even if the customer has not consumed all the service credit it bought. ## Coordinate workers and shutdown Use the same merchant store to serialize acceptance across stream and API workers. Otherwise, two workers can both see the same credit as available. The chain tracks cumulative Voucher amounts, not which resource request has already used that credit. At shutdown, stop new segments and save active cursors before stopping the settlement worker. Arrange for a supervised process or restart to continue watching the close window. A timer in a stopped process cannot submit a claim, and passing onchain time does not run a keeper. ## Receive settled value privately Settled Credit is an ERC-20 backed by assets in the payment rail. Deposit it through the Pool's existing guarded admission flow to obtain a Credit note. An admitted redemption adapter can return underlying assets to the Pool for a measured settlement note. Create the Deferred Note only from assets actually returned by that route. Usage receipts and future earnings cannot fund it. Shared-Pool route admission and HTTP integration still need their own deployment and funded end-to-end tests; contract tests cover only the contract part. --- # Subscriptions Charge prepaid periods and check whether the current period has been paid. Source: https://docs.fuyu.xyz/integrate/subscriptions ## Set the subscription terms A subscription sets its merchant and refund receiver, amount per period, duration, start, expiry, maximum periods and budget. Each onchain charge pays a period. The manager reports whether access is paid and when that paid period ends. Use that result to decide service access. Your application still issues its sessions, records jobs and handles outages; a paid period cannot show whether the service was delivered. ## Configure a backend Supply a deployment manifest with the chain, core and asset runtime hashes and token decimals. Use the same provider object for the reader and signer. Opening the subscription funds it in a transaction, after the payer approves token allowance. With private funding, the escrow is the payer. It controls cancellation. Use the subscription manager for period access and the funding driver for escrow cancellation and refund forwarding. ![Configure a backend diagram](https://docs.fuyu.xyz/diagrams/rails.svg) ## Charge a period and check access Import the CommonJS exports below from the protocol checkout. The host supplies the deployment manifest, provider, funded terms and durable store used by this example. ```javascript const { createSubscriptionBackend, createSubscriptionManager, } = require("./sdk/payment-sessions/index.cjs"); const backend = createSubscriptionBackend({ ...subscriptionDeployment, provider, signer: payerSigner, }); const subscription = createSubscriptionManager({ backend, store: subscriptionStore, terms: { subscriptionId, ...subscriptionTerms }, }); await subscription.tick(); const access = await subscription.access(); if (access.allowed) console.log(access.paidUntil); ``` ## Cancel or retry a charge For public payer funding, use the manager's cancellation interface. For private funding, call the funding driver: an ephemeral authorization key cannot act as the escrow payer. If a charge times out, read its period state before ticking again. Keep records for paid access, refunded funds and completed service work so you can see which part succeeded. --- # Authorization & Capture Reserve a spending ceiling, then capture the amount the merchant charges. Source: https://docs.fuyu.xyz/integrate/authorization ## Reserve funds before work Use Authorization when the final service cost is known later. The buyer signs a ceiling for a hold. reserve registers it onchain, and the fixed merchant operator can then capture a cumulative amount or void the hold. Wait for reserve to confirm before using the hold as payment capacity. A signature by itself has not locked any funds. ![Reserve funds before work diagram](https://docs.fuyu.xyz/diagrams/rails.svg) ## Use the right request ID Authorization uses nonzero bytes32 request IDs. Session uses nonempty strings. Keep each rail's serialization and EIP-712 domain separate. The authorization identifies the payment ID, merchant and operator, signing authority, refund receiver and maximum budget. Use unsigned integers and set a validity deadline for every hold. ## Create and capture a hold The example starts with a funded authorization payment and its deployment manifest. Final capture settles the cumulative target and releases the unused part of the reservation. ```javascript const { ethers } = require("ethers"); const { createAuthorizationBackend, createAuthorizationClient, } = require("./sdk/payment-sessions/index.cjs"); const backend = createAuthorizationBackend({ ...authorizationDeployment, provider, signer: merchantOperatorSigner, }); const client = createAuthorizationClient({ backend, signer: authorizationSigner, store: authorizationStore, terms: authorizationTerms, }); const requestId = ethers.utils.id("inference-42"); const approval = await client.authorize({ requestId, ceiling: "20", validUntil: String(now + 120), nonce: "0", }); await backend.reserve(approval); await backend.capture(authorizationTerms.paymentId, requestId, "15", true); ``` ## Release the remaining reservation Repeating the same capture target adds no payout. Final capture, void or expiry ends the hold. Payment cancellation returns unreserved value to its fixed refund receiver, while existing holds retain capture rights until they reach a terminal state. Use resume for a registered request and nonce. Do not sign a replacement just because the first submission was interrupted. The contract records the captured payment; your application must separately record service delivery. --- # Settlement & Revenue Sharing Claim earned payments onchain and distribute them to the configured beneficiaries. Source: https://docs.fuyu.xyz/integrate/settlement ## Check what has settled The merchant ledger records accepted credit, debited requests and budget usage. Settlement claims an earned voucher or rail entitlement onchain. Those amounts may differ until a claim confirms. Check the claim transaction and rail state after a service debit. Watch close and expiry deadlines too, since they can end the remaining claim window. ![Check what has settled diagram](https://docs.fuyu.xyz/diagrams/streaming.svg) ## Fund an escrow Configure the funding driver with the factory, rail and asset identities, runtime hashes, decimals, kind, authority, budget, receiver and timers. prepare returns the withdrawal destination and amount. The holder must separately prove and send that Pool withdrawal. Once assets arrive, deploy and activate the escrow. fund is an alias for those steps. It does not move money from a wallet or construct the private spend proof. | Method | Action | | --- | --- | | prepare() | Return the predicted funding recipient and amount | | deploy() | Deploy the configured escrow | | activate() | Activate assets already received by the escrow | | cancel() | Cancel through the funding authority's escrow path | | forwardRefundCredits() | Forward rail refunds to the immutable external receiver | ## Distribute earnings A Splitter pays settled credit or underlying assets to beneficiaries fixed at deployment. Its issuer, mode and shares are immutable. Cumulative release accounting prevents paying the same entitlement twice. Point the SDK at an existing splitter. Deploying it and choosing beneficiaries happen outside this interface. ```javascript const { createSplitterBackend } = require("./sdk/payment-sessions/index.cjs"); const splitter = createSplitterBackend({ ...splitterDeployment, provider, signer: relayerSigner, creditIssuer, creditCodeHash, }); const before = await splitter.status(); await splitter.claim(); // For a splitter deployed in settled-credit mode. // Asset-mode splitters use their separately reviewed redeem/claim path. ``` ## Recover an interrupted claim Save broadcast intent before sending. After a timeout, keep it pending or uncertain and check chain state before retrying. If another relayer claims the voucher first, your transaction can revert even though the payment has settled. A ledger commit, onchain claim and provider job can succeed or fail separately. Use durable job IDs and define how your application resumes failed work or refunds it. --- # Author an Adapter Write a Pool adapter and submit its route for publisher review. Source: https://docs.fuyu.xyz/integrate/adapters ## Add a synchronous venue A synchronous venue may fit the current action interface and spend proof. Its adapter must define asset behavior and permitted calls, check live contract identities and have client and relay drivers. Shared-Pool use also needs publisher admission. You can deploy a separate Pool with your own publisher and routes. That creates separate custody, configuration and privacy set, so test the new deployment rather than inheriting the shared Pool's results. ![Add a synchronous venue diagram](https://docs.fuyu.xyz/diagrams/integration.svg) ## Implement the interface Declare the Pool and accept operation, input amount, minimum output, deadline and one actionData word. The proof covers actionData. If the route needs no parameter, reject nonzero actionData. Allow only the configured Pool to execute. Set the venue and asset pair at deployment, and do not accept arbitrary targets, recipients, spenders, calldata or delegatecall choices. ```solidity interface IFuyuActionAdapter { function privacyPool() external view returns (address); function execute( uint8 operation, uint256 amountIn, uint256 minOut, uint256 deadline, bytes32 actionData ) external returns (address tokenOut, uint256 amountOut); } ``` ## Measure the token movements Consume exactly amountIn, return the actual output to the Pool and enforce minOut. Clear temporary allowances and prevent reentrancy. Leave no extra adapter balance or unexpected change to other Pool reserves; the Pool also checks its token deltas. The interface expects a supported token back before execution finishes. NFTs, delayed multiple outputs, nontransferable debt and rebasing or fee-on-transfer assets need another design. For asynchronous venues, a reviewed ticket can represent pending value if the action actually returns that supported token. ## Prepare the route manifest Describe the chain and Pool domain and runtime, adapter code and route tuple, tokens and decimals. Include external contracts and proxy implementations, identity checks, quote method, capacity and an ordinary exit for the output token. Approve the digest through a separate release review or authenticated publisher. The API serving a manifest cannot grant it permission itself. The publisher must admit tokens and actions onchain; setting a client flag does not do that. ## Test before admission Test supply and redeem, or both swap directions. Exercise short output and changed code, check reserves and allowances, then finalize and recover the result. Test ordinary token or share exit too. Use a disposable fork to change proxies or revoke routes and observe the failure behavior. A route used for spending needs a separate review if its outputs will support disclosure proofs. Record the source revision and deployment identity so the review applies to the code that was tested. - Check the original transaction after a lost response before permitting another spend. - Display share quantities separately from estimated underlying value. - Test ordinary exit after revoking the action route. - List the devices, liquidity conditions, recovery paths and deployments you have not tested. --- # DeFi Integration Connect swaps, vaults and settled payments to private notes. Start with the route, then handle quotes, execution and recovery. Source: https://docs.fuyu.xyz/integrate/defi ## 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. > **Start on the Queue fork**: The default and optional Queue venues run on a disposable Ethereum fork. Before deploying elsewhere, review that network's contracts, publish its addresses and artifacts, and test the complete transaction and account recovery. ![How a DeFi action works diagram](https://docs.fuyu.xyz/diagrams/integration.svg) ## 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. ```solidity // 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. ```typescript // 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. } ``` --- # ERC-4626 Vaults Add a synchronous vault: describe its shares, check its dependencies, register supply and redeem, and keep a share withdrawal path. Source: https://docs.fuyu.xyz/integrate/erc4626 ## Start with assets and shares An ERC-4626 deposit spends an amount of underlying and receives shares. Redemption spends shares and receives underlying. Store the share count as the private balance; display its estimated underlying value separately. Vault accounting can change that estimate, so calculate it from a preview instead of assuming a one-to-one rate. ReviewedFixedShareAdapter connects one Pool to one vault and underlying token. Its recipient and call targets are fixed at deployment. SUPPLY is operation 0, REDEEM is operation 1, and actionData is zero. The original fork runbook uses USDC vaults. The manifest path also supports the Sepolia Aave WETH pair and its native-ETH variant, each through that network's own release configuration. ![Start with assets and shares diagram](https://docs.fuyu.xyz/diagrams/asset.svg) ## Check token behavior and vault permissions Test that underlying and shares transfer the full requested amount and that their balances do not rebase. Check decimals, donation handling, rounding, receiver restrictions, pause controls and direct share transfers. Asynchronous withdrawals, debt positions, transfer fees, reward claims and arbitrary vault calls need a different adapter design. List the vault's proxies and other dependencies. A proxy can keep the same runtime code while changing implementation. Record its storage slot, implementation address and implementation code hash, together with bounded identity calls. If the manifest declares an implementation getter, include it in the adapter's identity pins too. A proxy without such a getter needs a reviewer decision because an adapter cannot read another contract's storage. ## Create the vault manifest The fuyu-queue-erc4626-manifest-v1 manifest names the chain, Pool address/runtime/domain, adapter runtime/guardDigest, tokens, operations, quote policy, ordered code pins and identity calls, display risks and screened share exit. nativeUnderlying: true uses address(0) for native ETH on the Pool side while the adapter trades the configured wrapped token. The parser rejects extra fields and a mismatched digest. Get the digest from your release catalog. The parser canonicalizes the manifest and hashes that value with Keccak-256; a file SHA-256 or runtime code hash is a different value. Keep the guard arrays in order, since the adapter's guardDigest includes their order. Returning a digest beside an API manifest does not make it trusted. ```typescript // Repository helpers from apps/privacy/src/queue-erc4626-manifest.ts import { parseReviewedErc4626Manifest, reviewedErc4626AdapterGuards, reviewedErc4626AdapterGuardDigest, reviewedErc4626RoutePair, } from './queue-erc4626-manifest'; // approvedDigest must come from your reviewed release, not the API. const manifest = parseReviewedErc4626Manifest(rawManifest, approvedDigest); const { extraPins, identityPins } = reviewedErc4626AdapterGuards(manifest); const guardDigest = reviewedErc4626AdapterGuardDigest(manifest); const routePair = reviewedErc4626RoutePair(manifest); // Deploy/review against these ordered guards, then authenticate chain state. ``` ## Check the venue before the vault call The adapter records the chain and Pool, vault and underlying code hashes. Before executing, it checks those hashes, any extra code pins and the expected results of its staticcalls. It then measures input pulled from the Pool and output returned there. The supply allowance is cleared after use. An unexpected transfer, leftover balance or short output reverts the action. The API also checks proxy storage slots, route registration and capacity at a canonical block. The browser repeats the checks before proving, and the relay checks again before submission. This matters for proxies whose implementation is visible through storage but has no onchain getter the adapter can call. ## Check capacity, then estimate the whole action For supply, pair previewDeposit with maxDeposit for the Pool receiver. For redemption, use previewRedeem and either maxRedeem or the manifest's exact-owner diagnostic. A preview gives a conversion amount. Check cash availability and recipient permissions separately before offering the quote. The exact-owner redeem diagnostic uses the manifest's gas limit. It skips the adapter's preceding share transfer and the rest of the Pool call, so follow it with full action estimation. Put a positive final minimum in the proof and recheck expiry after proving. The transaction will credit what actually arrived at the Pool. | Quote field | Purpose | | --- | --- | | supplyCapacity: max-deposit | Checks how much the Pool receiver may deposit | | redeemCapacity | Chooses max-redeem or the exact-owner-redeem diagnostic | | redeemCallGasLimit | Limits gas for that diagnostic | | maxAgeBlocks | Limits how old the quote may be before proof and relay | | maxSlippageBps | Caps the reduction from the quoted output | ## Register both directions Admit the share token, then register supply and redeem under their adapter/operation/input/output tuples. FUYU_QUEUE_ERC4626_REVIEWS_FILE loads absolute manifest paths and their approved digests from a separate release file. queue-erc4626-publish.cjs prints a dry run unless the disposable-fork transaction gates are enabled. It refuses to re-enable a configured route that governance revoked. Compile the same approved digests into the frontend through FUYU_QUEUE_ERC4626_FRONTEND_DIGESTS. The optional registry prototype instead lets a frontend authenticate one registry and load later vault digests onchain. Operators still update the catalog/config and restart the API. ExitOnly requires action-route revocation while leaving share withdrawal available. The registry and publisher workflows remain test-only. ```bash # Read-only publisher plan; run in the protocol checkout. # The release file contains independently reviewed absolute manifest paths. FUYU_QUEUE_ERC4626_REVIEWS_FILE=/absolute/reviewed-release.json \ node apps/privacy/runtime/queue-erc4626-publish.cjs ``` ## Handle a failed route or withdraw shares For VenueChanged, inspect which dependency or identity call changed and review it again. InsufficientOutput means the Pool received less than the proof's minimum. InexactInput and InexactConsumption mean the token or vault moved balances differently from the supported transfer model. Calling execute from an EOA gives OnlyPrivacyPool; submit the private action through the Pool. Existing shares can leave through the ordinary screened exit after the action route is disabled. Check the destination's receiver rules before proving. The recipient gets shares and must redeem them through the vault; cash availability can still delay that redemption. Test this fallback and recover the withdrawn/share balances from authenticated history before listing the venue. --- # Aave V3 Stata Supply or redeem Aave static shares using the USDC fork route or the Sepolia WETH/native-ETH manifests. Source: https://docs.fuyu.xyz/integrate/aave ## Choose the Aave deployment The USDC fork route uses Aave's existing StataTokenV2 ERC-4626 wrapper around the V3 USDC aToken. Queue deploys a Fuyu Pool and an AaveV3StataAdapter for that fork. The adapter inherits the fixed-share supply/redeem code; the external Aave contracts are left as deployed. The USDC fork and Sepolia WETH/native-ETH paths use different configurations and adapters. Their operations are supply and redeem, without borrowing, leverage or reward claims. External Aave activity is public. Inside Fuyu, store the number of static shares and calculate their redemption value when needed. > **USDC fork configuration**: The default USDC pair is test-only. Each fresh fork gets new Fuyu Pool and adapter addresses. Load those addresses from the fork configuration and verify them against the Pool's route state. ![Choose the Aave deployment diagram](https://docs.fuyu.xyz/diagrams/asset.svg) ## USDC fork addresses The fork profile records Ethereum block 26,038,058 and its block hash. It also records proxy runtimes, implementation slots and implementation runtimes for the addresses below. Use this snapshot to reproduce the fixture. For another block or deployment, check implementation and liquidity again. | Contract | Ethereum address in the fixture | Use | | --- | --- | --- | | USDC | 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 | 6-decimal underlying | | StataTokenV2 | 0xD4fa2D31b7968E448877f69A96DE69f5de8cD23E | 6-decimal fixed shares | | Aave V3 Pool | 0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2 | Underlying reserve protocol | | USDC aToken | 0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c | Interest-bearing token wrapped by Stata | ## Check the Stata wrapper links The constructor checks vault.asset(), Stata POOL() and aToken(), and the aToken's POOL() and UNDERLYING_ASSET_ADDRESS(). Compare each result with the configuration. Also check bytecode and proxy implementations: getters can return the expected address even when the underlying contract is wrong. AaveV3StataAdapter checks those links at construction and does not recheck proxy implementation pins inside execute. The API, browser worker and relay check them before use. An upgrade between preflight and inclusion can still change execution. Onchain, the adapter enforces the amount pulled, actual output, positive minimum and deadline. ```typescript // Read-only relationship check with ethers v5. provider is your reviewed RPC. const stata = new ethers.Contract( '0xD4fa2D31b7968E448877f69A96DE69f5de8cD23E', [ 'function asset() view returns (address)', 'function POOL() view returns (address)', 'function aToken() view returns (address)', 'function previewDeposit(uint256) view returns (uint256)', 'function maxDeposit(address) view returns (uint256)', ], provider, ); const blockTag = 26038058; const asset = await stata.asset({ blockTag }); const aavePool = await stata.POOL({ blockTag }); const aToken = await stata.aToken({ blockTag }); // Compare these to the profile and separately check runtime/proxy pins. ``` ## Use the right units for each direction Admit USDC and stataUSDC, then register aave-usdc-supply with operation 0 and aave-usdc-redeem with operation 1. Both require zero actionData. The Pool stores the adapter runtime code hash under each action key. For a 10 USDC supply, amountIn is 10000000 atomic units. Do not reuse that number as the expected shares: get previewDeposit at the quote block, check maxDeposit for the Pool, and calculate minOut in share units. Redemption takes shares as input and uses USDC units for its quote and floor. | Route | Operation | Private input → private settlement | | --- | --- | --- | | aave-usdc-supply | 0 | USDC (6 decimals) → stataUSDC (6 decimals) | | aave-usdc-redeem | 1 | stataUSDC (6 decimals) → USDC (6 decimals) | ## Recover the shares after settlement The Pool verifies the private spend proof and action fields. The adapter pulls the input, grants the vault only the supply allowance it needs, and calls deposit or redeem with the Pool as receiver. It clears the temporary allowance and measures the Pool's output increase. A vault revert or short output rolls back the action. Stage 1 reserves the shares or USDC. The default router finalizes in the same transaction. If the user chooses two stages, retain the action identifier until ActionFinalized, then scan authenticated history to recover the output. Keep it pending in the UI until the note is spendable, and recover any change from the input notes too. ## Sepolia WETH and native ETH queue-sepolia-aave-manifest.ts accepts chain 11155111 only for the WETH/static-share pair listed below. This path uses the generic guarded ERC-4626 adapter and a release manifest digest. It checks the Fuyu Pool identity, asset/share runtimes, proxy implementations and five Aave relationship calls. Load the manifest for that deployment before offering the route. The WETH route IDs are aave-weth-supply and aave-weth-redeem. With nativeUnderlying: true, they become aave-eth-supply and aave-eth-redeem. The Pool represents ETH as address(0), while the adapter trades its configured WETH. WETH and stataEthWETH both use eighteen decimals. The native route also needs the Pool's wrapping/unwrapping path and balance checks. See the deployment guide for Pool, adapter, domain and release digest. | Sepolia contract | Address in the manifest | | --- | --- | | Aave WETH | 0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c | | stataEthWETH | 0x162B500569F42D9eCe937e6a61EDfef660A12E98 | | Aave Pool | 0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951 | | WETH aToken | 0x5b071b590a59395fE4025A0Ccc1FcC931AAc1830 | ## When redemption fails Aave can reject redemption when paused, short of underlying or upgraded. Estimate the complete Pool transaction after the venue diagnostics and check quote expiry again after proving. InsufficientOutput means the Pool received too little; InvalidDeployment points to a constructor address or relationship that failed its checks. A screened withdrawal can send stataUSDC shares to a permitted public destination without using the redeem action. That wallet redeems through Aave later, subject to its liquidity and permissions. An emergency exit reveals the deposit source and returns an eligible Pending deposit. Check your deployment's funding-asset catalog and exit support. This path cannot redeem earned share notes. AaveMainnetFork and the yield-adapter tests cover the USDC fixture. For your deployment, record the profile, adapter artifact/runtime, route registrations, quote block, execution and finalization receipts, and recovered shares. Recheck these after an Aave implementation change. --- # Morpho V1 Vaults Supply USDC to the Steakhouse V1 fork vault, account for 18-decimal shares and handle redemption or direct share withdrawal. Source: https://docs.fuyu.xyz/integrate/morpho ## Set up the Steakhouse V1 fork The Morpho route uses the Steakhouse USDC MetaMorpho V1 vault and a MorphoV1SteakhouseAdapter deployed for Queue chain 31350. The constructor checks that chain and the vault's identity. Allocation queues and Morpho Blue stay under the external protocol's control. Set FUYU_QUEUE_MORPHO_V1=1 when preparing a fresh authorized Linux fork fixture; the default bootstrap leaves the pair off. This adapter supports that V1 vault and underlying. Add another vault, V2 deployment or network through a separate route review or the ERC-4626 manifest workflow. > **Optional fork pair**: This test-only pair is off by default. The addresses below are external venue addresses; Fuyu Pool and adapter addresses are generated for each fork. ![Set up the Steakhouse V1 fork diagram](https://docs.fuyu.xyz/diagrams/asset.svg) ## Check the vault, factory and core At the quote block, the runtime validator checks code hashes, factory registration, asset(), MORPHO() and decimals(). The adapter constructor checks vault and factory hashes, isMetaMorpho(vault), the Morpho core and eighteen-decimal shares. Compare these values with the fixture rather than identifying the vault by its display label. The same vault code can have different queues, caps, allocations and available liquidity over time. Check capacity at the quote block and again before execution. Show the vault name and share balance in the app, with an underlying estimate that reflects its accounting and redemption availability. | Contract | Ethereum address in the fixture | | --- | --- | | Steakhouse USDC V1 | 0xBEEF01735c132Ada46AA9aA4c54623cAA92A64CB | | MetaMorpho factory | 0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101 | | Morpho Blue | 0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb | | USDC underlying | 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 | ## Keep USDC units and share units separate morpho-usdc-supply uses operation 0 to turn USDC into steakUSDC shares. morpho-usdc-redeem uses operation 1 for the reverse. Supply takes six-decimal input and an eighteen-decimal output floor; redemption reverses those units. Keep amounts as integers and read display decimals from the token configuration. Store the share count as the private balance. Use previewRedeem for a separately labeled approximate USDC value. For example, parseUnits('10', 6) is 10 USDC, while parseUnits('10', 18) is 10 steakUSDC shares. They are different positions, even if the UI displays the same number. ```typescript // Read-only historical quote; ethers v5. const vault = new ethers.Contract( '0xBEEF01735c132Ada46AA9aA4c54623cAA92A64CB', [ 'function asset() view returns (address)', 'function MORPHO() view returns (address)', 'function decimals() view returns (uint8)', 'function previewDeposit(uint256) view returns (uint256)', 'function previewRedeem(uint256) view returns (uint256)', ], provider, ); const usdcInput = ethers.utils.parseUnits('10', 6); const shareQuote = await vault.previewDeposit(usdcInput, { blockTag: 26038058 }); console.log(ethers.utils.formatUnits(shareQuote, 18)); // This preview is not complete Pool execution or a capacity guarantee. ``` ## Simulate the share amount you want to redeem maxRedeem(Pool) can round below a share count that a redemption would accept. The Morpho quote path therefore simulates redeem for the requested shares at the quote block. Use that result instead of deriving a quote from an approximate displayed balance. The simulation skips the adapter's share transfer and other Pool checks. Estimate the complete transaction afterwards, including its gas requirements and settlement. The browser and relay recheck route identity and output at the head; the callback still compares actual USDC received with the proof's positive minimum. ## Register supply and redeem Admit USDC and steakUSDC, then register the two adapter/operation/input/output tuples. The Pool stores the adapter runtime hash. The proof commits to the route, input, minimum, deadline and settlement owner. Calls use zero actionData and must come from the adapter's Pool. On supply, the adapter pulls USDC and sends vault shares to the Pool. On redeem, it pulls shares and sends USDC there. The supply allowance is cleared after use. Stage 1 reserves the result; finalization and a private scan recover the spendable note. One-transaction and two-stage submission expose the same external venue calls. ## Withdraw shares when the redeem route is unavailable A screened withdrawal can send steakUSDC to a permitted EOA if the redeem queue closes, liquidity runs out or governance revokes the action. The recipient gets shares and manages redemption through Morpho. Offer this as a share withdrawal with the correct token label. The fork test revoked the redeem route and closed a queue, then transferred the shares successfully. That checks the transfer fallback in the fixture. Before offering the same fallback elsewhere, check asset admission and recipient rules; the recipient may still have to wait for underlying liquidity. ## Find the failed check InvalidDeployment can mean chain ID differs from 31350, a code hash changed, factory registration is missing or a constructor link is wrong. Quote failures can come from cash or allocation constraints instead. InsufficientOutput reverts without spending the input note. If submission status is uncertain, check receipts before using those notes again. Keep queue-morpho-v1.cjs, the adapter artifact, block/hash and route registrations with your Linux test results. For another vault, create a separate manifest and test supply, redeem, share withdrawal and account recovery. Changing the existing constructor checks would change which vault this adapter supports. --- # Dolomite dUSDC Use dUSDC shares for the USDC market-2 route. Check wrapper implementations, receiver permissions and available cash before execution. Source: https://docs.fuyu.xyz/integrate/dolomite ## Use the dUSDC share token The route deposits USDC into the dUSDC ERC-4626 wrapper for Dolomite market 2 and receives transferable shares. A Dolomite margin-account balance has different accounting and cannot become the share token used by this private note. Redemption spends dUSDC for USDC, subject to the wrapper's cash and receiver rules. Set FUYU_QUEUE_DOLOMITE_DUSDC=1 to add this optional pair to a fresh Queue fork. DolomiteDUSDCGuardedAdapter accepts only its configured Pool on chain 31350. The documentation mentions WLFI Markets as context; this route connects directly to Dolomite and carries no WLFI partnership, retail integration, points or rewards entitlement. > **Optional dUSDC fork route**: The pair is test-only and off by default. Queue deploys an adapter for the existing Dolomite contracts. Reproduce the fixture and check its identities before running it. ![Use the dUSDC share token diagram](https://docs.fuyu.xyz/diagrams/asset.svg) ## Identify the wrapper and registries The wrapper and both registries can be upgraded. The runtime validator checks proxy slots and implementations, market mapping, asset, decimals, receiver permissions and the enabled Pool route at one block. During execute, the adapter also checks the implementation getters and code hashes it stored for the venue. | Contract | Ethereum identity in the fixture | | --- | --- | | dUSDC wrapper | 0x444868B6e8079ac2c55eea115250f92C2b2c4D14 | | DolomiteMargin | 0x003Ca23Fd5F0ca87D01F6eC6CD14A8AE60c2b97D | | Dolomite registry | 0x0F38bFBd9c1450BCF7A758e80E148CE78cfE09fD | | Account registry | 0xFee366CECA2472B99d0A501b6B3d01351c24dAaE | | USDC underlying | 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 | | Market ID and units | Market 2; underlying and shares both use 6 decimals | ## Recheck receiver permissions during execute The adapter checks the dUSDC proxy/implementation, registry and account-registry implementations, margin market mapping, asset, symbol and decimals. It checks Pool and adapter receiver permissions and their account-registry state too. Any mismatch produces VenueChanged, so a changed recipient rule can stop execution even after a successful quote. The callback pulls the full input and checks that the Pool's input allowance was consumed. Supply approves that amount to the wrapper and clears the approval after deposit. Redeem sends USDC to the Pool. Starting balances are compared with ending balances, and underlying allowance must be zero. These checks catch short pulls, retained tokens and output below minOut. ## Quote supply or redeem dolomite-usdc-supply uses operation 0 for USDC to dUSDC. dolomite-usdc-redeem uses operation 1 for dUSDC to USDC. Admit both tokens and register both action tuples. Calls need zero actionData, positive input/output minimum and a deadline that has not passed. maxRedeem can report an account's share balance even when the market lacks cash. The quote path runs a gas-bounded redeem simulation for the requested amount. It skips the adapter's share transfer and the rest of the Pool call, so estimate the whole action afterwards and check again at the head. Utilization, pauses and recipient restrictions can stop a quoted redemption. ```typescript // Read-only recipient and vault check; ethers v5. const dUSDC = new ethers.Contract( '0x444868B6e8079ac2c55eea115250f92C2b2c4D14', [ 'function asset() view returns (address)', 'function marketId() view returns (uint256)', 'function implementation() view returns (address)', 'function isValidReceiver(address) view returns (bool)', 'function previewRedeem(uint256) view returns (uint256)', ], provider, ); const at = { blockTag: authenticatedBlock }; const validReceiver = await dUSDC.isValidReceiver(destination, at); if (!validReceiver) throw new Error('Choose a permitted dUSDC recipient'); // Recheck at the head and use the complete reviewed withdrawal path. ``` ## Show dUSDC shares and USDC value USDC and dUSDC both use six decimals, but a dUSDC unit is a share in the market. Store and display the share count as the private balance. If you show a USDC estimate, include its snapshot time and use the redemption preview. Issuer upgrades and market exposure still affect the shares held inside the Pool. Supply reveals its venue and public amount. The private dUSDC balance appears after settlement and scan recovery. Keep pending output separate from spendable shares. Add yield percentages or incentive amounts only when your app has a source for that value and knows how to refresh it. ## Check who can receive a share withdrawal The ordinary screened withdrawal can send dUSDC to a public address without redeeming it. Before proving, the UI calls isValidReceiver(destination) through the selected RPC. Check again near submission because recipient permissions can change. The wallet that receives dUSDC must redeem through Dolomite when cash and permissions allow. The invalid-recipient browser case remains an acceptance gap in the source. Test the user-facing error when a destination is rejected, including a permission change after preflight. If submission loses its response, keep the input notes reserved until receipts show what happened; a client error can occur after a transaction was broadcast. ## Distinguish a guard failure from a liquidity failure For VenueChanged, compare the wrapper, implementation, registry, market and receiver state with the configuration. Keep the per-call guards in place when investigating. InsufficientOutput means output failed the minimum. InexactInput and InexactConsumption point to token movements or allowance changes that the adapter did not expect. queue-dolomite.cjs provides venue diagnostics. DolomiteMainnetFork and DolomiteGuardBoundariesFork cover the fixture's checks. Before offering another deployment, check source/artifact identities, market cash, Pool/adapter/recipient permissions, full action execution, share withdrawal and private recovery. --- # Uniswap V3 Swap USDC and WETH through one adapter per direction. Set the output floor, check the pool and recover the final private note. Source: https://docs.fuyu.xyz/integrate/uniswap ## Configure a direction and fee tier The default Queue pair swaps USDC and WETH through the existing Uniswap V3 0.3% pool. Bootstrap deploys a UniswapV3ActionAdapter for each direction and registers each route separately. These are swaps using external liquidity; there is no new Uniswap pool or LP position. Each adapter stores its Pool, router, factory, input, output and fee at deployment. Both directions use operation 0 and zero actionData. The fork uses the legacy SwapRouter tuple with router02=false. The contract also supports a Router02 tuple when selected at deployment. Match that flag to the router interface in your configuration. > **USDC/WETH fork pair**: The default pair runs on a test-only fork. Fuyu adapter addresses change per fork. The table lists the external Ethereum contracts used by the fixture. ![Configure a direction and fee tier diagram](https://docs.fuyu.xyz/diagrams/integration.svg) ## Check the router, factory and pool Bootstrap checks code hashes, factory lookup, tokens, fee and nonzero in-range liquidity. The adapter saves the router, factory and pool runtime hashes and checks the route before swapping. Price and liquidity can still change while those contracts keep the same identity. | Contract | Ethereum address in the fixture | | --- | --- | | USDC/WETH 0.3% pool | 0x8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8 | | Legacy SwapRouter | 0xE592427A0AEce92De3Edee1F18E0157C05861564 | | V3 factory | 0x1F98431c8aD98523631AE4a59f267346ea31F984 | | QuoterV2 | 0x61fFE014bA17989E743c5F6cB21bF9697530B21e | | WETH | 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 | | USDC | 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 | ## Set minOut in the output token's units swap-usdc-weth takes six-decimal USDC and returns eighteen-decimal WETH. swap-weth-usdc reverses those units. amountIn is fixed by the proof. Get an executable quote for that input and compute minOut using the output decimals, rather than deriving it from a displayed USD value. Save the quote block and hash, apply the allowed slippage choice and show the minimum and deadline to the user. The browser worker and relay check the route and output again. If price moves below the floor, execution reverts and the input remains unspent. A zero floor is rejected. ```typescript // Read-only factory identity check; ethers v5. const factory = new ethers.Contract( '0x1F98431c8aD98523631AE4a59f267346ea31F984', ['function getPool(address,address,uint24) view returns (address)'], provider, ); const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; const WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'; const pool = await factory.getPool(USDC, WETH, 3000, { blockTag: quotedBlock }); // 3000 is 0.3% in millionths. Authenticate code and token0/token1/fee too. const minOut = expectedOut.mul(10000 - slippageBps).div(10000); if (minOut.isZero()) throw new Error('Output floor rounds to zero'); ``` ## Call the router and check the result The adapter pulls the input from the Pool and compares both balances. It grants that amount to the configured router, calls exactInputSingle with the Pool as recipient and clears the allowance. The Pool's output increase must agree with the router's return value and meet the proof's minimum. This route sets no sqrt-price limit and requires actionData to be zero. The output floor and deadline come from the user's proof. execute accepts calls only from the configured Pool, so an EOA call gives OnlyPrivacyPool. Prepare the private action and proof, then submit through the Pool/router flow. ## Register both directions and scan the output Admit USDC and WETH, then call publisherSetSupportedAction for each adapter with operation 0 and its input/output pair. The Pool stores the adapter code hash. The proof includes the adapter, tokens, amount, minimum, deadline and settlement owner. Stage 1 reserves the USDC or WETH received. Stage 2 creates the private note, which the scanner recovers from authenticated history. The default router performs both in one transaction. For two-stage submission, show pending output until finalization. Keep change notes and unresolved submissions across refreshes so the app does not reuse the same inputs after losing a response. ## Explain the public swap and supported extensions The swap reveals its pair, direction, amounts and timing. The note owner is absent from the ordinary private spend's venue calldata, though amounts and timing can still link activity. Explain that before the user proves the action; router submission does not hide the external order. The default adapters cover USDC/WETH swaps. Arbitrary pairs, stocks, LP provision and V4 hooks need their own integrations. Native ETH uses a separate Pool wrapping path. To add a pair, review both assets and liquidity, deploy direction adapters and publish the routes. For multi-hop swaps or swap-to-vault flows, use an immutable action plan. ## Retry a swap or withdraw the input asset RouteChanged means the router, factory or pool no longer matches configuration. InsufficientOutput means the Pool received too little or the router reported a different amount. InexactInput and InexactConsumption mean unexpected token movements. Check receipts before preparing a replacement when submission status is uncertain. WETH can leave through a screened ERC-20 withdrawal without reverse-swap liquidity; USDC has its own withdrawal path. Test those transfers with route revocation, slippage rollback, scan recovery and allowance cleanup. UniswapV3ActionAdapter tests cover their fixtures. Adding a pool needs the same checks with that pool's contracts and liquidity. --- # Asynchronous Redemption Turn a pending vault redemption into private tickets, then claim harvested assets or refund cancelled shares. Source: https://docs.fuyu.xyz/integrate/async-redemption ## Return a ticket while redemption is pending Stage 1 needs an ERC-20 output before it can reserve a settlement. A queued redemption cannot deliver its underlying yet, so AsyncRedeemTicketAdapter mints tickets backed by the requested shares. The ticket becomes a private asset. Later, CLAIM exchanges it for harvested underlying and REFUND exchanges it for cancelled shares. The test fixture uses TestAsyncRedeemVault. Its operator chooses the price and can fulfil or cancel requests. REQUEST, CLAIM and REFUND handle those results; they cannot force immediate payment. An external mainnet ERC-7540 vault needs its own review before it can use this path. | Operation | Route | What the user receives | | --- | --- | --- | | REQUEST = 0 | share → ticket | One ticket per native share unit while redemption is pending | | CLAIM = 1 | ticket → underlying | Value of the oldest harvested claimable batches | | REFUND = 2 | ticket → share | One returned share per refunded ticket unit | ![Return a ticket while redemption is pending diagram](https://docs.fuyu.xyz/diagrams/asset.svg) ## Check controller consent at the venue The constructor calls requiresControllerConsent() and accepts exactly one canonical ABI true word. Check that the venue enforces this rule: another requester must not be able to name the adapter as controller and mix its requests with the adapter's own. ERC-7540 conformance alone is insufficient for this adapter. F-06 records the failure when foreign requests enter that aggregate: their fulfilment can change ticket pricing or their cancellation can strand a holder's assets. The constructor now requires the consent declaration. Review the venue's implementation and upgrade authority too, since a contract can return true without enforcing the behavior. > **Use the adapter code at 4def6e17**: Older integration prose still describes F-06. The constructor now requires controller consent. Read that check together with the finding reproduction and the venue you are integrating. ## Read the ticket partitions lifecycle() returns pending, claimable and refundable ticket amounts for all holders. Your account's ticket balance is a separate value. Anyone can call harvest() to collect available assets or cancelled shares from the venue. A request also harvests; a claim or refund harvests when it needs more backing. Each call collects at most one uint128-sized claimable batch plus cancelled shares. A claim covered by already harvested assets pays its FIFO preview without reading the venue. A covered refund uses returned shares held by the adapter. Requests above the claimable or refundable partition revert. Owning pending tickets does not let the account claim underlying until the venue has fulfilled them and the backing is available. ```typescript // Read-only lifecycle and FIFO quote; ethers v5. const tickets = new ethers.Contract(adapterAddress, [ 'function lifecycle() view returns (uint256 pending,uint256 claimable,uint256 refundable)', 'function previewClaim(uint256) view returns (uint256)', 'function ticket() view returns (address)', ], provider); const { pending, claimable, refundable } = await tickets.lifecycle({ blockTag }); if (claimAmount.gt(claimable)) throw new Error('Ticket claim is not ready'); const expectedAssets = await tickets.previewClaim(claimAmount, { blockTag }); // Revalidate identities, partitions and the positive floor before proving. ``` ## Explain how batch order affects price Tickets from different requests are fungible. Each harvested batch keeps its share and asset amounts, and claims take the oldest remaining batch first. Partial payouts use integer rounding; taking the rest of a batch pays its remaining assets. previewClaim returns the payout for a covered claim in that state. Two users claiming the same ticket count can receive different amounts if they consume differently priced batches. Show the latest preview and venue-wide partitions. Explain that another claim can change which batch is next before execution. The user's proof still sets the minimum underlying they will accept. ## Configure deposit, request, claim and refund FUYU_QUEUE_ASYNC_TICKETS=1 deploys the test vault, shares, ticket adapter and deposit adapter. Admit shares and tickets, then register USDC → asyncUSDC, asyncUSDC → fASYNC, fASYNC → USDC and fASYNC → asyncUSDC. Deposit uses the fixed-share adapter; REQUEST, CLAIM and REFUND use the ticket adapter. queue-async-tickets.cjs checks configuration, deployment blocks, runtimes and immutable addresses. The browser independently checks the Pool, all four runtimes/artifacts, their bindings, route code hash and partitions before proving. REQUEST and REFUND put their one-for-one output in the proof. CLAIM uses a positive minimum supported by the FIFO value. The relay accepts operation 2 only for the configured refund route. ## Recover each output and explain what is public REQUEST reveals the venue and requested shares. CLAIM reveals tickets spent and underlying paid; REFUND reveals returned shares. Ticket ownership can stay private between actions, while amounts and timing can still connect them. Finalize and scan every output, including operation-2 refunds, through the ordinary action flow. The test operator controls price, fulfilment and cancellation. A stuck request waits for that operator; harvest only collects results already available. Ticket outputs have no Optional disclosure view. Recover ticket balances and lifecycle activity from history across devices, instead of relying on a local request record. ## Check which exit your client supports Outside the Pool, a ticket holder can approve the adapter and call claim(tickets, minimum, deadline) or refund(tickets, deadline). Those calls pay that holder from harvested backing. A Pool configuration can admit screened ticket withdrawal, but the ordinary app relay documented here accepts asyncUSDC share exits and has no general ticket-withdrawal fallback. Add and test that client flow before offering it. NotAvailable means the chosen partition cannot cover the amount. Keep the output floor positive and wait for fulfilment or cancellation. Expired and InsufficientOutput roll back the action. Test partial fulfilment, cancellation, FIFO across batches, preview/payout equality, rollback, controller consent and account recovery. The funded-fork results cover one operator-controlled test venue. --- # Tokenized Assets Check token transfers, issuer permissions and trading liquidity before adding custody or a swap route. Source: https://docs.fuyu.xyz/integrate/tokenized-assets ## Add the asset and its trading route separately First review the token's units, transfers and custody behavior, then use supported-token registration to admit it to the Pool. To trade it, also register an adapter route. A token can be transferable even when there is no market the adapter can use. The source has no admitted tokenized-stock route. The stock integration document contains the onboarding process and a historical venue screen. Use this guide to prepare an addition; a named equity needs token admission, an executable venue and a route release before the app can offer deposits or trades. > **Stock routes are not enabled**: A tokenized stock needs a fungible-asset review and publisher admission, followed by a separate trading-route review. No stock route is admitted in this source revision. ![Add the asset and its trading route separately diagram](https://docs.fuyu.xyz/diagrams/asset.svg) ## Check the unit that will become a note Record chain, address, runtime, decimals, supply behavior and proxy/upgrade authority. Test rebasing, transfer fees, blacklists, issuer allowlists and registry restrictions. The ordinary adapters require fixed balances and full-amount transfers. An ERC-20-shaped interface and a familiar ticker do not answer those questions. If a wrapper gives fixed shares over a rebasing asset, review both contracts. Check who can wrap or unwrap, which versions holders can still use, and whether the Pool, adapter and withdrawal recipient can hold it. Issuer freezes, redemption eligibility, underlying custody and corporate actions still affect the token inside a private note. | Part of the integration | Questions to answer | | --- | --- | | Fungible units | Do balances rebase? Do transfers arrive in full? What are the decimals? | | Issuer controls | Who can freeze, upgrade or restrict transfers? | | Wrapper | Which version is transferable, and who can unwrap it? | | Receiver rules | Can the Pool, adapter and destination receive the token? | | Backing and redemption | Who can redeem it, and under what conditions? | | Route liquidity | Can the configured amount trade in both directions now? | ## Check an executable quote in each direction For an AMM, check factory, pool, tokens, fee, runtime and available liquidity. Quote bounded input sizes in both directions. A pool with no in-range liquidity can exist without providing a usable fill. A ticker price or redemption value also cannot replace the quote for the adapter's actual call. For an issuer RFQ, check who may issue and execute quotes, expiry, replay protection, recipient, input/output accounting and cancellation. Build a separate adapter for the issuer's protocol. Passing its calldata through the fixed Uniswap adapter would skip these assumptions and change that adapter's supported calls. ## What the stock screen checked At Ethereum block 26,048,625, the screen checked 16 issuer-current xStocks v2 wrappers against USDC and WETH. It searched Uniswap V2, four V3 fee tiers and standard no-hook V4 keys. None of the 288 direct legs existed. The USDC/WETH controls passed, so the same lookup found the fixture's known pools. The report covers those candidates and that block. Other venues, aggregators, custom hooks and later liquidity were outside the screen. Raw rebasing xStocks and unwrap-only v1 wrappers also have different transfer behavior. Keep the block/hash, candidate list, pool/key choices and exclusions with the report when using its result. ```bash # Rechecks archived report structure and recorded source hashes. # This does not refresh present-day liquidity or execute trades. python3 docs/integrations/evidence/stock-venue-screen-2026-09-24/verify-evidence.py ``` ## Prepare the token and route release Create a fungible manifest for custody and screened exit, and put its digest in the asset release file outside mutable API configuration. Next describe the trading route: assets, venue, operation, input range, slippage policy, runtime/proxy checks, quote lifetime and public exposure. Publish the token and action registrations separately. Add quote/relay validation and browser checks. Display the token or share count as the balance, with any estimated value and receiver restrictions alongside it. Use a supported adapter or write a narrow one, then put its output and owner in the action proof. Standard fungible routes can reuse the spend circuit; different token semantics may need another design. ## Check withdrawal permissions and identity exposure A screened withdrawal sends the token to a public destination. Check the issuer's or wrapper's receiver rules first. Primary redemption and sale happen outside that transfer and may require issuer eligibility. When trading is revoked, offer only the withdrawals that the token's transfer rules still allow. The venue, direction, amounts and timing of a trade are public. A permissioned issuer or RFQ counterparty may also know the trading identity. Explain how controller addresses, gas funding and app identity affect that exposure before the user generates a proof. ## Test custody, trade and recovery together Test deposit accounting, both trade directions and a minimum-output failure that leaves the input unspent. Change a proxy or receiver permission and check rejection. Withdraw to a valid destination and exercise the user-facing failure for an invalid one. Then recover the final asset balance from history on a fresh client. Keep the research screen, static checks, contract tests, funded Linux execution and service deployment results attached to their own runs. A stock listing still needs the token, liquidity, adapter, publisher and recovery checks described here. The source remains without an admitted stock route until that release exists. --- # Payment Credits & DeFi Redeem settled payment credits for their backing asset and recover the payout as a private note. Source: https://docs.fuyu.xyz/integrate/payment-modules ## Settle the payment before redeeming its credit Sessions, subscriptions, authorization/capture and streaming billing resolve purchases and refunds in the payment contracts and app. FuyuPaymentCreditAdapter starts after that work: it takes transferable settled credits and redeems them for backing assets. The Pool does not decide a voucher dispute or release an authorization hold. One credit unit redeems for one native underlying unit. The issuer must settle claims, vouchers and refunds before creating credits. The adapter takes no session ID, merchant override, beneficiary or arbitrary calldata. Its callback only moves settled credits into backing assets for private settlement. ![Settle the payment before redeeming its credit diagram](https://docs.fuyu.xyz/diagrams/integration.svg) ## Check the issuer and backing token The issuer must expose asset, totalSupply, balanceOf, transferFrom and redeem(amount, receiver). Review backing, issuance/burn accounting, transfer behavior and upgrade policy. Deploy the adapter with distinct Pool, credit and underlying addresses, all with code, and check credits.asset() against the underlying. The adapter stores chain and runtime hashes for those contracts and checks them before and after redemption. Also check proxy implementations and issuer administration in the release: a proxy can change implementation while keeping its runtime hash. The credit's backing and issuer risk remain relevant when the credit is held inside the Pool. ```solidity interface IFuyuSettledPaymentCredit { function asset() external view returns (address); function totalSupply() external view returns (uint256); function balanceOf(address owner) external view returns (uint256); function transferFrom(address from, address to, uint256 amount) external returns (bool); function redeem(uint256 amount, address receiver) external returns (uint256 assets); } ``` ## Register credit redemption REDEEM is operation 0. The input token is the settled credit and the output is its backing asset. amountIn must be positive and no larger than uint128.max. minOut must be positive and no greater than amountIn. actionData is zero, and the inclusive deadline is checked onchain. Admit the credit asset and register this adapter route before using it. The conversion is one-to-one in native units. For a six-decimal backing token, redeeming 1000000 credit units must return 1000000 asset units. This says how redemption is accounted for, rather than setting the asset's fiat price. If the issuer cannot pay that amount, the action reverts. | Field | Value or constraint | | --- | --- | | operation | 0: settled-credit redemption | | amountIn | Positive native credit amount, at most uint128.max | | minOut | Positive backing-asset floor, no larger than amountIn | | actionData | bytes32(0); no session or beneficiary fields | | tokenOut / amountOut | Configured backing asset / measured 1:1 output | ## Check the credit burn and asset transfer The callback records adapter and Pool credit/asset balances, plus total credit supply. It pulls the input from the Pool and checks that transfer left supply unchanged. It then redeems to the Pool, checks that supply fell by the input amount and requires the adapter's balances to return to their starting values. Both the issuer's return value and the Pool's asset increase must equal amountIn. An issuer that reports payment without transferring it fails. Existing adapter donations stay out of this output. The Pool separately verifies spend authority and token deltas, then clears the input allowance. ## Connect the payment lifecycle to the Pool A Session app deposits a budget, accepts small cumulative authorizations, consumes service credit atomically and settles merchant income or the final refund. Once the issuer creates settled credits, the holder can redeem publicly or deposit through the asset/profile admission flow. A Pool-held credit can then use this action to create an underlying settlement. The SDK does not automate those deposit and recovery steps. Session funding refunds a public credit to its fixed recipient; it does not create recovery material or a private refund note. Build and check that deposit path in your app. A card authorization hold must finish settlement before it can be treated as a settled credit. ## Recover the payout and keep payment state separate Redemption exposes issuer, credit amount, underlying payout and timing. The payment app can also associate requests within a session. Private funding can reduce direct linkage to a long-term wallet under the protocol's assumptions, but merchant, network and controller data remain relevant. The issuer's payment history remains public after credit redemption. Deploy Session/Funding contracts and enable the credit asset through their own release. That release needs issuer/adapter identities, backing and proxy policy, publisher registration, persistent billing accounting and lifecycle tests. Stage 1 reserves the backing payout; finalization and a scan recover the private note. Track the credit liability separately from the note's settlement state. ## Find an accounting mismatch BindingChanged means chain, code or the asset relationship changed. InexactInput means the pull changed balances or supply unexpectedly. InexactConsumption means the burn, remaining balances or supply decrease failed a check. InsufficientOutput means the reported or received payout differs from the one-to-one amount. Changing minOut cannot make another conversion rate work with this adapter. FuyuPaymentCreditAdapter tests cover this callback. Test dispute and close timing, refunds, shared collateral, issuer solvency and recovery in the payment app too. The callback's accounting checks apply to already settled credits; provider behavior and unsettled sessions need their own tests and deployment checks. --- # Tools & SDKs Find the payment SDK, proof tools and independent audit verifier in the protocol checkout. Source: https://docs.fuyu.xyz/tools ## Tools in the repository Use the CommonJS SDK for payment accounting and rail lifecycle. Browser crypto and prover clients handle private account operations. FPL tools parse and evaluate questions; independent audit verifiers check exported proof answers. Examples use repository paths. The docs assume a protocol checkout, not a published npm package or hosted SDK endpoint. ![Tools in the repository diagram](https://docs.fuyu.xyz/diagrams/architecture.svg) ## Find the tool you need | Tool | Location | Use | | --- | --- | --- | | Payment modules | sdk/payment-sessions/ | Sessions, subscriptions, authorization, splitters and funding | | FPL toolchain | dsl/ | Parse and check .fuyu programs, then compile or evaluate them | | Audit proof relations | circuits/owned-notes/ | Prove facts about owned notes and spend records | | Independent verifier | apps/privacy/runtime/verify-audit-answer.cjs | Verify an exported answer using independent history | | Client crypto and proving | apps/privacy/src/crypto/ | Open account keys, decrypt delivery and prepare spends | ## Set up the checkout Use Node 24, Python 3 and Git LFS. Install lockfile dependencies and fetch the proof files before proving or verifying. The payment SDK uses ethers 5.8.0, and its SQLite worker uses Python's standard-library sqlite3 module. ```bash git lfs pull npm ci --ignore-scripts npm ci --prefix apps/privacy --ignore-scripts # Rebuild circuit sources only when needed: npm ci --prefix circuits --ignore-scripts ``` ## Use Fuyu with an AI assistant Give the assistant the current protocol source, SDK reference and deployment manifest. Ask it to use the exported methods and atomic-unit amounts, with providers and funded terms supplied by your application. For an agent buying services, configure a SessionManager budget and authenticate each signed resource request in your transport. Check contract hashes and required approvals before allowing a broadcast. The SDK has no vendor-specific agent connector. ## Keep the deployment files together Save the source revision, runtime hashes, proof files and deployment data used by the integration. Dependency installation checks none of those contract identities. Likewise, evaluating a question locally produces a preview; a proof answer still needs verification. Run contract, circuit and sustained acceptance work on the provisioned Linux environment. Use the development keys on a development deployment; production needs its own key setup. --- # Payment SDK Load the SDK from the protocol checkout and set up its payment ledgers. Source: https://docs.fuyu.xyz/tools/payment-sdk ## Load the SDK Import the CommonJS entrypoint shown below from the protocol repository root. It exports managers, low-level clients and gateways, backends, funding drivers and the SQLite store. The directory is not a published npm package. Install the lockfile first. The SDK expects ethers 5.8.0; check compatibility before substituting a different major version. ```javascript const { createSessionManager, createSessionClient, createSessionGateway, createEthersBackend, createSqliteStore, createFundingDriver, } = require("./sdk/payment-sessions/index.cjs"); ``` ## Create a ledger Choose a private directory owned by the process user for each SQLite ledger. The store creates missing private directories and its database, serializes transactions across local Node processes and rolls back failed transactions. Use createMemoryStore only for single-process development. It has no crash durability or cross-process lock, so it cannot safely authorize production purchases. ```javascript const path = require("node:path"); const { createSqliteStore } = require("./sdk/payment-sessions/index.cjs"); const store = createSqliteStore({ path: path.resolve("var/fuyu/merchant/ledger.sqlite"), }); ``` ## Configure the backend Set the session backend's chain, core and asset. readConfirmations selects how far behind the latest block to read; confirmations sets how many confirmations a submitted transaction waits for. The signer must use the same provider object as the reader. Subscription, Authorization, Splitter and generic funding backends also require reviewed runtime hash manifests and decimals. For a proxy, check its implementation as well as the proxy runtime hash. ![Configure the backend diagram](https://docs.fuyu.xyz/diagrams/rails.svg) ## Choose a manager or lower-level client SessionManager handles budgeted preparation, request acceptance and settlement recovery. If you already manage those steps, use createSessionClient and createSessionGateway directly. In either case, keep purchase and resource-request signatures separate. On multiple hosts, supply a database adapter that preserves nested atomicity and locking across them. The bundled SQLite store coordinates local processes only. ## Configure buyer and merchant The buyer signs with the funded session's voucherSigner. The merchant's settlement signer can submit claims, but the rail always pays the fixed merchant. Each backend uses one provider object for reads and writes. Buyer and merchant keep separate durable stores. The example takes already funded terms and a policy from the host. Save that policy with the terms. Recalculating expiresAt on restart changes it and causes a store mismatch. This configures accounting; token approval, session opening, asset transfers and provider execution still need their own calls. ```javascript const path = require("node:path"); const { createSessionManager, createSqliteStore, createEthersBackend, } = require("./sdk/payment-sessions/index.cjs"); function configurePayment({ provider, sessionSigner, settlementSigner, terms, policy }) { const buyerStore = createSqliteStore({ path: path.resolve("var/fuyu/buyer/ledger.sqlite"), }); const merchantStore = createSqliteStore({ path: path.resolve("var/fuyu/merchant/ledger.sqlite"), }); const buyerBackend = createEthersBackend({ provider, chainId: terms.chainId, core: terms.core, asset: terms.asset, readConfirmations: 2, }); const merchantBackend = createEthersBackend({ provider, signer: settlementSigner, chainId: terms.chainId, core: terms.core, asset: terms.asset, readConfirmations: 2, confirmations: 2, }); return { buyer: createSessionManager({ backend: buyerBackend, signer: sessionSigner, store: buyerStore, terms, policy, }), merchant: createSessionManager({ backend: merchantBackend, store: merchantStore, terms, policy, }), }; } module.exports = { configurePayment }; ``` ## Set the budget Use atomic units for budget and purchaseStep. budget must be positive and no greater than terms.maxDeposit; purchaseStep cannot exceed budget. The session must have enough deposited capacity for the next purchase before prepare succeeds. A six-decimal token has 1,000,000 atomic units per display unit. budget 1,000,000 and purchaseStep 100,000 buy up to one unit in increments of one tenth. Choose values for your own prices. Fixed-budget private escrows reject topUp; public session calls have their own payer authority. ## Keep nested updates atomic SessionManager nests updates to manager, buyer-client and merchant-gateway records. An inner credit acceptance must roll back if the outer receive operation fails. In a custom store, await signing, chain reads and updates before the transaction callback returns. SQLite uses a local write lock and nested savepoints. It works across processes on one host, not across hosts. When archiving requests, preserve their IDs for deduplication and keep every transport for the merchant session on the same accounting store. ## Restart from the saved ledger Recreate managers with their original terms and policy, reopen the existing ledgers and call recover before accepting work. The backend and ledger reject backward movement in the block, timestamp, deposited, claimed and closure observations they retain. After a reorganization, investigate the changed chain state. Deleting the database would discard prepared reservations, accepted credit and debit receipts. Keep the uncertain intent and reconcile it before retrying the same settlement operation and amount. ## Use fresh reads and settle on time maxReadAge controls the session backend's RPC freshness check, and nowSeconds supplies its authorization clock. The default freshness allowance is 120 seconds. Configure readConfirmations and transaction confirmations separately. Use synchronized clocks and leave time inside the deployed close period for settlement. Older reads can miss closure. The smallest permitted dispute period may be too short for your RPC lag and worker recovery; choose it around those conditions and monitor earned vouchers. --- # Fuyu Policy Language Write account-history questions and check which evidence their answers need. Source: https://docs.fuyu.xyz/tools/fpl ## Write a question FPL names Yes/No questions about an account history. Its parser and checker resolve assets and units, subjects and snapshots, disclosure effects and the evidence needed for each answer. The reference evaluator runs a program against a history model you supply. FPL questions cannot change spending permission. The Pool keeps an opaque note-policy attachment, but it does not read the language or execute its predicates. ![Write a question diagram](https://docs.fuyu.xyz/diagrams/disclosure.svg) ## Check what the prover supports FPL can express questions beyond the current audit circuits. A positive lower bound may need only selected witnesses. An upper bound or absence claim can need complete history in the reference model. The holder audit compiler accepts a capacity-limited upward subset and rejects programs with unsupported questions. Label reference evaluation as a local, unproven result. ## Evaluate the example history Run this fixture from the protocol repository root. It evaluates the supplied example history. To produce a zero-knowledge answer, you need the separate audit plan and proof flow. ```bash node dsl/cli.cjs eval dsl/examples/stock-query.fuyu \ --registry dsl/examples/stock-registry.json \ --target dsl/examples/stock-target.json \ --policy dsl/examples/stock-disclosure.fuyu \ --evidence dsl/examples/stock-history.json ``` ## Use the same program on both sides The audit plan includes the program's canonical digest, subject, audience, nonce, expiry and finalized snapshot. Prover and verifier must compile it with the same registry, relation configuration and verification-key hashes. Show the holder the question and what the answer will publish. A holdings or participation proof cannot be used as evidence of a source set, exhaustive history or exclusive contribution to a transaction. | Stage | Result | | --- | --- | | Parse and check | A program accepted under its registry and target | | Reference evaluation | An answer calculated from the supplied history model | | Audit plan compilation | A statement supported by the current proof backend | | Proof verification | A proof chain checked against the configured relation and independent history | --- # Independent Verifier Verify an exported audit answer against your own finalized chain history. Source: https://docs.fuyu.xyz/tools/verifier ## Gather the verifier inputs Provide the auditor's FPL program, holder's exported answer, trust file, verification keys and an RPC endpoint. The verifier checks the chain and Pool, then rebuilds complete finalized history from the deployment block. Read chain history independently of the holder. A wallet checkpoint or balance export can omit events, so it cannot replace the audit history used to check the proof. ![Gather the verifier inputs diagram](https://docs.fuyu.xyz/diagrams/disclosure.svg) ## Choose trusted deployment data Record the expected Pool and cryptographic contracts, receiving directory runtime, deployment block and verification-key hashes. The deployment-export tool writes this data for the deployment it inspects. Keep the trust file separate from the holder's answer. Obtain expected hashes through a reviewed source. Accepting whatever code the RPC returns on its first request would let that same RPC decide which deployment you trust. ## Run the verifier Supply the program, answer and trust file as separate inputs. Set your RPC and receive-directory address and code hash for that deployment. The command below uses the CLI's current flags. For browser verification, open verify-audit-answer.html in the app distribution. ```bash # Run from the protocol checkout with reviewed deployment inputs. node --experimental-strip-types \ apps/privacy/runtime/verify-audit-answer.cjs \ --program review.fuyu --answer answer.json --trust trust.json \ --rpc "$FUYU_AUDIT_RPC_URL" \ --directory "$FUYU_AUDIT_DIRECTORY" \ --directory-code-hash "$FUYU_AUDIT_DIRECTORY_CODE_HASH" ``` ## Read a verified answer Verification confirms the compiled statement at the selected finalized snapshot and within the relation's capacity. Later transactions can change the account balance. FPL questions outside the compiler's subset still need a different proof backend. The repository uses test-only relations and files. Include that key status with exported answers; production key generation and security review are still pending. - Read the subject's registered key generations independently. - Reject incomplete history, a wrong deployment or changed keys. - Keep the input-participation qualification on spend-record results. - Label verified Yes answers separately from local previews and rejected questions. --- # Contract Testing Run Solidity tests, choose the suites for your change and reproduce contract artifacts. Source: https://docs.fuyu.xyz/tools/contract-testing ## Prepare the checkout Choose a protocol revision and record any local changes. Contract source, spend layout, verifier artifacts and deployment scripts need to match. Save the source revision, Solidity and Foundry versions and external fork block with the results. If you change contract bytes afterward, rerun the affected checks. The contract wrapper requires Linux and FUYU_REMOTE_EXPERIMENTS=1. Run experiments, fuzzing and fork campaigns on the designated Linux development host. Use the macOS workspace for source inspection and documentation; the wrapper refuses contract experiments there. The Foundry profile uses Solidity 0.8.30, Cancun EVM, one optimizer run, via_ir false, no bytecode hash and no CBOR metadata. Dynamic test linking is disabled so constructor revert tests run at the actual CREATE call. Use these settings when comparing artifacts or reproducing contract sizes. ```bash # On the designated Linux host, from the protocol repository root export FUYU_REMOTE_EXPERIMENTS=1 npm ci npm run test:contracts # The same wrapper with a focused Foundry selector bash contracts/script/test.sh --match-path 'test/payments/*.t.sol' bash contracts/script/test.sh --match-contract FuyuTransactionRouter bash contracts/script/test.sh --match-contract PoolInvariantTest ``` ## Choose a test suite Select tests for the authority, asset movement and retry behavior your change affects. Then run the composition suite that connects the module to the Pool or payment rail. Mock-venue tests cover controlled failures; external-fork tests check behavior against the venue state at their chosen block. | Directory | Checks | | --- | --- | | test/pool | Funding amounts, spend layout, permanent roots, reserves, reserved slots and finalization | | test/authorization / test/controller | EOA/Safe/1271 digests, malformed payloads and claim/refund deadlines | | test/directory / test/registry | Registration nonces and revisions, descriptors and venue identity | | test/portal | Invoice witnesses, sweep bounds, recovery and owner-only credit | | test/router | Ordered batches, full rollback and immediate settlement | | test/payments | Voucher deltas, close windows, holds, recurring charges, funding and splits | | test/adapters | Measured token changes, identity checks, leftover balances/allowances and venue failures | | test/earn | Flex/Term accounting, ticket windows, fees and adapter operations | | test/governance | Proposal delays, DENY limits, protected exits and renewal | | test/migration | Source receipts, private credit and timed recovery | | test/hash / test/verifier | Poseidon vectors, the fixed spend verifier and oracle comparisons | ## Accounting invariants The default Foundry fuzz profile runs 256 cases. PoolInvariantTest exercises randomized transitions through the Pool fuzz harness. Set RUN_POOL_INVARIANT_DEEP=true to enable deep and census variants; FUZZ_CENSUS_CALLS sets census length. Include seeds and run settings in the report so a failing sequence can be reproduced. Check credited liabilities against actual custody, unique nullifier consumption, output conservation and release of reserved slots. Verify that wallet/controller checks cannot be bypassed. Payment-rail tests must account for active escrow separately from settled credit supply and reject a second debit for the same cumulative capture or claim. For failures, check state rollback as well as the error selector. Compare balances, reserves, allowances, nullifiers, receipts and nonce/revision state before and after. Include invalid constructor identities, token callbacks and a failed final append; a successful token transfer alone cannot exercise those cases. ## Run venue fork tests Fork suites run only when their flags are enabled. Historical blocks make venue identity and liquidity repeatable; the mainnet suites listed here generally use Ethereum block 26,038,058. Some also have a latest-state flag for a separate compatibility check. Use current venue queries to check live capacity, even when the historical test passes. Set FUYU_MAINNET_RPC_URL for the mainnet suites and check that your RPC serves the chosen block. Run the suite for the venue you are changing. Report skipped cases separately from tests that actually executed. ```bash # Linux only; these use external chain state but no public transaction broadcast export FUYU_REMOTE_EXPERIMENTS=1 export FUYU_MAINNET_RPC_URL='' RUN_AAVE_FORK=true bash contracts/script/test.sh --match-contract AaveMainnetFork RUN_PLAN_FORK=true bash contracts/script/test.sh --match-contract FuyuPlanMainnetFork RUN_V3_ROUTER_FORK=true bash contracts/script/test.sh --match-contract UniswapV3ActionAdapterFork RUN_DOLOMITE_FORK=true bash contracts/script/test.sh --match-contract DolomiteMainnetFork RUN_MORPHO_FORK=true bash contracts/script/test.sh --match-contract MorphoMainnetFork ``` ## Reproduce artifacts npm run reproduce:contracts rebuilds historical deployed/test-only artifacts from archived inputs, checks source and archive hashes, and compares creation/runtime bytecode. Use the Solidity version recorded in the archive. The script builds in an isolated generated workspace without editing current source or the stored artifacts. Reproducing an archived artifact checks that archive, not repaired current contracts/src. Test current source separately with Foundry. For a new deployment, build artifacts from the intended revision and record that connection rather than deploying an old artifact because its archive reproduced. npm run check runs layout, artifact, contract-size, circuit-source and generated hash/verifier checks. Keep its output and manifest identities with the result. The docs build and TypeScript checks cover the site; they do not run these protocol checks. ```bash # Linux toolchain with the pinned solc available npm run check npm run reproduce:contracts # SDK helpers complement Solidity tests npm run test:payment-sessions npm run test:payment-integration ``` ## Test the full application flow After component tests, fund a disposable deployment using the artifacts and configuration intended for release. Make a proof, review signatures, submit and check the recovered result in a fresh client. Include lost responses and permissionless completion, and verify both spent inputs and recovered outputs. For routes, test supply and redemption or both directions where applicable. Include minimum failures, changed identities, token accounting, public exit, route revocation and queued finalization. For payment rails, cover close/refund, holds that survive cancellation, billing-period boundaries, refund destinations and split rounding. Record the revision, commands, enabled flags, block, checks run and remaining limits. Tool-assisted tests are not an independent audit. A proof-key ceremony, physical-device/browser acceptance and public deployment checks also need their own release work. ## Save the results Write down the command and source version, which contracts and venues ran, and which cases failed or were skipped. Keep transactions or traces for custody discrepancies. Enabling a flag, acquiring source or adding a test file does not mean the test has run. When a test loses a submission response, use the original ID and chain state to find the outcome. Apply the same behavior in your app: check whether the first payment settled before a retry can create another payment. --- # Fuyu API Read deployment configuration, submit prepared proofs and track payment state. Source: https://docs.fuyu.xyz/api ## Choose an interface The onchain contracts settle funds. The app runtime serves configuration, proof files, relay submission and status. The payment SDK runs in your process to manage accounting and rail lifecycle. The queue API and disposable-fork setup are development services. Run them locally or use an operator's reviewed runtime. These docs provide no production base URL or shared bearer credential. ![Choose an interface diagram](https://docs.fuyu.xyz/diagrams/architecture.svg) ## Runtime endpoints | Method and route | Use | | --- | --- | | GET /api/queue/config | Read deployment, asset and relay fee configuration | | GET /api/queue/assets | Read funding assets at an authenticated block | | POST /api/queue/quote | Quote an approved external action | | POST /api/queue/send-relay | Submit a prepared private send | | GET /api/queue/send-status | Check a private send's state | | POST /api/queue/withdraw-relay | Submit a prepared withdrawal | | GET /api/queue/withdraw-status | Check a withdrawal's state | | POST /api/queue/finalize | Finalize a reserved action output | ## Read the deployment configuration Fetch the runtime configuration before preparing a request. Compare its chain, Pool, verifier and contract hashes with your application's reviewed deployment data. An HTTP 200 response still needs those identity checks. ```javascript // runtimeBaseUrl is the local or explicitly reviewed runtime origin. const response = await fetch(new URL("/api/queue/config", runtimeBaseUrl)); if (!response.ok) throw new Error(`Configuration failed: ${response.status}`); const config = await response.json(); // Validate chain, Pool, verifier and contract pins before using config. ``` ## Keep private inputs in the client Send the relayer proofs and public execution fields. Keep note openings, spend secrets, passkey material and audit witnesses in the holder's browser or encrypted backup. The server does not need those secrets to submit the transaction. For paid resource APIs, build a transport around SessionManager or the low-level client and gateway. HTTP 402 and vendor billing endpoints need application implementations; they are not supplied by this SDK. --- # SessionManager Reference Prepare purchases, accept resource requests and recover settlement after a restart. Source: https://docs.fuyu.xyz/api/session-manager ## Create a manager createSessionManager takes a backend, durable store, session terms and policy. Add the session authority signer for buyer preparation and an optional lifecycle backend when needed. The merchant needs a backend that can submit claims. Keep terms, policy and ledger unchanged across restarts. A manager rejects a changed configuration for a live session. Deleting the ledger would lose reservations and replay protection. | Policy field | Controls | | --- | --- | | budget | Maximum service purchases in atomic units | | purchaseStep | The increment used to raise cumulative purchases | | requestTtl | Signed resource-request lifetime in seconds | | expiresAt | When application acceptance stops, in Unix seconds | | settlementInterval | Time between settlement ticks | | broadcastTimeout | When an unresolved broadcast is marked uncertain | | autoClose / autoFinalize | Lifecycle behavior; defaults false / true | ## Prepare and receive prepare takes requestId, requestDigest and amount. When needed, it signs a cumulative purchase increment, then signs the resource request and saves its reservation. receive checks both signatures against content and price calculated by the merchant. Retrying an ID with the same content and price reuses its preparation or receipt. Changing those values fails. The buyer keeps a prepared request's reservation even if it is never delivered. ```javascript const bundle = await buyer.prepare({ requestId, requestDigest, amount }); const receipt = await merchant.receive(bundle, { requestId, requestDigest: serverDigest, amount: serverPrice, }); ``` ## Check status and settle status and recover save new chain observations. settle claims the highest accepted voucher. tick checks its settlement interval and watches closure. Other lifecycle methods call the configured driver. After a broadcast interruption, call recover to check chain state. An uncertain retry must be the same operation with the same settlement amount. ![Check status and settle diagram](https://docs.fuyu.xyz/diagrams/streaming.svg) ## Run a settlement worker startWorker schedules ticks and reports failures through onError. It handles payment state only; your application runs, caches and retries service jobs. Stop the worker cleanly when shutting down. ```javascript await merchant.recover(); const worker = merchant.startWorker({ intervalMs: 5000, onError: error => console.error(error.code, error.message), }); // After stopping your application from accepting new work: await worker.stop(); ``` --- # Signed Request Reference Sign the resource ID, content, price and deadline separately from a purchase voucher. Source: https://docs.fuyu.xyz/api/session-requests ## SessionRequest typed data SessionRequest uses EIP-712 domain Fuyu Session Requests, version 1, for the configured chain and core contract. Its fields identify the session, hashed request ID, content digest, amount and deadline. Voucher uses another domain and signs cumulativeAmount. Keep these formats separate when carrying requests over a transport, logging them or checking authentication. | Field | Format | Use | | --- | --- | --- | | sessionId | bytes32 | Identifies the funded session | | requestIdHash | bytes32 | keccak256 of the UTF-8 request ID | | requestDigest | bytes32 | Identifies the resource and content | | amount | Unsigned atomic-unit integer | Sets the request price | | deadline | Unsigned Unix-second integer | Sets when the request expires | ## Define the content digest Publish a codec covering every option that affects the result: method and route, body, model and other relevant parameters. Recompute it on the server from the request you receive. Do not accept the client's digest without that comparison. This example combines a route identifier with a hash of the body bytes. The application defines that resource codec separately from the EIP-712 signing domain. ```javascript const { ethers } = require("ethers"); const routeId = ethers.utils.id("fuyu.example/inference/v1"); const requestBodyBytes = ethers.utils.toUtf8Bytes('{"prompt":"hello"}'); const requestDigest = ethers.utils.keccak256( ethers.utils.defaultAbiCoder.encode( ["bytes32", "bytes32"], [routeId, ethers.utils.keccak256(requestBodyBytes)], ), ); console.log(requestDigest); ``` ## Choose stable request IDs A Session request ID is a nonempty string of at most 1024 JavaScript characters. The signature covers keccak256 of its UTF-8 bytes. Reuse the ID for a retry of one job; choose a fresh ID for new work. After expiry, obtain a fresh signed deadline for the same ID, digest and price. It can retrieve the existing debit receipt without charging again. Your job ledger still needs to prevent repeated provider execution. ## Recompute the merchant context For consume or receive, calculate requestId, requestDigest and amount from the actual route and server pricing. Copying them from the customer's envelope would skip the check that the authorization matches the requested work. Associate the payment receipt with a durable job record. Use provider idempotency when available and return cached output for an already accepted request. --- # Errors & Recovery Handle SDK errors and check whether the original operation reached the chain. Source: https://docs.fuyu.xyz/api/errors ## Read the error code The CommonJS SDK throws an Error with code and message fields. Branch on code and show the user an action they can take. Keep request envelopes and private account data out of diagnostic output. These errors catch changed contracts, budgets and request content, as well as unresolved broadcasts. Resolve the reason before attempting to accept the original request again. ## Common error codes | Code | Reason | Next step | | --- | --- | --- | | PIN_MISMATCH | The deployment or authority changed | Check configuration against the intended chain and contracts | | STORE_MISMATCH | Saved policy or observed state no longer matches | Reconcile the original ledger; keep its records | | CAPACITY_EXCEEDED | Funding or its configured limit is too small | Fund within the agreed terms before retrying | | BUDGET_EXCEEDED | Prepared purchases exceed the manager budget | Approve a new policy or session separately | | REQUEST_CONFLICT | A prepared ID has different content or price | Use its original request or assign a new job ID | | REQUEST_MISMATCH | Content or price differs from the server calculation | Correct the request or server billing context | | REQUEST_EXPIRED | The signed deadline passed | Renew the same request's signature if permitted | | LIFECYCLE_UNCERTAIN | A broadcast outcome is unresolved | Recover and check chain state | | MANAGER_EXPIRED | The application policy expired | Stop new requests and settle before claim rights end | | SESSION_NOT_OPEN | The session is unfunded or closing | Check its funding and close state | ## Recover after a timeout A validation failure and a broadcast timeout need different handling. After submission, the transaction may succeed even if its response is lost. Save the intent and hash, then recover chain state before another mutation. ```javascript try { await merchant.settle(); } catch (error) { if (error.code === "LIFECYCLE_UNCERTAIN") { await merchant.recover(); // Review the recovered intent and state before an explicit retry. } else { throw error; } } ``` ## Check state before retrying Use session, hold and transaction state to choose the retry, rather than matching an error message. Repeating a settled target can be idempotent. Changing content under the same request ID is a conflict. Stop authorization when RPC reads fail the freshness check, and wait for the RPC and clock to recover. Investigate reorganized or backward state instead of removing the stored observation floor. --- # Fuyu Protocol Learn how the Pool stores private notes and executes spends and external actions. Source: https://docs.fuyu.xyz/protocol ## The shared Pool Fuyu holds assets in the Pool and represents private claims as note commitments. The browser proves ownership, tree membership and value conservation. The Pool checks the proof and records unique nullifiers to consume the inputs. For an external action, an approved adapter calls the public venue and measures what it returns. Finalization creates the holder's private note for that result. ![The shared Pool diagram](https://docs.fuyu.xyz/diagrams/architecture.svg) ## Core and surrounding contracts The selected core embeds its verifier and has no proxy, verifier setter, administrator withdrawal or forced migration. Its ordinary exit follows the original ownership and accounting rules. New features use peripheral contracts and offchain tools. The publisher controls admission data, supported tokens and action routes. It has no private account keys or custody authority through those permissions. | Component | Handles | | --- | --- | | Pool and verifier | Reserves, notes, nullifiers and the original spending rules | | Adapters | Permitted venue calls and measured returns | | Router | Ordered transactions without taking custody | | Controllers | Extra approval for Safe or claim notes | | Portals | Plain transfers credited to a fixed private recipient | | Directory | Receiving descriptors and key generations | | App and proving workers | Account recovery, proof preparation and holder consent | ## Ask questions with FPL FPL and holder-run proofs let the holder choose to answer supported questions. They do not change spending permission. The Pool stores opaque policy attachments without interpreting the language. Check which questions the audit compiler supports. FPL syntax, a local evaluated answer and a verified proof are different outputs with different uses. ## Using the implementation The repository includes contracts, circuits, test files and a development app. It uses development proof keys. Production keys, independent review, mainnet and physical-device acceptance are still outstanding. Use the specifications and whitepaper when building an integration. Before using a deployment, check its runtime and proof-file hashes against the release you intend to trust. --- # Notes & Commitments Understand note openings, nullifiers and the point where outputs become spendable. Source: https://docs.fuyu.xyz/protocol/notes ## What a note contains A note opening holds the asset, amount, ownership fields and secret randomness. The Pool records a commitment to those values. Randomness hides their contents under the protocol's hash assumptions. To spend, the holder proves tree membership under an accepted root and derives a nullifier from secret keys. The Pool records that nullifier and rejects any later attempt to spend it again. ![What a note contains diagram](https://docs.fuyu.xyz/diagrams/payment.svg) ## Types of note | Kind | Origin | Spending and recovery | | --- | --- | --- | | Pending | A public deposit | Ordinary screened admission checks its direct source policy | | Active | A private transfer output | The recipient decrypts delivery; full input ancestry is not certified | | Settled | A measured external action output | Public venue execution fixes the result before note append | ## Find and decrypt a note Ownership uses Poseidon images and hash-derived nullifiers. X-Wing combines ML-KEM-768 and X25519 to derive the shared secret used for encrypted output delivery. The recipient decrypts the opening and checks that it matches the recorded commitment. Delivery tags reduce the notes a client has to try decrypting. They do not authenticate a note by themselves. Keep the complete receiving descriptor and recovery keys in the format the client supports. ## Inputs, outputs and reserved value The current relation has at most two inputs and two outputs. Inputs share one asset and controller. A spend can create private change and a public payout; an approved action can return one distinct output asset. An action receipt reserves returned value before it becomes a note. Finalization must keep reserve and note accounting consistent. The account can spend the output only after its note is appended and recovered. ## Roots and tree capacity The permanent-core candidate keeps completed known roots. Later appends therefore do not evict an old unspent note's membership root. The spend must still pass nullifier and current execution checks. The tree has finite cumulative leaf capacity. Spent leaves do not free slots. New private outputs need space, while ordinary zero-output exits have their own liveness rules. --- # Privacy & Trust Boundaries See which note details stay private and what observers can still learn. Source: https://docs.fuyu.xyz/protocol/privacy ## Private note data Spend witnesses stay on the holder's device. Proofs, hashes and encryption protect note openings, input ownership and recipient delivery under their respective assumptions. The relayer can submit a request without holding plaintext account history. Public chain fields and application traffic remain visible. The table below lists what each operation exposes. ![Private note data diagram](https://docs.fuyu.xyz/diagrams/architecture.svg) ## What the chain shows | Operation | Public data | | --- | --- | | Deposit | Funding wallet, asset, amount and timing | | Private transfer | Commitments, nullifiers, proof submission and public fields | | Withdrawal | Payout asset, amount and recipient | | External action | Venue, route and input/output amounts | | Controlled spend | Controller calls and their authorization effects | | Payment session | Funding budget, merchant and lifecycle state | | Direct wallet submission | Submitting wallet and transaction metadata | ## Encryption and proof assumptions X-Wing protects recorded delivery using its hybrid cryptographic assumptions. Spend proofs use Groth16 over BN254, whose soundness still depends on elliptic-curve assumptions. Protecting encrypted delivery does not make that proof system post-quantum. Wallet-signature recovery inherits the security of the wallet key. Passkey and paper recovery are other access methods. Production key setup and independent circuit and contract review are still required. ## Network and service records An RPC operator or relay can see connection timing and the public requests sent to it. External services can keep content, IP and billing logs outside the Pool. Requests in one payment session remain linkable. Tell users what each part of your application publishes. Private transfers cannot make a provider's API logs or card records anonymous, and public venue execution has its own visible amounts. ## Screening Pending deposits Where a spend path requires it, direct Pending inputs are checked against the publisher's effective source policy. That check does not cover the entire ancestry of an Active note or give a regulatory verdict about its holder. A source-revealing Pending exit publishes the original deposit source and amount. The holder chooses a public payout recipient separately, so the path need not return money to the original depositor. --- # Controllers & Authorization Require a wallet or claim controller to approve spending a note. Source: https://docs.fuyu.xyz/protocol/controllers ## A controller adds approval The note commitment fixes its controller. The spend relation covers that field, and the Pool checks the controller before execution. A valid ownership proof and value conservation are still required. Ordinary notes use the same Pool without an extra wallet controller. Show whether approval is needed when the user opens the account or reviews a spend. ## Wallet and Safe approval A spending wallet can be an EOA, Safe or supported ERC-1271 account. A Safe applies its current quorum and authorization rules. Recovering private keys does not remove those approvals. The holder chooses this external authority. Owner changes, wallet upgrades and delegated account code can change whether an authorization is accepted later. ![Wallet and Safe approval diagram](https://docs.fuyu.xyz/diagrams/architecture.svg) ## Approve a claim or refund A claim controller supports a private payment to an unregistered wallet. Its descriptor fixes the recipient, refund signer and deadline. The recipient can authorize before the deadline; from the deadline, the sender's one-time refund signer can authorize the refund. The recipient is named onchain when the controller is deployed for claim or refund. Protect the claim secret and read the balance from authenticated history rather than amount hints in the link. ## Recheck at execution An ERC-1271 wallet can change policy or revoke approval after offchain verification. Recheck when the operation executes. The payment SDK rejects contract signers by default; enabling them requires a reviewed acceptance policy. Keep the original request and signatures during submission and recovery. A current controller check tells you whether that saved authorization can still execute. --- # Fees & Gas Read the relay fee policy and see who pays gas for each funding and payment path. Source: https://docs.fuyu.xyz/protocol/fees ## Protocol and relay charges The fee specification separates principal, relay service fees, gas and Fuyu Earn yield fees. Deposits have no protocol fee on principal. A relay may sponsor private sends and related operations, while public-amount operations can use its published service and gas schedule. Quote against the policy published by the selected runtime. Development prices and sponsorship apply to that configuration; do not hard-code them for another deployment. ## Calculate the fee in the client The app downloads the full schedule and calculates fees locally. This avoids revealing the private asset through an individual price request. The spend authorizes its fee and payee, so another submitter cannot redirect the payment. Calculate in token base units with integer arithmetic. The fee conversion rounds required amounts upward as described in the published policy. ![Calculate the fee in the client diagram](https://docs.fuyu.xyz/diagrams/payment.svg) ## Who pays gas? | Path | Gas payer | | --- | --- | | Direct deposit from a wallet | The funding wallet | | Relayed private operation | The relay hot wallet, under its sponsorship or fee policy | | Ordinary external transfer to a Portal | The external wallet or exchange | | Sponsored Portal setup and collection | The service operator | | Permissionless completion from your wallet | Your submitting wallet | | Direct recovery or withdrawal | Your submitting wallet | ## If the relay schedule changes A saved proof can have a fee below a new relay schedule. The relay may refuse it even while the Pool could still execute that authorization. Check current relay acceptance before retrying. Keep the saved authorization and reconcile its state first. Do not silently create a higher-fee proof from the same inputs while the original could execute. ## Fees on shares and tickets Show share or ticket units separately from their estimated underlying value. Yield fees follow the vault's accounting; they do not change the asset quantity recorded in an existing private note. Example yield rates and ETH prices in the repository illustrate its policy calculations. Use current deployment policy and price sources for actual quotes, and avoid presenting the examples as promised returns. --- # Smart Contracts Choose a contract for funding, private transfers, merchant payments or recovery. Source: https://docs.fuyu.xyz/protocol/contracts ## Choose a contract ActionPool holds supported assets and checks the proofs that spend private notes. The contracts around it handle receiving addresses, wallet approvals, prepaid payment budgets and calls to external venues. Choose the interface by the result you need: a private note, a public withdrawal, merchant credits or the output of a DeFi action. Your client keeps the private keys and note openings. It sends contracts the public proof signals, encrypted delivery envelopes and execution request. Sessions and subscriptions hold public budgets, so their parties, amounts and progress are visible onchain. Funding one with private assets makes that payment public, even if you later return a refund to the Pool. ![Choose a contract diagram](https://docs.fuyu.xyz/diagrams/architecture.svg) ## Contract map The names below refer to implementations in the protocol repository. Load addresses from the deployment your app uses. The same contract name on two chains refers to two separate deployments. Check the deployed code as well as any address predicted by a factory. | Component | Contracts | Responsibility | | --- | --- | --- | | Confidential custody | ActionPool, ActionPoolKernel | Hold assets, maintain notes and nullifiers, check screened spends, and settle withdrawals and actions | | Source admission | PolicySet, FuyuGovernor, FuyuCoverageRenewer | Maintain the source list, delay configuration changes, and renew coverage | | Proofs and hashes | PinnedSpendVerifier, SpendGroth16Verifier, Poseidon3, TreeConstants | Verify spends with a fixed key and compute scalar-field commitments and tree hashes | | Account recovery | FuyuAccountRegistry, FuyuAccountRegistryFactory | Store independent accounts, their fixed controllers and versioned encrypted profiles | | Receiving | FuyuReceiveDirectory | Publish versioned receiving descriptors with the public owner's approval | | Deposit addresses | FuyuDepositRecoveryPortal, FuyuAnonymousPortal, FuyuAnonymousPortalFactory | Receive ordinary ERC-20 transfers, then credit private notes or recover to a fixed destination | | Private claim links | FuyuClaimController, FuyuClaimControllerFactory | Authorize the recipient before a deadline and the refund signer afterward | | Public escrow | FuyuUnregisteredEscrow | Let a recipient claim a public token payment before a timed refund | | Atomic sequencing | FuyuTransactionRouter | Settle an action immediately or run up to eight private spends in order | | Venue execution | Yield, swap, plan, ticket and payment-credit adapters | Execute a fixed operation for one Pool and measure the input and output | | Payment budgets | FuyuPaymentSessions, FuyuPaymentAuthorizations, FuyuSubscriptionPayments | Settle cumulative vouchers, reserve holds and charge prepaid billing periods | | Payment funding | FuyuSessionFunding, FuyuPaymentFunding, FuyuPaymentSplitter | Deploy fixed funding terms, handle close/refund calls and pay fixed beneficiary shares | | Earn | FuyuEarnVault, FuyuEarnAdapter, FuyuEarnToken | Manage Flex, Term and withdrawal tickets, including their return to private notes | | Migration | FuyuMigrationReceiver, FuyuMigrationReceiverFactory | Receive assets from a fixed source and credit the chosen Fuyu account | | Venue catalog | ReviewedVenueRegistry | Track Active and ExitOnly venues against their code hashes and identities | ## Check the deployment Save the chain identifier, Pool address and deployment block before scanning history or making a proof. Read domain, spendVerifier, accountRegistry and policyPublisher from that Pool. The domain includes the chain and Pool address, so accounts and proofs from another deployment are not interchangeable. The deployment artifact should list the other contract addresses, their Pool or rail connections and expected runtime code hashes. Factory addresses also depend on the constructor terms. Check the factory and those terms before approving an allowance or sending assets to a Portal or escrow. Use the deployment manifest to configure the app, then read current state at a known block. Token support, route admission, source coverage and wallet policy can change after deployment. To check liquidity, query the venue; compiling its contracts locally tells you nothing about its live capacity. ## Who can change what The holder proves ownership of the input notes. If those notes have a spending controller, that controller must also approve execution. A relayer can submit the public inputs, but the proof fixes the recipient, fee payee and delivery envelopes. Anyone can finalize an action that has already executed; the finalizer cannot take its output. The publisher admits new tokens and adapter routes and manages source policies. After genesis, a governor delays proposals that widen admission. Disabling a token stops new deposits without blocking withdrawal of notes already credited in that token. The guardian can make specified risk-reducing changes but has no general permission to transfer assets. Each payment rail has its own authority rules. Voucher signers authorize cumulative earnings. Merchant operators capture registered holds. Any caller can charge the current subscription period under the fixed terms. Refunds always go to the recorded beneficiary, regardless of who calls the refund function. ## Submit and check an operation Load a deployment, check how its contracts connect, and recover history through finalized blocks. Read the state your operation depends on. Build the request, prepare the proof or signature, save the intent and simulate the transaction before submitting it. If submission times out, check its receipt and contract state before retrying. Contract amounts use native token units. Keep calculations in integers and convert values for display in your UI. Store the token address and decimals together; budgets, cumulative vouchers, minimum outputs and note amounts all depend on that asset identity. Confirm payment from settlement state, not an allowance change or HTTP response. - Read the Pool reference for custody, proofs and queued outputs. - Read Portals for wallet and exchange transfers into private balances. - Read payment rails for streaming, API usage, holds and subscriptions. - Read adapters for swaps, yield, ordered plans and asynchronous tickets. ## Reference revision This reference describes protocol revision 4def6e17d671d284e755a03d07d99a925b631512. Before using a venue, check that your Pool admits its adapter, ordered asset pair and operation. Source code for an adapter does not make that route available on every chain. The Networks guide lists deployment addresses, supported assets and faucets. This revision uses development proof keys. An independent audit, production key ceremony and mainnet release are still separate requirements. --- # ActionPool Fund private notes, spend them with proofs, and settle external actions through ActionPool. Source: https://docs.fuyu.xyz/protocol/contracts/pool ## What ActionPool holds ActionPool is the immutable custody contract. ActionPoolKernel tracks asset reserves, the lean note tree, spent nullifiers and receipts for actions awaiting finalization. During construction, ActionPool deploys its spend verifier and asks the supplied factory to create its account registry. It has no upgrade initializer or unguarded deposit entrypoint. Private balances are notes, not a balance mapping indexed by wallet address. Your client proves ownership and membership, supplies fresh nullifiers and commits to the outputs and public execution request. reserves(asset) counts credited private liabilities and leaves out unsolicited donations. Sending ERC-20 tokens straight to the Pool does not create a note or credit your account. ![What ActionPool holds diagram](https://docs.fuyu.xyz/diagrams/asset.svg) ## Fund a note The first profile deposit publishes encrypted recovery material and collects funds in one transaction. Later deposits must match the published block/hash pointer and the caller's funding nonce. Independent accounts instead identify the recovery wallet and account, registry revision and full profile hash. These checks keep a stale browser from funding the wrong profile. The Pool must receive exactly the requested ERC-20 amount. For native ETH, use address(0) and send matching msg.value. After collecting tokens, it checks the profile or account pointer again to catch changes made by a callback. If collection, pointer validation or note append fails, the transaction rolls back both the note and nonce. ```solidity function publishAndDeposit( address _asset, uint256 _amount, uint256 _ownerCommitment, bytes32 _recoverySalt, bytes calldata _ciphertext, bytes32 _policyCommitment ) external payable; function depositWithProfile( address _asset, uint256 _amount, uint256 _ownerCommitment, bytes32 _recoverySalt, uint64 _expectedBlockNumber, bytes24 _expectedCiphertextHash, uint64 _expectedNonce, bytes32 _policyCommitment ) external payable; function depositWithAccount( bytes32 _accountId, uint64 _expectedRevision, bytes32 _expectedProfileHash, uint64 _expectedNonce, address _asset, uint256 _amount, uint256 _ownerCommitment, bytes32 _recoverySalt, bytes32 _policyCommitment ) external payable; ``` ## Spend private notes Call transact with one Groth16 Proof, 39 ordered public signals, a Request, two delivery envelopes, the sender-recovery capsule and any controller signatures. Request holds recipient, relayer, deadline and two output policy commitments. Before settling, the Pool checks the domain, note root, operation layout, execution digest, deadline, nullifiers, tree capacity and proof. The two nonzero nullifiers must differ, and neither may be spent. Each nonzero output needs the delivery data committed by its proof. The spend relation also includes the full hash of the sender capsule. Public signal 38 names a controller when one is required; that controller must approve the proof, signals, request, capsule and verification-key hash under its current policy. Settlement consumes the input notes, appends nonzero outputs and subtracts the public payout and relayer fee from reserves. To pay part of a note, create a recipient note and a change note. Recovery can restore the private keys, but it never clears spent nullifiers or removes controller approval requirements. ```solidity struct Proof { uint256[2] a; uint256[2][2] b; uint256[2] c; } struct Request { address recipient; address relayer; uint256 deadline; bytes32[2] outputPolicyCommitments; } function transact( Proof calldata _proof, uint256[39] calldata _s, Request calldata _request, bytes[2] calldata _kemCiphertexts, bytes calldata _senderCapsule, bytes calldata _safeSignatures ) external; ``` ## Execute and finalize an action ActionRequest specifies adapter, operation, output asset, minimum output, owner tag, action data, recovery randomness, relayer, deadline and both output attachments. The Pool checks route admission and the adapter code hash. It approves only the input amount, measures the token changes and uses the resulting output amount for settlement. transactAction calls the public venue and reserves tree slots for the output. The first input nullifier identifies its settlement commitment. The output becomes a spendable note only after finalizeQueuedOnchain appends it. Anyone can finalize without a second proof, even if the route is later revoked or the source policy expires. transactActionAndFinalize executes the action and appends the output in one transaction, using the same authorization. A failed venue call, balance check or append rolls back token movement and nullifiers. Both paths use the same action digest, so someone holding a released proof can submit it through either path. | Entrypoint | Result | Check completion | | --- | --- | --- | | transactAction(...) | Executes the venue call and reserves an output receipt | queuedSettlementCM(firstNF) is nonzero | | finalizeQueuedOnchain(uint256 _firstNF) | Appends the reserved notes; anyone may call it | Receipt is cleared and ActionFinalized is emitted | | transactActionAndFinalize(...) | Executes the action and appends its measured output | Transaction succeeds and the account recovers the output note | ## Roots, screening and note attachments The lean note tree holds at most 2^32 typed leaves, counting slots reserved for queued actions. Published nonzero canonical roots remain valid permanently. Spent nullifiers prevent replay against an old root. Appending unrelated notes therefore does not force you to rebuild an otherwise valid proof. A screened Pending spend specifies the policy root, membership/non-membership mode and covered block. The policy must still use that root and mode, be active and unexpired, and cover at least the proved block. Increasing coverage keeps the proof usable; changing the source list may require another proof. Screening applies to direct Pending inputs, not the full ancestry of Active notes. notePolicyCommitment stores an opaque attachment for each issued commitment, including zero, and the attachment cannot change. The Pool never executes FPL or uses that attachment as a spend rule. An action fixes its attachments during execution and installs the same values when finalized. ## Spend verifier and hashes ActionPool deploys PinnedSpendVerifier itself. Call verifySpend with the Groth16 A/B/C points and 39 public signals in circuits/spend/public-layout.json order. Proof coordinates must be below the BN254 base-field modulus. The generated verifier also checks public scalar bounds before running the pairing check. VK_HASH identifies the embedded verification-key encoding and is included in controller approvals. The Pool deploys the Poseidon implementation used for note and policy trees. Its domain tags are fixed; TreeConstants supplies the source-policy sentinel and empty-root values. Use a matching circuit layout, verifier key, hash artifacts and client encoding. ## Read state and events Index Deposited for funding, EncryptedProfilePublished for encrypted profile versions, SpendRecorded for recovery data and ActionQueued/ActionFinalized for action progress. SpendRecorded contains the public signals, encoded request, delivery envelopes and capsule. Recovery can use these events even when a router or another wallet submitted the transaction. > **Check before making another proof**: After a timeout, inspect the original transaction, nullifiers and queued receipt. Cancelling locally cannot revoke a proof you already sent to another caller. | Read or error | What to check | | --- | --- | | domain(), spendVerifier(), accountRegistry() | The Pool's domain, verifier and account registry | | knownRoot(root), spent(nullifier) | Whether a root is accepted and an input has been consumed | | noteCount(), reservedLeaves() | Tree slots already used and reserved for queued outputs | | reserves(asset), supportedToken(asset) | Credited liabilities and admission for new funding or actions | | InvalidOperation() | Check context, current state, spent inputs and operation support | | InvalidProof() | The fixed spend verifier rejected the proof | | TransferFailed() | A token or payout call failed | | BadPolicy() | Check the policy schedule and screened spend inputs | --- # Deposit Portals Receive ERC-20 transfers at a Portal, then credit private notes or recover uncredited tokens. Source: https://docs.fuyu.xyz/protocol/contracts/portals ## Choose a Portal A Portal receives ordinary ERC-20 transfers from wallets or exchanges that cannot call the Pool directly. Funds arrive at the Portal first. A later Pool call creates the private note, so the sender's transfer receipt alone does not mean the recipient has a spendable private balance. FuyuDepositRecoveryPortal links to a public owner and their directory registration. FuyuAnonymousPortal uses an invoice tree, encrypted profile and recovery commitment without publishing a receiving-owner field. Both contracts expose funding assets, amounts, credit transactions and timing. The anonymous Portal omits the owner association; its funding transfer is still public. ![Choose a Portal diagram](https://docs.fuyu.xyz/diagrams/payment.svg) ## Owner-linked Portal Construction fixes owner, Pool, directory, Pool domain and the initial receiving-descriptor hash. The directory must point to the same Pool/domain, and the owner's starting descriptor must be active. Only that owner can credit private notes or recover uncredited tokens. Credit checks the current directory version, controller/owner/key descriptor and recovery material. Read the registration again when preparing a credit. A rotated descriptor can make an old request stale, and a keeper cannot resolve that by choosing another receiver. An ERC-20 balance does not identify who funded it. Transfer logs can help you match public transfers, but the Portal has no per-payer claim ledger. Recovery sends tokens to the fixed owner. Explain that to users before offering an owner-linked Portal for shared payment collection. | Field or event | Meaning | | --- | --- | | owner | The public account that can credit and recover tokens | | pool / poolDomain | The Pool that receives private credit | | directory | The owner's receiving registrations | | initialDescriptorHash | The descriptor selected at deployment | | Credited event | The asset and amount credited with a directory version | | Recovered event | Uncredited tokens returned to the owner | | StaleDescriptor / InvalidBinding | Reload the directory or check the deployed contracts | | InvalidAsset / InvalidAmount / TokenCallFailed | Check the asset, amount and token balance changes | ## Anonymous invoices The anonymous factory deploys a Portal from signed Setup terms. Setup contains invoiceDomain, invoiceRoot, invoiceCount, encryptedProfileHash, recoveryCommitment, setupSigner, passkeyDiscoveryKey and deadline. The factory connects it to a Pool and records authenticated discovery mappings. Save the setup payload and factory address with your recovery data. The depth-eight invoice tree covers the declared invoice range. Each Invoice has an asset, minimum and maximum amount, recovery salt and owner commitment. sweep takes the entire asset balance only if it is within those bounds. Set both bounds equal for an exact-amount invoice. invoiceLeaf(index, invoice) includes the Pool and invoice domain; sweep checks the next invoice with eight sibling hashes. Sending another asset or amount cannot change its terms. ```solidity struct Invoice { address asset; uint128 minAmount; uint128 maxAmount; bytes32 recoverySalt; uint256 ownerCommitment; } function invoiceLeaf(uint16 _index, Invoice calldata _invoice) public view returns (bytes32); function sweep( Invoice calldata _invoice, bytes32[8] calldata _siblings, bytes calldata _initialEncryptedProfile ) external; function recoverUncredited( address _asset, uint256 _amount, address _fallbackDestination, bytes32 _recoverySecret ) external; ``` ## Credit a transfer Before showing a payment address, check the deployed Portal and publish or save its invoice witness. Compare the asset contract, atomic amount and invoice index with the payer's review. For a predicted address, verify the factory, Setup and any code already deployed there. Anyone can call sweep once the entire asset balance is within the invoice's minimum/maximum range. The first credit needs the encrypted profile that matches the setup hash. Later credits use the Portal's existing Pool profile pointer and funding nonce. A successful sweep advances the invoice; a failed sweep leaves it unchanged and cannot redirect the note. Read Swept for invoice progress, InvoiceWitnessPublished for the invoice data and the Pool's Deposited event for the commitment. Recover the recipient note and check that commitment. Until credit succeeds, funds at the Portal remain public tokens, even if the sender's wallet calls the transfer complete. ## Recover uncredited tokens The recovery commitment includes the chain, Pool, invoice domain, fallback destination and secret. Opening it lets a caller recover only to that destination. Once recovery opens, private sweeps stop permanently. Choose recovery when you want to recover the remaining tokens rather than complete the invoice. Recovery reaches only tokens still at the Portal. Notes already credited in the Pool stay there. Save the recovery secret and destination before sharing the address, and keep the secret out of analytics and logs. Using it onchain makes the opening public. InvalidInvoice means the invoice or tree proof failed. InvalidProfile means the profile hash differs. InvalidRecovery means the recovery opening failed. Closed means recovery has already stopped private credit. Check the existing Portal state before creating another address or asking the payer to resend. > **The transfer is public**: A Portal receives public ERC-20 transfers. Successful Pool credit creates the private note, but the sending wallet, token and amount of the earlier transfer remain visible. ## Show payment progress Show the chain, token address, atomic amount, Portal address and current state. Use separate states for Awaiting transfer, Awaiting credit, Credited and Recovery opened. When a sponsored keeper is unavailable, a supported direct-wallet flow can call the same sweep and pay its gas. For recurring receiving, read discovery and invoice progress from the chain. Track transfers separately from credited invoices, especially when several transfers add up to one invoice. Balance arithmetic cannot authenticate a sender, and Portal recovery cannot retrieve funds already credited as private notes. --- # Controllers and Claim Links Require wallet approval for private spends and set recipient and refund windows for claim links. Source: https://docs.fuyu.xyz/protocol/contracts/controllers ## Ownership and wallet approval To spend a controlled note, you need its private ownership proof and the controller's current approval. The note commitment includes that controller, and the spend relation reveals it during execution. Recovering a profile restores keys; the EOA, Safe or contract wallet still has to approve notes assigned to it. The Pool computes an EIP-712 approval digest from the chain, Pool/domain, controller, operation kind, proof, all 39 signals, encoded request, sender capsule and verification-key hash. Sign this digest for the final transaction. A signature for a quote, recipient label or earlier proof cannot replace it. ![Ownership and wallet approval diagram](https://docs.fuyu.xyz/diagrams/recovery.svg) ## Wallet signatures WalletAuthorization handles spend approvals and recovery-configuration approvals. EOAs use canonical low-s ECDSA with 64-byte compact or 65-byte signatures. Contracts use an ERC-1271 envelope or Safe-compatible checks. During static wallet calls, msg.sender remains the calling Pool or registry; wallets that inspect the caller must allow that address. An ERC-1271 envelope starts with the four-byte FUYA magic 0x46555941, then scheme byte 0x01 and the wallet's signature. A contract without that envelope must return a positive initialized getThreshold() and accept checkSignatures for the supplied preimage and digest. If its chosen check fails, Fuyu rejects the approval without trying another scheme. Fuyu uses the Safe's own owner count and threshold rules. The wallet checks its policy at execution time. If owners, threshold or ERC-1271 policy change while an operation is pending, check whether the approval still works before retrying. ```solidity function safeApprovalDigest( Proof calldata _proof, uint256[39] calldata _s, uint8 _operation, bytes32 _requestHash, bytes calldata _senderCapsule ) public view returns (bytes32); // Contract-wallet envelope: FUYA || scheme 1 || signature // 0x46555941 || 0x01 || ``` ## Claim before a deadline, refund afterward FuyuClaimController controls a private claim-link note. Its Pool/domain, recipient wallet, distinct refund signer and nonzero deadline are immutable. Before the deadline, only the recipient can approve a spend. At or after it, only the refund signer can. The windows never overlap and use Unix seconds. The controller holds no assets or note keys. Spending needs both the link's private note material and the wallet approval for the current window. Having the link alone is insufficient. After a successful claim or refund, Pool nullifiers prevent another spend of those inputs. The factory predicts the controller with CREATE2, and anyone can deploy it with those terms. You can issue the note before deploying the controller. Deployment reveals recipient, refund signer and deadline onchain, so a later claim can expose authorization details that were absent when the note was issued. | State | Authorized wallet | Effect | | --- | --- | --- | | Before deadline | recipient | Approve the controlled note's spend | | At/after deadline | refundSigner | Approve a refund spend | | Before controller deployment | No hook code yet | The note can commit to the factory's predicted address | | Controller deployment | Any caller who pays gas | Recipient, refund signer and deadline become public | | After successful spend | Neither can reuse inputs | The Pool keeps their nullifiers spent permanently | ## Controller payload getThreshold() returns two as the claim controller's Safe-compatible hook marker. This does not require a user's ordinary Safe to have two owners. checkSignatures rebuilds the Pool digest from Authorization and checks the cosignature from the recipient or refund signer whose window is active. Start the payload with 130 zero bytes, then abi.encode(Authorization). Authorization contains operation, proof, 39 signals, encoded request, capsule hash, verification-key hash, output-opening fields and cosignature. The controller ignores the output-opening fields for authorization. Signal 38 must identify this controller. ```solidity function predict( address _pool, address _recipient, address _refundSigner, uint64 _deadline ) public view returns (address); function deploy( address _pool, address _recipient, address _refundSigner, uint64 _deadline ) external returns (address controller); function getThreshold() external pure returns (uint256); function checkSignatures( bytes32 _dataHash, bytes calldata, bytes calldata _signatures ) external view; ``` ## Public token escrow FuyuUnregisteredEscrow holds a public ERC-20 payment. open fixes token, recipient, refundTo, amount, deadline and clientRef. Only the recipient can claim before the deadline. Afterward, funds can be refunded to refundTo. The escrow moves through Missing, Pending, Claimed and Refunded states without creating private notes. escrowId is derived from the sender and client reference. Retry with matching terms to identify the same escrow; different terms raise ConflictingRetry. This is a public escrow payment. Its claim state tells you nothing about whether a separate controlled private note has been spent. ## Check a failed claim MalformedAuthorization means the header, payload layout or controller signal failed. DigestMismatch means Authorization rebuilds a different Pool digest. ClaimNotAuthorized and RefundNotAuthorized mean the active wallet rejected the signature. InvalidConfig points to invalid Pool, wallet or deadline terms. Check the recipient, refund signer and deadline before issuing the note. Store its recovery material separately from signatures. After a timeout, inspect the original note nullifier and controller terms before making another claim or automatically signing a new proof. --- # Payment Rails Use prepaid sessions, authorization holds and subscriptions, with fixed funding and payout terms. Source: https://docs.fuyu.xyz/protocol/contracts/payment-rails ## Prepaid public budgets Payment rails hold public budgets for API usage, streaming, authorization/capture and recurring access. Once earnings settle, they become backed credits that cannot be reversed. Parties and request amounts remain visible. The rail authorizes payment; it does not prove service delivery. To bring settled credits into the private Pool, use a separately admitted payment-credit adapter action. Amounts use native asset units. Session, payment and subscription IDs derive from payer and salt and can be used only once. Save the chain and rail address with the ID for each offchain request. Credits represent settled earnings or refunds. A provisional hold or unclaimed budget has not yet become transferable credits. ![Prepaid public budgets diagram](https://docs.fuyu.xyz/diagrams/integration.svg) ## Cumulative sessions FuyuPaymentSessions fixes its asset and dispute period at deployment. openSession collects the full initial budget and fixes merchant and voucher signer. A zero signer uses the payer. The payer can top up until requesting closure. Vouchers specify total merchant earnings; claim pays only the increase over what was already claimed. Anyone can relay a claim, and its credits go to the fixed merchant. Only the merchant can call claimAndRedeem, which redeems the newly claimed credits. Only the payer can call requestClose; this stops top-ups and starts the dispute window. Claims stop at closeAt. Anyone can call finalizeClose to credit the unused remainder to the payer, while finalizeCloseAndRedeem is payer-only. ```solidity function openSession(address _merchant, address _voucherSigner, uint256 _amount, bytes32 _salt) external returns (bytes32 sessionId); function topUp(bytes32 _sessionId, uint256 _amount) external; function voucherDigest(bytes32 _sessionId, uint256 _cumulativeAmount) public view returns (bytes32); function claim(bytes32 _sessionId, uint256 _cumulativeAmount, bytes calldata _signature) external returns (uint256 settledAmount); function requestClose(bytes32 _sessionId) external; function finalizeClose(bytes32 _sessionId) external returns (uint256 refundedAmount); ``` ## Reserve a hold, then capture FuyuPaymentAuthorizations fixes merchant, optional operator, authorization signer, refund receiver and budget. A zero operator uses merchant, and a zero signer uses payer. Authorization signs paymentId, requestId, ceiling, validUntil and nonce. The merchant/operator must reserve the hold onchain before relying on the ceiling. Until then, cancellation or another hold may use the available budget. reserve locks the full ceiling, consumes the request and nonce, and checks the signer once. A hold can last at most 30 days. Registered holds remain valid through payer cancellation or a later signer-policy revocation, until they are captured, voided or expired. Cancellation prevents new holds. capture takes cumulativeAmount and credits only its increase. Repeating a target does not charge twice. finalCapture releases the unused remainder; capturing the full ceiling closes the hold even without that flag. Anyone can expire a hold after its deadline. Released funds return to available budget, or to the refund receiver's credits if the payment was cancelled. ```solidity function reserve(bytes32 paymentId, bytes32 requestId, uint256 ceiling, uint64 validUntil, uint256 nonce, bytes calldata signature) external; function capture(bytes32 paymentId, bytes32 requestId, uint256 cumulativeAmount, bool finalCapture) external returns (uint256 capturedAmount, uint256 releasedAmount); function expireHold(bytes32 paymentId, bytes32 requestId) external returns (uint256 releasedAmount); function cancelPayment(bytes32 paymentId) external returns (uint256 refundAmount); ``` ## Prepaid subscriptions FuyuSubscriptionPayments fixes merchant, refund receiver, amountPerPeriod, periodSeconds, startAt, expiresAt, maxPeriods and budget. Creation collects the budget without charging a period. Anyone can charge the current calendar period once. Missed periods cannot be charged later. Each charge mints merchant credits and updates paidUntil. Only the payer can cancel, which stops future charges and refunds remaining reserve. After expiry, anyone can call refundExpired for the fixed refund receiver. Charged credits stay with the merchant. A partial final period costs the full fixed amount, so use a period-boundary expiry if you want full periods. currentPeriod returns the current index, start/end and chargeable flag. Simulate charge before submitting it, since another worker can charge first and cause PeriodAlreadyCharged. Your application decides how payment affects access, usually by reading finalized paidUntil. ## Fund a deterministic escrow FuyuSessionFunding and FuyuPaymentFunding predict and deploy immutable escrows from fixed terms, chain and rail/asset identities. Anyone can deploy or activate a funded escrow without gaining signer or refund rights. Deploying the same terms returns the same escrow; activation can happen only once. In a session escrow, sessionKey authorizes closure and refundReceiver receives refunds. The multi-rail escrow supports session, authorization and subscription kinds, with a budget, funding deadline and active expiry. Reaching active expiry allows a caller to trigger closure or cancellation, but a caller must send that transaction. Session dispute windows and registered holds keep the rights their rails provide. Before funding, check the predicted address, rail and asset code, authority and refund terms. After activation, read the rail's opened ID. Recover uncredited assets or forward settled refund credits through the escrow functions. If activation times out, check its state before sending another budget. ## Redeem credits and split payouts FuyuPaymentCreditLedger provides transferable credits backed by equal underlying units for authorization and subscription rails. Sessions have their own equivalent credit functions. redeem burns the caller's settled credits and sends the same number of underlying units to the receiver. Balance checks reject inexact transfers. Verify the backing asset address rather than relying on the credit symbol or decimals. FuyuPaymentSplitter fixes its credit ledger, asset, beneficiaries, shares and payout mode. creditPending and assetPending show what each beneficiary is owed. Anyone can distribute, but only the recorded beneficiaries get paid. redeemCredits works only in asset payout mode and cannot select another recipient. | State | Events and errors | | --- | --- | | Session earnings and closure | VoucherClaimed, CloseRequested, SessionClosed; InvalidVoucher, ClaimWindowEnded, CloseNotReady | | Hold capture or release | HoldReserved, HoldCaptured, HoldVoided, HoldExpired; InsufficientAvailableBudget, AuthorizationExpired | | Subscription billing | PeriodCharged, SubscriptionCanceled, SubscriptionRefunded; PeriodAlreadyCharged, SubscriptionInactive | | Escrow activation and refund | Activated, RefundCreditsForwarded, AssetsRecovered; BindingChanged, FundingExpired, InsufficientFunding | | Credit transfers and payouts | Transfer, CreditRedeemed, PaymentReleased; InexactTransfer, InsufficientBacking, WrongPayoutMode | ## Implement the merchant flow Save an operation record for every voucher, hold request or subscription period. Check signatures against the rail's digest function and read finalized settlement state before delivering irreversible service. For cumulative usage, track authorized earnings separately from settled earnings. Stop accepting new session usage when closure starts. Reserve holds before committing billable work, and use finalized payment state for subscription access. Run a worker for close, hold expiry and refund forwarding if your product needs prompt completion. Your service still needs to account for usage honestly; the contracts enforce payment authority. --- # Routers and Adapters Batch private spends and run fixed swap, yield or payment-credit operations through the Pool. Source: https://docs.fuyu.xyz/protocol/contracts/routers-adapters ## How calls reach a venue The Pool holds private assets and checks proofs. An adapter executes a specific operation at a public venue. The router calls existing Pool functions in order. The proof fixes the private receiver, so neither the router nor the adapter can substitute another recipient. A route key contains adapter, uint8 operation, input asset and output asset, in that order. The Pool records the admitted adapter runtime hash and checks privacyPool. Reversing direction or changing the operation or pair needs a separate admission. Deploying an adapter is only the first step; the publisher must admit its route before the Pool can use it. ![How calls reach a venue diagram](https://docs.fuyu.xyz/diagrams/architecture.svg) ## Transaction router FuyuTransactionRouter holds no tokens or allowances and has no privileged role. transactActionAndFinalize forwards an action to the Pool and emits ActionSettledInOneTransaction. The Pool appends the measured output note before the transaction completes. Any failure reverts the call. transactBatch forwards one to eight TransactCall entries in order, each with its own authorization. A later proof can refer to the root created by an earlier call in the transaction. This lets you chain change notes for multi-recipient sends or consolidate notes without waiting between transactions. EmptyBatch and BatchTooLarge reject calls outside those bounds. A submitted bundle runs atomically, but anyone who sees its proofs can also submit them individually to the Pool. Design each proof as a complete authorized payment. Releasing a bundle does not revoke those individual submission paths, and secrecy is not an execution guarantee. ```solidity struct TransactCall { ActionPoolKernel.Proof proof; uint256[39] signals; ActionPoolKernel.Request request; bytes[2] kemCiphertexts; bytes senderCapsule; bytes safeSignatures; } function transactBatch(TransactCall[] calldata _calls) external; // MAX_BATCH = 8 // IActionAdapter callback; implemented by adapters and called only by the Pool. function execute( uint8 _operation, uint256 _amountIn, uint256 _minOut, uint256 _deadline, bytes32 _actionData ) external returns (address tokenOut, uint256 amountOut); ``` ## Adapter types Only the Pool can call execute. The adapter takes a positive exact input and returns the output token and measured amount. Its constructor and operation rules constrain actionData and the permitted venue calls. A caller cannot use it to forward arbitrary targets or calldata. | Adapter | Calls | Output | | --- | --- | --- | | FixedShareYieldAdapter | Deposit into or redeem from one configured ERC-4626 vault | Vault shares or underlying | | ReviewedFixedShareAdapter | Use a vault after checking its additional identity pins | Shares or underlying | | AaveV3StataAdapter | Use the configured Aave static-aToken dependencies | Static shares or underlying | | MorphoV1SteakhouseAdapter | Use the configured Morpho-v1 vault | Vault shares or underlying | | DolomiteDUSDCGuardedAdapter | Use dUSDC after checking the Dolomite identity and guards | dUSDC or underlying | | UniswapV3ActionAdapter | Swap through one router, factory, pair, fee and direction | Measured swap output | | UniswapV3VaultActionAdapter | Run a fixed swap and vault path | Vault shares or public swap output | | FuyuPlanAdapter | Run the steps and identities fixed at construction | Final token from the atomic plan | | AsyncRedeemTicketAdapter | Request, harvest or settle a withdrawal at one asynchronous vault | Ticket, harvested asset or refunded shares | | FuyuPaymentCreditAdapter | Redeem credits from one issuer for their backing asset | One underlying unit per credit unit | | FuyuEarnAdapter | Call one FuyuEarnVault | Flex/Term shares, series tickets or underlying | ## Fixed multi-step plans FuyuPlanAdapter fixes the input/output, steps, code hashes and static identity checks at deployment. A plan has at most four steps. It supports Uniswap V3 exact-input single-hop or two/three-hop paths and ERC-4626 deposit/redeem. Every token on the plan is distinct. Read steps, tokens, codePins, identityPins and planDigest to inspect what the adapter will execute. The proof sets one final minimum. The adapter derives earlier floors when the remaining vault steps have deterministic previewMint or previewWithdraw conversions. Otherwise, an earlier step must produce a nonzero output and the final minimum checks the overall result. Users cannot replace targets or supply arbitrary intermediate floors at execution. Each step's reported output must match measured balance changes. The final step pays directly to the Pool. After execution, adapter balances must return to their starting values, allowances must clear and identities must still match. StepFailed wraps a venue revert, StepInexact reports dishonest or partial effects, and StepBelowFloor reports a short output. Any of these rolls back the whole action. ## Asynchronous withdrawals When a vault accepts only a withdrawal request, the underlying is not available yet. AsyncRedeemTicketAdapter issues a fungible ticket for the requested position. You can hold that ticket in a private Pool note. harvest settles venue requests that are ready and records the assets or cancelled shares received. Use lifecycle, batchCount and previewClaim to show pending, claimable and refundable positions. A later private action consumes tickets to claim underlying or refund shares. Previews reflect the current venue state; a submitted request still needs settlement. Show ticket units separately from their estimated underlying value and retain the ticket token address. ## Redeem settled payment credits FuyuPaymentCreditAdapter supports REDEEM = 0 and requires actionData zero. It fixes Pool, credit issuer, backing asset, chain and code hashes. Input must be positive and fit uint128. The output minimum must also be positive and no greater than the input. The adapter checks Pool and adapter balances, the credit supply burn and the underlying gain. Redemption must return one underlying unit per credit unit. It cannot reserve holds, authorize usage or claim an unsettled session. First settle the earnings or refund on the rail; only then are the credits transferable. ## Add an adapter route Choose an operation with known input and output assets. Record dependency code hashes, transfer behavior and receiver restrictions. For upgradeable venues or tokens, also check implementation or registry state where needed; a proxy's runtime hash alone will not identify its implementation. Use exact-transfer nonrebasing assets unless your accounting design handles other behavior. Build the quote and proof with the same route, amount and minimum. Before broadcasting, check venue identity, capacity and expiry again. Test reentry, dishonest reports, changed dependencies, partial pulls, donations, leftover approvals and failure at the final append. After revoking new action admission, verify that holders can still exit directly and finalize queued outputs. DeFi calls expose input, intermediate and output amounts, venue paths and timing. They omit the private note owner, but those public amounts and times can still link activity. Explain that visibility in the product instead of describing the venue call as confidential. --- # Policies and Governance Manage source policies, delayed configuration changes and coverage renewal. Source: https://docs.fuyu.xyz/protocol/contracts/policies ## Source policies and note attachments PolicySet decides source admission for screened Pending inputs. notePolicyCommitment is an opaque attachment used for holder-run queries; the Pool never reads it. A source-policy change can affect a Pending spend. A note attachment cannot restrict that spend. A source policy records root, epoch, coverage, publication block, activation block, exclusive expiry and mode. Mode zero requires membership; mode one requires non-membership. Coverage is the latest completed deposit block included in the policy. The Pool's fixed minDelay sets the minimum Pending age in completed blocks, not seconds. ![Source policies and note attachments diagram](https://docs.fuyu.xyz/diagrams/disclosure.svg) ## Update a source list The candidate source set is a depth-32 authenticated interval tree. Addresses are encoded as uint160(source) + 1, which lets the tree represent address zero without using its lower sentinel. publisherInsertPolicySource checks the predecessor path, then the next empty slot against the intermediate root. The publisher cannot supply an arbitrary replacement root. Deletion checks the predecessor and target intervals. It updates the predecessor first and verifies the target against that intermediate root. Deleted slots stay unused. PolicyInserted and PolicyDeleted describe candidate changes; PolicyScheduled records the root, mode and schedule for screened spending. publisherPublishPolicy requires coverage to precede the publication block, activation no earlier than the current block, and expiry after activation. An unactivated schedule cannot be replaced. effectivePolicy switches to the scheduled policy at activation. It can return an expired record, so also check its validity interval. ```solidity struct Policy { uint256 root; uint64 epoch; uint32 coverage; uint32 published; uint32 activate; uint32 expires; uint8 mode; } function effectivePolicy() public view returns (Policy memory); function publisherPublishPolicy( uint8 _mode, uint32 _coverage, uint32 _activate, uint32 _expires ) external; ``` ## Delayed proposals FuyuGovernor publishes Pool configuration and manages its own roles. Council and guardian must be contract accounts. Its fixed delay is at least seven days and no more than 90 days. councilPropose records an ordered array of target/data calls and salt. Once ready, anyone can execute those calls within the 14-day grace window. After genesis, adding token or route support, widening source admission and changing roles require delayed proposals. The governor allows specific targets and selectors rather than arbitrary calls. During genesis, the fixed operator can configure the deployment without delay until genesis closes or 30 days pass. governanceAdmitRoute checks the adapter code hash and can protect an exit route. successor announces a Pool for voluntary migration. Holders must choose to migrate; setting successor cannot replace their Pool or move their notes. ```solidity struct Call { address target; bytes data; } function proposalId(Call[] calldata _calls, bytes32 _salt) public view returns (bytes32); function councilPropose(Call[] calldata _calls, bytes32 _salt) external returns (bytes32 id); function execute(Call[] calldata _calls, bytes32 _salt) external; function governanceAdmitRoute( address _adapter, uint8 _operation, address _assetIn, address _assetOut, bytes32 _codeHash, bool _protected ) external; ``` ## Guardian and reviewer permissions The guardian or council can immediately revoke an unprotected route and cancel eligible proposals. A standalone proposal replacing the guardian has special veto rules so the outgoing guardian cannot block its replacement indefinitely. Immediate source denial applies only to the effective DENY list, with a shared limit of 64 successful additions per UTC day. This quota limits additions, not who can be targeted or how far the anonymity set can shrink. Calls on either side of a UTC midnight can use twice the daily quota in a short interval. Removing sources or widening admission still needs governance after genesis. The reviewer can extend coverage only if the candidate root matches the effective root. Renewal keeps the mode and cannot reduce coverage or expiry. The reviewer cannot replace the list. Governance can schedule activation at most 300 blocks ahead, with policy lifetime between 7,200 and 2,628,000 blocks. | Role | Permission | Constraint | | --- | --- | --- | | Council | Propose wider admission and role changes | Wait for the execution delay; calls must pass validation | | Guardian or council | Revoke routes and veto eligible proposals | Protected exits and guardian replacement have special rules | | Guardian or council | Add sources to DENY | Current root/mode must match; at most 64 additions per UTC day | | Reviewer | Extend coverage of the list in force | Keep root/mode and do not shorten coverage or expiry | | Genesis operator | Configure the new deployment | Genesis closes explicitly or after 30 days | ## Renew coverage when the operator stops Install FuyuCoverageRenewer as the governor's reviewer to enable a public renewal path. It fixes governor and optional operator at deployment, holds no funds and has no setters. operatorRenew forwards a schedule through the reviewer checks. operatorRenewAfter creates a schedule that activates when the transaction executes. Anyone can call renew after 3,600 blocks without an operator renewal, if coverage lags by at least 3,600 blocks and the 3,600-block public rate limit permits it. Renewal covers the previous block and activates immediately. Expiry is at least 100,000 blocks later, while any longer existing expiry is preserved. renewStatus returns a refusal selector, nextBlock, proposed coverage and expiry. nextBlock assumes no intervening state changes. A pending schedule, edited candidate list or replacement reviewer can change the result. Handle NotDue, OperatorActive, RateLimited, SchedulePending, ListChanged and NotReviewer instead of estimating readiness from time alone. ## Prepared proofs and exits A screened proof works while its root and mode remain in force, the policy is active, and coverage reaches the block named by the proof. Renewing the same list keeps the proof and its controller approval usable. A denial or another root can require a new proof. Anyone can still finalize an action that has already executed, regardless of new route admission or source coverage. A source-revealing exit publishes one full Pending deposit's original source and amount. The holder chooses the public withdrawal recipient separately. This exit does not require return to the original sender and gives no compliance verdict. Governance cannot change the private ownership relation or transfer note custody. Publisher decisions can still affect new admission and whether Pending notes can be spent. Show your deployment's publisher and active schedule so users can see who controls those decisions. --- # Accounts and Receiving Directory Store encrypted account records and publish receiving descriptors with wallet approval. Source: https://docs.fuyu.xyz/protocol/contracts/accounts ## Account records and receiving descriptors FuyuAccountRegistry catalogs optional, independently recoverable accounts under recovery wallet A. FuyuReceiveDirectory publishes the public owner's opt-in private receiving descriptor. Both store public records or encrypted data; neither stores plaintext private balances, decrypts profiles or replaces note ownership proofs. During construction, the Pool uses FuyuAccountRegistryFactory to fix its accountRegistry. Each account row includes Pool/domain, recovery wallet, nonzero accountId, revision, fixed spending controller and encrypted profile/recovery envelope. A directory entry instead links a public owner to the current controller, receiving owner root and KEM key hash. ![Account records and receiving descriptors diagram](https://docs.fuyu.xyz/diagrams/recovery.svg) ## Read account records Use accountCount and accountIdAt to discover wallet A's account IDs, or accountIds to read pages of up to 100 IDs. account returns revision, update block, controller and both encrypted records. profilePointer returns the revision and profile hash needed for guarded funding. Your client creates the recovery envelope. The contract checks its length and approval but cannot check whether it decrypts. Before publishing, reopen the profile with the intended recovery method and verify the account you derive. Registration confirms the write was authorized; you must test recovery separately. | Field or limit | Meaning | | --- | --- | | revision | A uint64 version that increases and must match before an update | | updateBlock | The block where the record was published | | controller | Wallet B chosen at registration; zero uses the ownership proof alone | | profile | Encrypted profile, between 48 and 2,048 bytes | | recoveryEnvelope | Encrypted wallet recovery material, between 48 and 32,768 bytes | | accountId | A nonzero independent ID under wallet A | | MAX_PAGE_SIZE | Read at most 100 IDs per page | ## Register or update an account Recovery wallet A calls register for an unused accountId, creating revision one. If controller B is nonzero, B must sign the FuyuAccountConfig digest. update takes the expected current revision and keeps the controller chosen at registration. B approves the next revision and hashes of both replacement ciphertexts. The EIP-712 configuration includes Pool, Pool domain, recovery wallet, accountId, controller, revision, profile hash, recovery-envelope hash and deadline. The deadline is inclusive; uint256 maximum means no expiry. Wallet checks are static and run before storage writes. A stale revision or rejected approval leaves the row unchanged. Use empty signature bytes when controller is zero. Otherwise, use the shared EOA, Safe or explicitly selected ERC-1271 signature format. Registry approval and Pool-spend approval sign different types, domains and payloads, so get a separate signature for each. ```solidity function register( bytes32 _accountId, address _controller, bytes calldata _profile, bytes calldata _recoveryEnvelope, uint256 _deadline, bytes calldata _controllerSignature ) external; function update( bytes32 _accountId, uint64 _expectedRevision, bytes calldata _profile, bytes calldata _recoveryEnvelope, uint256 _deadline, bytes calldata _controllerSignature ) external; ``` ## Publish a receiving descriptor FuyuReceiveDirectory fixes Pool and Pool domain. get(owner) returns version, active status, controller, ownerRoot and kemKeyHash. The descriptor hash covers the receiving terms; publishDigest also includes owner, active/revoked state, nonce and deadline. Anyone can relay publish with the owner's signature. EOAs use canonical 65-byte ECDSA, and contract owners use ERC-1271 directly. The directory does not accept the Pool's FUYA envelope or compact-signature format. A publication increments version and requires nonce to equal the current version. An active descriptor needs a nonzero scalar-field owner root and a 1,216-byte KEM public key. Validate the key encoding in your client before paying. To revoke, send zero controller, zero owner root and empty key bytes. That publishes an inactive entry; old notes and their controller requirements remain unchanged. ```solidity function get(address _owner) external view returns ( uint256 version, bool active, address controller, uint256 ownerRoot, bytes32 kemKeyHash ); function publish( address _owner, address _controller, uint256 _ownerRoot, bytes calldata _kemPublicKey, bool _active, uint256 _nonce, uint256 _deadline, bytes calldata _signature ) external; ``` ## Use the current record for funding depositWithAccount uses msg.sender and accountId to choose the account. Supply its current nonzero registry revision, full profile hash and guarded account deposit nonce. The Pool checks them before and after collecting tokens. A stale tab, concurrent update or callback therefore cannot redirect credit to another account record. Wallet-scoped profile funding instead uses latestEncryptedProfilePointer: a uint64 publication block and the leading 24 bytes of the ciphertext hash. Keep this namespace separate from account-bound funding. A Portal publishes and deposits under its own caller address, not the address that sent it ERC-20 tokens. For a directory payment, read an active descriptor at a known finalized block and validate its key before building delivery. Include its version/hash in an owner-linked Portal credit review. If the owner rotates the descriptor, refresh it before preparing the next payment. ## Venue registry ReviewedVenueRegistry records reviewed ERC-4626 manifests onchain. It fixes governor and Pool and stores adapter, underlying/share identities, code hashes and guard digest under the manifest digest. Before governorActivate succeeds, the Pool must admit both supply and redemption routes with the reviewed adapter hash. governorExitOnly can mark a venue ExitOnly only after both action routes are revoked. Holders can then use an ordinary public share-token exit; the external redemption adapter is disabled. effectiveState checks current code, identities and routes and returns Unknown if they disagree with the stored state. Use that check instead of trusting a stored Active row. ## Events and errors AccountUpdated emits recovery wallet, accountId, revision, controller and ciphertexts. The directory's Published event emits descriptor version and receiving public key. Anyone can read these records to discover and recover published data, while the secret contents remain encrypted. > **Publishing links a wallet to receiving keys**: A wallet-linked receiving descriptor is optional for ordinary private use. Explain this public association before asking the owner to sign a publication. | Error | What to do | | --- | --- | | InvalidRevision | Reload the row and review its next revision | | InvalidConfiguration | Check IDs, ciphertext lengths, deadline and Pool/registry connection | | InvalidAuthorization | Request approval of the configuration from the fixed controller | | InvalidNonce / NonceExhausted | Reload the directory version; an exhausted version cannot advance | | InvalidDescriptor | Check active/revocation fields, scalar root and key length | | Expired / InvalidSignature | Check signed terms and the owner's current policy | --- # Earn Contracts Use Flex shares, Term shares and withdrawal tickets through the Earn vault and Pool adapter. Source: https://docs.fuyu.xyz/protocol/contracts/earn ## Flex, Term and tickets FuyuEarnVault invests through one configured ERC-4626 venue and tracks Flex shares, Term shares and withdrawal tickets. The vault is the Flex token. term() returns the Term token, and ticket(series) returns an asset-denominated ticket. These public ERC-20 positions can also be held in private Pool notes when the tokens and routes are admitted. Flex accepts deposits and redeems shares for underlying. Term uses supplyTerm, then requestWithdrawal to issue a series ticket, and claim when its window opens. A withdrawal request gives you tickets while you wait for underlying. Read the series and window before telling a user they can claim. ![Flex, Term and tickets diagram](https://docs.fuyu.xyz/diagrams/asset.svg) ## Deposit and redeem Flex Use totalAssets, previewDeposit, previewRedeem, maxDeposit and maxRedeem for amounts and limits. deposit must receive exactly the underlying amount before minting shares to the receiver. redeem consumes authorized shares and pays measured underlying. Shares and underlying have separate units; their conversion follows the venue and current vault accounting. The vault supports only part of the ERC-4626 API. mint and withdraw are unsupported, their max functions return zero, and previewMint/previewWithdraw revert. Use deposit and redeem for exact-input flows. A generic ERC-4626 helper must not assume that the other methods work. ```solidity function deposit(uint256 _assets, address _receiver) external returns (uint256 shares); function redeem(uint256 _shares, address _receiver, address _owner) external returns (uint256 assets); function supplyTerm(uint256 _assets, address _receiver) external returns (uint256 shares); function requestWithdrawal(uint256 _shares, address _receiver) external returns (uint256 tickets, uint256 series); function claim(uint256 _series, uint256 _tickets_, address _receiver) external returns (uint256 assets); ``` ## Request and claim Term withdrawals Term has its own asset bucket and share conversion. previewSupplyTerm estimates shares, previewRequest estimates tickets, and requestWithdrawal returns the issued ticket amount and series. Scheduling uses a one-week period, three-day offset and four-period notice rule, with eight rotating series. Read currentSeries, requestClaimWindow and claimWindow for the applicable dates. claimOpen tells you whether a series is claimable, and previewClaim estimates its payout. claim burns eligible caller-owned tickets and pays the asset to the receiver. For ClaimClosed, InvalidSeries or ExceedsLimit, check the window, series and amount. A preview does not reserve the venue's liquidity. Store the ticket token address with the position. Different series are different assets even if the UI uses the same label. The private action's output asset must match the series selected at execution, so check it at review and again before broadcasting. ## Earn adapter operations FuyuEarnAdapter fixes Pool, vault, underlying, Term token, deployment chain and runtime hashes. route(operation) returns the input/output pair. Only the Pool can call execute. It requires a positive input and minimum, actionData zero, a valid deadline and unchanged contract identities. The adapter consumes the input, calls the vault operation and returns one measured output to the Pool. Queued or immediate finalization then creates the private settlement note. Targets and calldata come from the adapter's code, not the user. | Operation | Input | Output | | --- | --- | --- | | 0: SUPPLY_FLEX | Underlying asset | Vault/Flex shares | | 1: REDEEM_FLEX | Vault/Flex shares | Underlying asset | | 2: SUPPLY_TERM | Underlying asset | Term shares | | 3: REQUEST | Term shares | Ticket for the current series | | 8 + s: CLAIM | Ticket for series s, 0 ≤ s < 8 | Underlying asset | ## Fees and administration FEE_BPS is 1,000, a 10% fee on Flex yield. The current protocol-share basis points divide that fee between Term boost and treasury. MAX_PROTOCOL_BPS is 5,000, and protocol-share changes take effect after the 30-day delay. Boost cycles last seven days. Yield estimates follow venue performance and current accounting; they are not promised returns. adminProposeProtocolShare schedules a change, and currentProtocolShareBps reads the effective value. An admin transfer requires nomination and acceptance. sync updates accounting, collectTreasury pays accrued treasury value, and claimVenueRewards handles the reviewed venue rewards. The admin has no permission through these functions to change private note ownership. Follow FlexFeeAccrued, BoostCycleStarted, ProtocolShareProposed/Applied and TreasuryCollected when explaining share-value changes. Display underlying, Flex, Term and ticket values separately. If a ticket valuation is unavailable, show that status instead of counting it as zero in a total. ## Build the Earn flow Check asset, venue, treasury, admin and share-token addresses and route admission at a known block. Simulate the full Pool transaction as well as reading vault previews. Deposits, redemptions and venue calls reveal public asset amounts even when the input was a private note. After supply, check the measured shares and recover their note. After a Term request, show the ticket series and notice/claim state. After claim, confirm the finalized output and change. A queued receipt still needs finalization before the private balance is spendable. Test same-block window changes, minimum-output failures, inexact transfers, wrong series, revoked supply and remaining exit routes. Query capacity instead of assuming it from a deployed vault address. If maxDeposit is zero on a network, supply needs another usable reviewed venue. > **Check venue capacity**: Supply and redemption depend on the venue's current capacity, token behavior and the routes admitted by your Pool. ## Handle a failed Earn action OnlyPrivacyPool means a caller tried to execute the adapter outside its Pool. VenueChanged means the chain or code differs. InexactInput and InexactConsumption mean measured balances failed their checks. InsufficientOutput means the output missed the proof's minimum. For Insolvent or ClaimClosed, inspect the vault accounting, venue and claim window. If submission times out, check the original nullifier, ActionQueued/ActionFinalized events and ticket/share position. The transaction may already have spent the input, so check before making another action. --- # Migration Receivers Receive a source withdrawal, credit a fixed private account and recover uncredited funds after a deadline. Source: https://docs.fuyu.xyz/protocol/contracts/migration ## Source and receiving account FuyuMigrationReceiver credits the existing Fuyu funding interface with immutable Terms. These include source kind, contract and code hash, target Pool/domain, chain, asset, private owner commitment, recovery salt, encrypted profile hash, output attachment, expected amount, refund recipient and deadline. The source protocol checks its own proof, and Fuyu keeps its existing screening rules. When the receiver deposits into Fuyu, the Pool records the receiver as the funding source. The configured source identifies the withdrawal route; it cannot replace that deposit-source record. ![Source and receiving account diagram](https://docs.fuyu.xyz/diagrams/integration.svg) ## Receiver terms The constructor rejects an unknown source kind, missing source/Pool code, a different source runtime or wrong chain/domain. It also rejects an invalid owner commitment, missing salt/profile hash, zero or over-uint128 expected amount, invalid refund recipient or elapsed deadline. The Pool must admit an ERC-20 settlement asset; address(0) means native ETH. The source-kind enum contains TornadoClassic, PrivacyPoolsV1, PrivacyPoolsV2, ZkMoney and AztecConnect. Each source deployment still needs a working withdrawal executor. Check its adapter, recipient, calldata and recovery path before enabling that source in the UI. | Term | What it fixes | | --- | --- | | source / sourceCodeHash | The withdrawal call target and its reviewed runtime | | pool / poolDomain / chainId | The receiving deployment and note domain | | asset / expectedAmount | The token and atomic amount to credit | | ownerCommitment / recoverySalt | The private receiving account | | encryptedProfileHash / policyCommitment | The recovery bytes and note attachment | | refundRecipient / refundAfter | Who receives public recovery funds, and when | ## Credit funds or execute a withdrawal complete takes the encrypted profile matching the stored full hash and deposits expectedAmount from funds already at the receiver. This confirms available funds without authenticating their origin. The receiver allows multiple completions, so a donation cannot consume it permanently before the intended withdrawal arrives. execute calls the fixed source and measures the new asset balance. It accepts no source allowance, escrowed call value, arbitrary target or replacement destination. For ordinary source kinds, the new receipt must equal expectedAmount. PrivacyPoolsV2 can return more than its reviewed minimum; the receiver credits the whole new receipt, up to uint128. If the receipt check or Fuyu deposit fails, the transaction rolls back the source withdrawal and its nullifier. Completed includes the completion sequence, termsHash, amount and sourceCallVerified. Use that flag to tell an atomic source call from completion of a balance already held. ```solidity function available() public view returns (uint256); function complete(bytes calldata encryptedProfile) external; function execute(bytes calldata sourceCalldata, bytes calldata encryptedProfile) external; function completeRemainder(bytes calldata encryptedProfile) external; function refund() external; function recover(address recoveryAsset, uint256 amount) external; ``` ## Credit a remainder or resume a flow After at least one reviewed amount has been credited, completeRemainder deposits the full remaining balance to the same private owner. It must be nonzero and no larger than expectedAmount. The caller cannot change the amount, asset or destination. The first credit publishes the stored profile in the same transaction. Later credits use the receiver's existing Pool profile pointer and funding nonce. Save the account's recovery material and test reopening it; the contract checks a ciphertext hash, not whether the holder can decrypt it. If a withdrawal is interrupted, check the source receipt, receiver balance, completionCount and Fuyu deposit events. Find the outcome at the original receiver before funding another. Confirm both that the source withdrawal succeeded and that the private account recovered its Fuyu note. ## Recover after the deadline At refundAfter, anyone can call refund. It marks the receiver cancelled and sends its available settlement balance to refundRecipient. Already credited Pool notes stay private and cannot be recovered this way. Tokens arriving after cancellation can still be recovered. recover can return a wrong asset at any time or the settlement asset after cancellation. Every payout uses the fixed destination. Save the receiver address, terms, profile and source operation reference before starting a withdrawal. | Error | Check before retrying | | --- | --- | | SourceChanged | The source runtime on the selected chain | | InexactSourceReceipt | The new receipt amount against expectedAmount or its minimum | | InvalidProfile | The profile bytes and full hash | | InexactDeposit / InsufficientFunds | The receiver balance and Pool token changes | | Expired / RecoveryNotAllowed | Cancellation state and refund deadline | | RemainderNotAllowed | Whether a prior completion exists and the full remainder fits the limit | ## Receiver factory FuyuMigrationReceiverFactory has initCodeHash, predict and create for Terms plus userSalt. The address includes the factory and constructor data. Before funding, compute the terms hash independently and compare the factory runtime and deployed receiver fields. Enable migration separately for each source. The receiver handles funding and credit, but a working route also needs a source withdrawal method and proof, a supported target asset and an account the holder can recover. Verify those pieces before advertising the source as integrated. --- # Run Infrastructure Run deployment, relay and recovery services without holding private account secrets. Source: https://docs.fuyu.xyz/infrastructure ## Services around the Pool Deploy the contracts and distribute their authenticated proof files. An app operator can also serve configuration, submit relay transactions, collect Portal deposits and store encrypted backups. An auditor uses their own chain source and trust data. Give each service only the inputs it needs. The relay uses public proof data without spend secrets. A backup service can store ciphertext while account history stays private. ![Services around the Pool diagram](https://docs.fuyu.xyz/diagrams/architecture.svg) ## Choose what to operate | Role | Inputs | Keep working | | --- | --- | --- | | Deployment operator | Reviewed contracts, network profile and authorities | Runtime and proof-file authentication | | Relayer | Public request, deployment configuration and gas | The approved request and transaction status checks | | Portal keeper | Published invoice witness and delivery data | Credit to the invoice's recipient | | Artifact host | Authenticated proving and verification files | Download digest checks | | Recovery host | Static bundle and a holder-selected RPC | Account access and the original exit tools | | Auditor | Program, answer and independent finalized history | Verification of the stated question | ## Start with a fork The repository runtime starts a disposable fork and development API. Use it for development and acceptance tests. Run contract and proving work on the provisioned Linux environment. To serve another network, review its assets, external contracts and proxy implementations with the routes and runtime profile. After deploying the Pool, test the app and relayer against that deployment too. ## Prepare for interrupted operations Retain requests and transaction hashes after failures. Watch reserved actions that need finalization and keep a reproducible static recovery bundle. Back up the payment ledger separately from encrypted account backups. Show whether a failure came from the service or the chain, and offer the next completion or exit step available for the saved operation. --- # Deployments & Artifact Pins Deploy the contracts and record the hashes needed to authenticate them. Source: https://docs.fuyu.xyz/infrastructure/deployment ## Record deployment identity Record the chain, Pool, verifier and hash contracts, receiving directory, routers, assets and routes. Keep runtime hashes and deployment blocks alongside the proof files served by the app. For external proxies, record the implementation slot and implementation hash too. Their behavior can change while the proxy bytecode stays the same. ![Record deployment identity diagram](https://docs.fuyu.xyz/diagrams/architecture.svg) ## Run the deployment script Select a network profile and inspect it before running the core script. It writes addresses and code hashes to your output directory. Give every attempt a fresh directory. The script cannot resume a failed deployment. Start again with fresh output rather than treating partial results as complete. Keep deployer signing material in local secret storage, outside committed configuration. ```bash # Run from the protocol checkout on the provisioned Linux host. # Supply reviewed RPC, deployer and governance configuration externally. export FUYU_NETWORK=sepolia export FUYU_OUT=/absolute/path/to/fresh-deployment-output node contracts/script/deploy-core.cjs ``` ## Configure governance The publisher admits tokens and routes and manages source policy. The governor adds delayed admission and council, guardian and reviewer roles. Use deployer-as-publisher only for development or testnet deployments. Review token transfer behavior and external dependencies, then test original exit behavior. Setting governance roles does not perform those checks for you. ## Check the release Record the source revision, reproduced contract files and proof-key hashes. Run funded app flows and recovery tests, then verify the public runtime serves that same deployment. Contract deployment success is only one part of this process. The repository uses development proof keys. Production key setup is still required, and a checked-in network profile or fork report cannot tell you which public mainnet deployment is currently served. - Check the chain and contract code before funding or proving. - Check served proof-file digests and the Pool verifier hash. - Test ordinary exit as well as admitted actions. - Save the recovery bundle's hash and its deployment trust data. --- # Relayers & Runtime Submit prepared proofs, check transaction status and finish pending settlement. Source: https://docs.fuyu.xyz/infrastructure/relayer ## Relay a prepared request The holder sends a proof and public inputs. Before broadcasting, the relay checks the deployment and verifier, route, reserves and fee policy. Private witnesses stay in the browser. The relay can refuse or delay submission. It cannot change the authorized recipient or outputs and keep the proof valid. Its own wallet appears as the public sender instead of the holder's transaction wallet. ![Relay a prepared request diagram](https://docs.fuyu.xyz/diagrams/architecture.svg) ## Start the development runtime Run the queue bootstrap and API in separate processes with the same runtime directory. They use a disposable fork, public proof files and a test sponsor. Production operation needs its own deployment and service setup. ```bash # Separate terminals on the provisioned Linux development host: node apps/privacy/runtime/queue-chain-bootstrap.cjs node --experimental-strip-types apps/privacy/runtime/queue-api.cjs ``` ## Check before sending Check Pool and verifier identity along with current routes and assets. Estimate and simulate the transaction at a consistent block, then save its broadcast intent. After sending, check the receipt; simulation cannot guarantee the eventual result. Give requests stable status lookups by transaction hash and chain state. If HTTP loses a response, use those lookups instead of automatically creating a second proof or transaction. ## Run a payment worker SessionManager needs a durable merchant store and a backend that can submit claims. Its worker settles accepted vouchers and watches closure. Run paid provider jobs in your application separately. Allow for RPC age, clock skew and confirmations inside the close window. The session backend checks read age; confirmations and readConfirmations affect when changes are observed. Stop acceptance on stale or backward state until it is reconciled. ## Complete credits and actions A Portal keeper credits the recipient named by the invoice. An action finalizer appends the measured output already fixed by execution. Neither can choose a new private recipient. Anyone can call these transitions, but they still need gas and available public witness data. Monitor unfinished work and offer the holder a direct way to finish it. --- # Service-independent Recovery Keep the app, proof files and deployment data users need during a service outage. Source: https://docs.fuyu.xyz/infrastructure/recovery ## Ship recovery with the deployment The recovery design combines a static app bundle identified by its hash and a holder-selected RPC. It lets the holder reopen an account, rebuild history and finalize queued actions, then use the original withdrawal path without the operator's API. Distribute the bundle with the deployment. Preserve the codecs, proof files and contract identity needed by notes issued under that release; a future recovery page would not help users who need those files now. ![Ship recovery with the deployment diagram](https://docs.fuyu.xyz/diagrams/recovery.svg) ## Files and keys to retain | Artifact | Used for | | --- | --- | | Static app and worker code | Open the account, find notes and prepare proofs | | Proving and verification artifacts | Run the original relations and check verifier identity | | Deployment trust data | Authenticate the chain, Pool, directory and runtime | | Historical note and delivery codecs | Read earlier key generations and account history | | Encrypted operation bundles | Restore proofs and signatures that were never broadcast | | Holder's passkeys or paper words | Open the private account without operator records | ## Read history from another RPC Check the RPC's chain and contract code against deployment data. Rebuild notes from public history and validate decrypted outputs before adding them to the spendable balance. A cached balance without those checks is historical display data. Audit verification has a stricter history requirement: it reconstructs all finalized events from the deployment block. A checkpoint sufficient for an account scan can still omit events the auditor needs. ## Finish or withdraw from a wallet Finalize a reserved receipt if the action has already returned its output. For an ordinary direct withdrawal, use the supported proof and submit from the holder's wallet. It pays gas and is publicly linked to that operation. Controlled notes still need controller approval. A Pending source-revealing exit publishes additional information. Present those as separate choices so the holder knows which authority and disclosure each step requires. ## Test with the service blocked In a fresh browser, block the app service and use the saved static bundle with an independent RPC. Restore the account keys, find its notes, reconcile an interrupted operation and complete a supported exit. Record which deployment and devices you tested, including the funded result. Checking source files or finding an archive cannot tell you whether a user can actually complete recovery on that deployment. --- # Contract Addresses Find each Sepolia contract, what it does and which Fuyu deployment uses it. Source: https://docs.fuyu.xyz/infrastructure/contract-addresses ## How these addresses were checked We checked every contract in the two deployment tables on Ethereum Sepolia through an independent RPC on 2026-10-02. Each had runtime code, and its Keccak-256 hash matched the value in the corresponding API configuration or source deployment file. All reads used block `11828202`, hash `0xb613d35efdf70ee1b2457cd67935556530a66f911a368b67d6d5481425302abe`. The hosted API and this source revision select different Pools. The first table shows the API response from the check; the second shows the active source profile at revision `4def6e17`. Both sets exist onchain. To use either one, match it with the app build and deployment manifest, then check the route's current liquidity before submitting an action. Keep each table's contracts together. Both use chain ID `11155111`, but their Pool domains and constructor-bound settings differ. The public app's recovery URL for the new source bundle returned 404 during the check. The bundle is in the repository; you'll need a reachable copy on the host you use for recovery. > **Deposit through the app or a Portal**: Use the app's deposit transaction or a Portal whose address and invoice you've checked. Sending a regular ERC-20 transfer to a Pool, router, directory, registry, verifier or factory won't create a private note. ## Hosted API deployment · Sepolia The [public configuration](https://api.fuyu.xyz/api/queue/config) returned the following deployment on 2026-10-02. The Pool was deployed at block `11797824`. Its block hash matched `0x5773781d9f24271571b096deb33e2954f3f1b8cf9320ce8c4945de9e19402c89` when read through the independent RPC. This Pool's domain is `4527036073603490995570783483612003915492427550420872067287949540190896173749`. We checked the directory and account registry with `pool()` and `poolDomain()`, the router with `pool()`, and the Portal factory's binding getters. Their values all matched this Pool and domain. | Contract | Address | Responsibility | | --- | --- | --- | | ActionPool | [0x83CE32c83913c4637A635c997B161ecCA732c97B](https://sepolia.etherscan.io/address/0x83CE32c83913c4637A635c997B161ecCA732c97B) | Private note state, proofs, nullifiers, reserves and queued settlement | | Poseidon hash child | [0xb859BfC7f3DDed7Ad0F9575B9C8C0EeDD2D73333](https://sepolia.etherscan.io/address/0xb859BfC7f3DDed7Ad0F9575B9C8C0EeDD2D73333) | Hashes notes and tree entries for this Pool | | FuyuGovernor | [0x50dba5871536179aa66932eF1D1e882df4B0B204](https://sepolia.etherscan.io/address/0x50dba5871536179aa66932eF1D1e882df4B0B204) | Source-policy and asset/route governance | | FuyuReceiveDirectory | [0xb49b9D0B908c64523Df47DeF5eDA005d361e68D4](https://sepolia.etherscan.io/address/0xb49b9D0B908c64523Df47DeF5eDA005d361e68D4) | Authenticated public receiving descriptors | | FuyuAccountRegistry | [0x5DC9241Ce36F17f241f3d13d8E97865cC5B89e6e](https://sepolia.etherscan.io/address/0x5DC9241Ce36F17f241f3d13d8E97865cC5B89e6e) | Versioned encrypted account profile and controller registration | | FuyuAccountRegistryFactory | [0xa53A81445F22a9F948A3DF0Bff42d1556967fEB1](https://sepolia.etherscan.io/address/0xa53A81445F22a9F948A3DF0Bff42d1556967fEB1) | Creates the account registry associated with a Pool | | FuyuUnregisteredEscrow | [0x7C110b6AEe5D76C69De148fBfd16eD8DE9B6F71D](https://sepolia.etherscan.io/address/0x7C110b6AEe5D76C69De148fBfd16eD8DE9B6F71D) | Public payments to unregistered wallets | | FuyuTransactionRouter | [0xBB14D2C1005CaA92Ef2d32b54771852180Bb46af](https://sepolia.etherscan.io/address/0xBB14D2C1005CaA92Ef2d32b54771852180Bb46af) | Atomic queued settlement and bounded chained spends | | Claim controller factory | [0xD08a887F76952160D4De9b35E8125cd38FaA3ed5](https://sepolia.etherscan.io/address/0xD08a887F76952160D4De9b35E8125cd38FaA3ed5) | Deploys recipient/refund-authorized claim controllers | | Anonymous Portal factory | [0x0c01D28C34a348aE8B1645eF68B2c8FA25bA0616](https://sepolia.etherscan.io/address/0x0c01D28C34a348aE8B1645eF68B2c8FA25bA0616) | Creates immutable recipient-bound deposit Portals | | Reviewed Aave ETH adapter | [0x92C7aB53cf70C8666022a2edccB8A8149D97f7bE](https://sepolia.etherscan.io/address/0x92C7aB53cf70C8666022a2edccB8A8149D97f7bE) | ETH supply to and redemption from the configured static WETH vault | | USDC → ETH swap adapter | [0xF027452a6D4a803b59c320F63099670F7efE394f](https://sepolia.etherscan.io/address/0xF027452a6D4a803b59c320F63099670F7efE394f) | Approved exact-input Uniswap V3 route | | ETH → USDC swap adapter | [0x837b7F0bAEaD17a758ee69ce94Ab66109d75F48B](https://sepolia.etherscan.io/address/0x837b7F0bAEaD17a758ee69ce94Ab66109d75F48B) | Approved reverse Uniswap V3 route | ## Checked-in deployment · Sepolia In the source, `SEPOLIA_ACTIVE_PROFILE` selects `SEPOLIA_NATIVE_ETH_PROFILE` and the separate deployment below. Its Pool was deployed at block `11812881`. The independent RPC confirmed block hash `0x8855e6d17dd0dbf009a18a9f595b0e37afc11e29d62a2ed5eb74f6b63a854544`. This deployment uses domain `2123002541694988798946165044072273737634637675085476779155179838890530815293`. Reads of its directory, registry, router and Portal factory matched the Pool. Use these addresses when working with this source release; at the time of the snapshot, the hosted API still returned the earlier set shown above. | Contract | Address | | --- | --- | | ActionPool | [0x8AF98425649a9b9581eAA1E70F25Bab18b2E79Ce](https://sepolia.etherscan.io/address/0x8AF98425649a9b9581eAA1E70F25Bab18b2E79Ce) | | Poseidon hash child | [0x83d53f2B215D79D52100Ad04991ba3802d00Ae8B](https://sepolia.etherscan.io/address/0x83d53f2B215D79D52100Ad04991ba3802d00Ae8B) | | FuyuGovernor | [0x88155AC3bbb8FA91bF7399545252Eda67379890C](https://sepolia.etherscan.io/address/0x88155AC3bbb8FA91bF7399545252Eda67379890C) | | FuyuReceiveDirectory | [0x174Ad2404262614D6ED3bE26489a22f7b4Dd50a4](https://sepolia.etherscan.io/address/0x174Ad2404262614D6ED3bE26489a22f7b4Dd50a4) | | FuyuAccountRegistry | [0x2474fD71c22Cd39C462336676c20af3acd32ccD3](https://sepolia.etherscan.io/address/0x2474fD71c22Cd39C462336676c20af3acd32ccD3) | | FuyuAccountRegistryFactory | [0x7f7A3140A9145c7c30128E6BA26dC60f65B78a0C](https://sepolia.etherscan.io/address/0x7f7A3140A9145c7c30128E6BA26dC60f65B78a0C) | | FuyuUnregisteredEscrow | [0x565000b97198Df16a8d11cCbcBDFe75d35e33610](https://sepolia.etherscan.io/address/0x565000b97198Df16a8d11cCbcBDFe75d35e33610) | | FuyuTransactionRouter | [0x5B960678f585625EB53F675A38dd126Ad2B2a146](https://sepolia.etherscan.io/address/0x5B960678f585625EB53F675A38dd126Ad2B2a146) | | Claim controller factory | [0xDa9A87619873c5F965bE3F99B98dC6BE1D807216](https://sepolia.etherscan.io/address/0xDa9A87619873c5F965bE3F99B98dC6BE1D807216) | | Anonymous Portal factory | [0xB20cDF916d9170325503dCD8fE212bA21deA5DCc](https://sepolia.etherscan.io/address/0xB20cDF916d9170325503dCD8fE212bA21deA5DCc) | | Reviewed Aave ETH adapter | [0x482DB2219Ec2Cb4B3E8C5C9798bd91d2De55c92c](https://sepolia.etherscan.io/address/0x482DB2219Ec2Cb4B3E8C5C9798bd91d2De55c92c) | | USDC → ETH swap adapter | [0xa17ac228Cf4509e77f7eE5833D4958880eE552db](https://sepolia.etherscan.io/address/0xa17ac228Cf4509e77f7eE5833D4958880eE552db) | | ETH → USDC swap adapter | [0x8157056135bd0091b8D85449Fa457E87Db572a54](https://sepolia.etherscan.io/address/0x8157056135bd0091b8D85449Fa457E87Db572a54) | ## Shared test assets and external venues Both releases use the same Aave test USDC, test WETH and static WETH share. The token runtime hashes matched their source and configuration values. We also found code at the configured Uniswap V3 venue. Before using a venue, check its route manifest and, for a proxy, the implementation and code hashes required by that manifest. The route list contains `aave-eth-supply`, `aave-eth-redeem`, `swap-usdc-eth` and `swap-eth-usdc`. Each swap direction has its own adapter, with V3 fee `100`, or 0.01%. Use only the assets and token pairs allowed by your selected deployment. Deploying an adapter doesn't enable every pair that venue can trade. | Item | Sepolia address | Meaning | | --- | --- | --- | | Aave test USDC | [0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8](https://sepolia.etherscan.io/address/0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8) | 6 decimals | | Aave test WETH | [0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c](https://sepolia.etherscan.io/address/0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c) | 18 decimals; configured wrapped-native asset | | Static WETH share | [0x162B500569F42D9eCe937e6a61EDfef660A12E98](https://sepolia.etherscan.io/address/0x162B500569F42D9eCe937e6a61EDfef660A12E98) | 18 decimals; underlying is Aave test WETH | | Uniswap V3 USDC/WETH venue | [0xAd5fF0b22E32FC8aCA003816cF298143DaCC7FbD](https://sepolia.etherscan.io/address/0xAd5fF0b22E32FC8aCA003816cF298143DaCC7FbD) | Check the configured route and current liquidity before swapping | ## Governance and the public payee The hosted configuration names council Safe `0x26c3D140adAbDFbE1c8C606a07CA9914774437Fe` and guardian Safe `0xDFFe775E0d1CF40e801E7D2C99fe940d03677112`. Their runtime code matched the configured Safe proxy hash. The configuration lists Safe 1.4.1, a threshold of one and one development owner. Read the current Safe owner and threshold settings when checking who can authorize governance actions. Both deployments name `0x03cAe8cb91623fa968b4B9c2Bc2b4b97f988B857` as the public relayer/payee. Proof fees go to that configured address. Use the app's funding destination for deposits; this payee address isn't a user Portal or a recovery key. The relay can submit from a separate hot wallet while keeping the proof's fee payment bound to the payee. The configured governor delay is `604800` seconds, seven days. Whether genesis is still open can change while that delay stays fixed. Read the governor's current state before assessing a proposed action; a boolean saved in the deployment JSON can be out of date. ## Verify a contract identity Check `eth_chainId`, the deployment block and its canonical hash, the full runtime code hash, the Pool domain and `VK_HASH()`. Check the directory, account registry, router, Portal factory and routes against that same Pool. Use your release manifest to decide which contracts to accept, even when an explorer displays verified source code. Constructor values are part of a Pool's deployed runtime. Compare the correct hash: a creation-artifact SHA-256 and a deployed-runtime Keccak-256 describe different bytes. For a proxy, also check its implementation slot and implementation code against the venue manifest. The proxy's own bytecode can stay unchanged when its implementation changes. Both Pools returned verification-key identifier `0x9be4fc098eacb83c4f84f0bca3a466803158f921960f8ac2981372aadd49352d`. They share that verifier identifier, but keep their proofs and companion contracts tied to the correct deployment. The Pool domains and protocol-context behavior differ. ## Historical and local contracts The source also includes older Sepolia profiles for Pools `0xF3cbf96f000C29F85693b667469828f328be6C03` and `0xf174039a78F094de36B89c441a70F669D01b434f`. Use them to understand earlier releases. Choose the selected deployment's funding flow for new deposits. The current recovery registry has one entry, `sepolia-8af98425`; before using an older checked-in directory, check that the app and proof context still support it. Each disposable fork bootstrap creates fresh Pool and companion addresses. Read its `config.json` and exported `deployment.json` to find them. There is no shared local Pool address you can reuse across runs. For another public network, obtain and check that network's manifest before adding its addresses to your integration. --- # Proof Artifacts & Verification Keys Download, host and check the files used to prove private spends and holder disclosures. Source: https://docs.fuyu.xyz/infrastructure/proof-artifacts ## What each proof file does To prove a spend in the browser, load the witness-generation WebAssembly file, Groth16 proving key and JSON verification key. The browser uses the JSON key to check its proof locally, then submits the proof and public inputs. Onchain, the Pool checks them with its fixed verifier. Transactions don't upload a replacement verifying key. Fuyu uses one private-spend relation and two holder-audit step relations. `spend/admission.circom` handles private transfers, consolidation, withdrawals and admitted actions with 39 public inputs. `owned-notes-4.circom` processes four padded note slots per audit step. `spend-records-8.circom` processes eight padded authenticated spend records. An independent verifier checks holder audit answers offchain against finalized history. The app checks each artifact's SHA-256 before loading it. You can move a file to another CDN or static host, provided the bytes match and the app accepts the deployment and artifact settings. Treat the download URL as a location and the digest as the file identity. ![What each proof file does diagram](https://docs.fuyu.xyz/diagrams/disclosure.svg) ## Private-spend files and hashes The source and public API configuration list the same digests for these three spend files. During the check, GET requests for the WASM and proving key succeeded with the sizes below. We closed those streams after the first 16 bytes. We downloaded the whole JSON verification key and confirmed its SHA-256. The large files' listed hashes come from the source and configuration; we didn't rehash their full hosted downloads. The proving key's source filename is `TEST-ONLY-UNISWAP-SETTLEMENT.zkey`. Use it with the configured routes. The Pool and runtime still check the route, public context, controller approvals and token effects, so the filename doesn't grant permission to execute arbitrary Uniswap calls. | Role and service path | Expected bytes | SHA-256 | | --- | --- | --- | | Witness program · /artifacts/queue-private.wasm | 2583534 | f2359cf11cc8a1708fb57b7b27989662f59ed9ec065985d49c0d0237317afad0 | | Proving key · /artifacts/queue-private.zkey | 68769773 | bfcf453c294e56fc37d38a3d1af25eb7e56e7e5df0c9d4de9f4e571bd04440dd | | Local verification key · /artifacts/queue-private-vk.json | 9887 | 3f0d7f8bcafceb54c3a452156d3cbc15c4414955c3b1ff0d64d9719d6be69a8e | ## Holder-audit files and hashes The audit companion serves the six files below from the directories you configure. Git LFS stores four large WASM and proving-key files under `circuits/owned-notes/artifacts`. The two JSON verification keys are under `apps/privacy/public/audit-keys`. Their paths and hashes are listed in `apps/privacy/runtime/audit-artifacts-manifest.json`. The holder worker checks the proving files before using them. The independent verifier checks the verification-key bytes for the audit relation. Keep these checks separate from the Pool's spend verification: an audit answer uses its own relations, artifacts and offchain verification flow. | Manifest path | SHA-256 | | --- | --- | | owned-notes-4_js/owned-notes-4.wasm | b0c7db68d0a6f0da7d975d41cd3338e6db656b4ee7f8739bfd1390fab705b463 | | TEST-ONLY-owned-notes-4.zkey | 323b4a50d8f82e1f90ed8550170376f8ffc2f55cae0b64ca474a5673744ffabf | | TEST-ONLY-owned-notes-4-vk.json | b244f82bf1b564987e5528c2adf3e51372651ced4526d378035e29a8df25ed54 | | spend-records-8_js/spend-records-8.wasm | b0ea4ce8280cb6105642dc87181e728a1cb658bb552a181ea6c8e89a50ce4906 | | TEST-ONLY-spend-records-8.zkey | 813b24cbfde966b9bc6922655b64909961e5f0a94d897829755162d4c50c8612 | | TEST-ONLY-spend-records-8-vk.json | 457307e28269e2cb0def19f894ef6dfa0329c58c5e3fa1a5ea8ad83a992c4307 | ## Check the files, relation and onchain key Pull Git LFS files before hashing artifacts. Otherwise, you may be looking at a pointer instead of the proving key. Check the circuit include graph with `circuits/source-artifact-manifest.json`, run the repository artifact checker, and read `Pool.VK_HASH()` for the deployed verifier. The onchain verification-key Keccak-256 is `0x9be4fc098eacb83c4f84f0bca3a466803158f921960f8ac2981372aadd49352d`. It hashes the canonical verifier-key encoding. The JSON file has a separate SHA-256, so compare each value with the format expected by the browser, exporter or contract you're checking. Run artifact and circuit verification on the Linux development host. A successful key-to-relation check confirms which compiled relation and transcript the key uses. Then run the application checks you need for your change and keep the setup records with the result. ```bash # Run in the protocol checkout on the Linux development host. git lfs pull python3 scripts/check-artifacts.py node circuits/scripts/check-sources.cjs node apps/privacy/runtime/audit-artifacts.cjs check \ --directory "$PWD/circuits/owned-notes/artifacts" \ --keys "$PWD/apps/privacy/public/audit-keys" ``` ## Test-key setup These checked-in keys are test-only. The circuit documentation records single-party phase-two contributions over the public `ppot_0080_17.ptau` transcript, size `2^17`, SHA-256 `f807e065fde53f72f4bf4d57140fab85b26daa6cc95bdfec7cce93622b3a367c`. Keep the setup identified as a test contribution when distributing the files or deploying an app that uses them. Keep that label visible in the development app. Compilation checks the relation, `snarkjs zkey verify` checks the key against its relation and transcript, and onchain key checks compare the deployed verifier. A successful testnet spend confirms that transaction's verification. These checks don't add contributors to the single-party setup or create a production ceremony. > **Test-only keys**: Keep TEST-ONLY in bundle and operator documentation. Hosting these files on a new domain, CDN or network still uses the same test setup. ## Serve and cache verified artifacts For disclosure development, start the loopback artifact companion with all six files. It checks their hashes before listening, serves only the allowed paths and rejects a file if it changes. If you use a separate host, set the artifact base URL in the app and allow the app's origin in the host's CORS configuration. The app caches spend artifacts by SHA-256 and rehashes entries when it reads them. It discards a mismatched entry and downloads it again. Prefetch can run while account history is recovering; if the user starts proving before the download finishes, they still wait for the remaining bytes. Keep account secrets, recovery words and private witnesses out of this public cache. ```bash node apps/privacy/runtime/audit-artifacts.cjs serve \ --directory "$PWD/circuits/owned-notes/artifacts" \ --keys "$PWD/apps/privacy/public/audit-keys" \ --port 8799 # In a second Linux terminal: FUYU_AUDIT_ARTIFACTS_SERVER=http://127.0.0.1:8799 \ npm --prefix apps/privacy run preview ``` ## Export a service-independent bundle The static exporter reads public deployment state at one anchor block and checks the contracts and proving files. It writes `deployment.json` and hash-named artifacts to a fresh directory, leaving out RPC credentials, demo accounts, process IDs and private account material. When opening the app, supply the SHA-256 of the deployment JSON you intend to use. The source recovery entry `sepolia-8af98425` lists deployment JSON SHA-256 `a6fcfabb28d713a212ff12e2b4df602d64ec5d04125e88bb7b091f47ff9ce9ad` and checked block `11812907`. Download it from the host you plan to use and check its hash. The expected app-host URL returned 404 during the documentation check, so confirm a reachable copy before depending on this bundle for recovery. ```bash node apps/privacy/runtime/queue-static-deployment.cjs \ --config /absolute/path/to/runtime/config.json \ --out /absolute/path/to/fresh-bundle # Serve the exported directory with the required CORS policy. # Open the matching app with: # ?deployment=&deploymentSha256= ``` --- # Local Development & Testing Start a private fork, run the API and app, and test against the contracts from your own build. Source: https://docs.fuyu.xyz/infrastructure/local-development ## How the development runtime works The protocol repository includes Solidity contracts, Circom relations, the browser app, SDK and local runtime. The runtime starts a disposable fork, deploys a fresh Pool and its companion contracts, and runs a loopback API. The browser worker prepares proofs while the holder's private witnesses and note secrets stay in the browser. Use the provisioned Linux development host for protocol builds, proof generation, Solidity suites and funded browser acceptance. Give each run a fresh output directory and keep its source and build manifests. For an integration test, start the runtime alongside your frontend preview so the browser can reach the chain and test contracts. The app's fork chain ID is `31350`. The fork reads Ethereum mainnet state at block `26038058`, hash `0x67624a72ab377cbdd7a963398e20308bb56ce8cae568dde56d9ba1d99b8a2940`. The bootstrap selects a free local RPC port and creates disposable accounts. Find the addresses and port in that run's generated configuration instead of assuming Anvil's defaults. ![How the development runtime works diagram](https://docs.fuyu.xyz/diagrams/architecture.svg) ## Install the source toolchain Install Node 24, Python 3, Git LFS and the project's Foundry/Anvil toolchain. The browser package uses ethers `5.8.0`, snarkjs `0.7.6`, TypeScript `5.9.3` and Vite `7.2.2`. Install dependencies from the lockfiles so your build and artifact checks use those versions. Record the source revision before starting a test run. These guides refer to `4def6e17d671d284e755a03d07d99a925b631512`. If you test a newer revision, record that revision with its own results. If the test includes uncommitted changes, also save those source changes so someone else can reproduce the same build. ```bash # Run on the Linux development host in the protocol checkout. node --version # Node 24 git rev-parse HEAD git status --short git lfs pull npm ci --ignore-scripts npm ci --prefix apps/privacy --ignore-scripts # Needed when rebuilding circuits: npm ci --prefix circuits --ignore-scripts ``` ## Start the fork and API Run the fork bootstrap and API in separate Linux terminals. Set `FUYU_QUEUE_RUNTIME_DIR` to the same fresh absolute directory in both. Set `FUYU_ANVIL` to the binary you want to use. `FUYU_MAINNET_RPC_URL` provides read-only access to the historical upstream state; keep any endpoint credentials in the environment. The bootstrap writes `config.json`, deploys the test contracts and checks the fork's external state. The API listens on `127.0.0.1:8796` by default and provides local `/api`, `/rpc` and `/artifacts` routes. Set `FUYU_QUEUE_API_PORT` if you need another API port. Read the bootstrap output and config for the fork's RPC endpoint. ```bash # Terminal 1, from the repository root: export FUYU_QUEUE_RUNTIME_DIR=/absolute/path/to/fresh-runtime export FUYU_ANVIL=/absolute/path/to/anvil # Set FUYU_MAINNET_RPC_URL in the environment if needed. node apps/privacy/runtime/queue-chain-bootstrap.cjs # Terminal 2, from the same checkout: export FUYU_QUEUE_RUNTIME_DIR=/absolute/path/to/fresh-runtime node --experimental-strip-types apps/privacy/runtime/queue-api.cjs ``` ## Start the browser app Start Vite from `apps/privacy`, or use the prefix command below from the repository root. `index.html` is the app's main entry; `verify-audit-answer.html` is the independent audit-answer verifier. Run this protocol app separately from the documentation site's development server. The ordinary build is read-only with the development proof setup. For a disposable integration build, enable writes with `FUYU_QUEUE_E2E_ENABLED=1`. Hosted test writes use a separate public-test flag and check the Sepolia deployment. Keep an E2E fork build connected to its disposable runtime, and leave the public-test deployment checks in place. A remote browser or phone won't reach the Linux host's loopback RPC through WalletConnect pairing. Run your acceptance browser next to the runtime. If you need remote access, configure a reachable test endpoint and check its network and origin settings before using it. ```bash npm --prefix apps/privacy run dev # Build the normal app: npm --prefix apps/privacy run build # An explicitly disposable integration build: FUYU_QUEUE_E2E_ENABLED=1 npm --prefix apps/privacy run build ``` ## Choose the checks for your change Run the checks for the code you changed. Artifact and layout checks compare source and build inputs. Unit tests cover module behavior, Solidity suites execute contracts, and funded browser suites exercise the user flow against a running chain. Say which checks passed when reporting a result so the reader knows what you tested. Use the repository's Foundry configuration: Solidity `0.8.30`, Cancun target, optimizer runs `1` and the standard code generator. The Anvil bootstrap sets its own hardfork and gas limit. To reproduce artifacts, compare both creation and runtime bytecode with the stored source build; compilation alone won't tell you whether the bytes match. ```bash # Linux host only for protocol suites and proof work: npm run check npm --prefix apps/privacy run typecheck npm --prefix apps/privacy test node --test apps/privacy/runtime/*.test.cjs FUYU_REMOTE_EXPERIMENTS=1 npm run test:contracts node contracts/script/reproduce-artifacts.cjs ``` ## Funded browser acceptance The acceptance wrapper starts a suite's fork, API and browser preview, writes the output to its own directory and stops the processes afterward. Configure the Linux browser module and archive RPC before launching it. Build with the flags required by your suite, including profile-deposit support when the harness needs it. For a first integration test, deposit a real fork asset, send a private payment and recover the recipient in a fresh process. Check the contract reserves against the expected amounts. For an external action, check its queued and finalized states, recover its output note and compare the adapter's token effects. Save those results alongside any screenshots of the flow. Use the broader acceptance sweep when your change needs it. Some suites create test-only venues for Morpho, Dolomite, asynchronous tickets, composite actions or Fuyu Earn. Read the public Sepolia route catalog separately to see which routes that deployment supports. A venue created by the fork suite belongs to that test run. ```bash # Configure a fresh Linux output and the installed browser module. export FUYU_ACCEPTANCE_DIR=/absolute/path/to/fresh-acceptance export FUYU_PLAYWRIGHT_MODULE=/absolute/path/to/playwright export FUYU_QUEUE_UI_OUT_DIR=/absolute/path/to/e2e-build # Use the harness-required E2E/profile-deposit build flags. apps/privacy/runtime/run-browser-acceptance.sh \ first-payment test-batch-send-browser-e2e.cjs api # Full sweep, when appropriate for the change: FUYU_REMOTE_EXPERIMENTS=1 \ apps/privacy/runtime/run-acceptance-sweep.sh ``` ## Test recovery without the API For the independent verifier, export an operator trust manifest from the matching runtime to a fresh destination. For service-independent account recovery, export a static deployment bundle. Keep them separate: the verifier reads operator trust, while the recovery app reads the bundle. A holder's recovery file has a different purpose again. To test an outage, stop the API and recover with the exported bundle and a suitable RPC. Check that the browser makes no requests to service API paths and that each downloaded proving file matches its hash. Submit a wallet-paid exit and compare the received amount with the expected result. Record that direct submission publicly links the transaction to the wallet. Keep demo-wallet secrets, passkey material, paper words and private note openings out of public deployment artifacts. Save the public proofs, manifests and transaction receipts with the acceptance results needed to reproduce the test. Check the output before sharing or serving it. ```bash FUYU_REMOTE_EXPERIMENTS=1 \ FUYU_AUDIT_DEPLOYMENT_OUT=/absolute/path/to/fresh-trust.json \ node --experimental-strip-types apps/privacy/runtime/audit-deployment.cjs node apps/privacy/runtime/queue-static-deployment.cjs \ --config /absolute/path/to/fresh-runtime/config.json \ --out /absolute/path/to/fresh-recovery-bundle ``` ## Common development failures If a proving file is missing, check whether Git LFS has downloaded it. If an artifact hash changed, compare the source and build before changing any expected digest. If the fork cannot start, check whether the upstream serves the chosen historical block. If writes are disabled, check whether you are serving the ordinary build or the disposable E2E build. Check ports and runtime directories when a new app appears to show the wrong balance. Compare the instance ID, chain ID, Pool and build manifest so you know which run you're connected to. Keep partial output from an interrupted test and rerun it into a fresh directory. Report the completed run's result separately.