Skip to main content

Deposit

A deposit moves public funds into the pool and creates a note, the private value you spend from then on. It is also where the protocol's compliance screening happens: the ASP reviews every deposit before the resulting note becomes spendable, so everything circulating inside the pool has passed that review.

How a deposit becomes spendable

The deposit moves through a few stages before the note is spendable:

  1. Funds enter the pool. You send ETH or an ERC20 token to the Entrypoint, which forwards it to the PoolVault. The vault inserts the new note's commitment into its state tree and emits two events: Deposited (the public deposit details) and Note (the encrypted note payload). Your note now exists in PENDING state, and because the deposit transaction is public, your wallet is still visibly linked to it.
  2. The ASP opening is registered. In the same transaction, the Entrypoint registers the deposit's encrypted ASP opening (aspCiphertext) with the ASPRegistry, which emits a LabelRegistered event carrying that ciphertext.
  3. The ASP screens the deposit. The ASP service consumes the LabelRegistered event, decrypts the opening with its own key, then recomputes and screens the deposit's label, the identifying value that every note descended from it will carry.
  4. Attestation makes the note spendable. When the deposit is approved, the ASP includes the label in its association-set Merkle root, and an account holding the POSTMAN_ROLE publishes that root to the ASPRegistry contract. That published approval is the deposit's attestation. Spending proofs are checked against the latest published root, so your note turns ACTIVE only once its label is in it. Approval is often complete within an hour, though it can take up to 7 days. You can check a specific deposit's status while you wait.

A deposit the ASP refuses moves to REJECTED instead, and the note's owner can still recover the funds through ragequit, a public exit that works without the ASP's cooperation.

Register before you spend

The deposit path never touches the keystore, so a wallet that has not registered can still deposit successfully. Spending and ragequit both prove keystore membership, though, which means a note owned by an unregistered wallet can be created but neither spent nor recovered until the owner registers. For that reason, register before you spend rather than before you deposit. Depositing first is fine, but the note stays unspendable until registration, so frontends typically handle registration as part of account setup.

How to deposit

const NATIVE_ETH = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";

const receipt = await session.deposit({
tokenId: NATIVE_ETH,
value: "0x2386f26fc10000", // 0.01 ETH in wei
});

await session.discoverNotes();

Native ETH uses the placeholder asset address 0xeeee…eeee. The SDK's AddressSchema validates the hex format only, and the deposit path compares the asset case-insensitively, so either casing is accepted.

deposit() returns a transaction receipt, not note material. For an owned deposit, the SDK persists the note locally, where it appears in exportAccount().notes as PENDING right away. After ASP attestation, discoverNotes() promotes it to ACTIVE. Use prepareDeposit(...) first if you need the pending note before submitting.

Constraints

  • Min amount, vetting fee, and max relay fee are set per asset on the Entrypoint. Read them live with Entrypoint.assets(asset), which returns AssetConfig{ enabled, minAmount, vettingFeeBPS, maxRelayFee }, rather than assuming fixed values. There is no max deposit amount.
  • Pre-attestation visibility: until the ASP attests the deposit label, the note exists on-chain in PENDING state and the depositor's wallet is linked to it. Privacy is realized only after attestation and a subsequent spend.

Check a deposit's attestation status

Each note carries its deposit's label, and the ASP answers status queries per label:

const labelHash = hashService.hash([note.label]);
const decimalLabelHash = BigInt(labelHash).toString();
const attestation = await fetch(
`${aspUrl}/labels/${decimalLabelHash}/status`,
).then(r => r.json());

switch (attestation.status) {
case "approved":
console.log("Note is spendable. ACTIVE.");
break;
case "pending":
console.log("ASP still reviewing. Wait or check back later.");
break;
case "rejected":
console.log("ASP refused this deposit. Use ragequit to recover.");
break;
case "unknown":
console.log("ASP has no record of this label. Keep waiting or re-check.");
break;
}

A rejection is a different state from a pending review: if the ASP explicitly rejects a label (a sanctions hit or compliance flag), the note moves to REJECTED rather than back to PENDING, and ragequit is its recovery path.

Most apps don't call this directly. discoverNotes() integrates the attestation check into its sync, so your local NoteManager status updates from PENDING to ACTIVE automatically when the ASP catches up. Use this query when you need to check one specific deposit. The ASP indexes the Poseidon hash of the label, encoded as a decimal integer (GET {aspUrl}/labels/{decimalLabelHash}/status).

Behind the scenes

SDK call session.deposit({tokenId, value}) (same signature for ETH and ERC20)
Contract method Entrypoint.deposit(...), which calls PoolVault.deposit(...) and then registers the encrypted ASP opening via aspRegistry().registerLabel(aspCiphertext)
ERC20 prerequisite An Entrypoint allowance covering the deposit value plus the vetting fee. session.deposit() submits the approve automatically when the current allowance is too low.
Circuit deposit Groth16
On-chain events PoolVault emits Deposited(outputCommitment, asset, depositedValue, caller) plus a Note(hint, data) carrying the encrypted payload (the Note event itself does not include the commitment). Entrypoint additionally emits its own Deposited(asset, depositor, value, fee) capturing the depositor and vetting fee, and ASPRegistry emits LabelRegistered(ciphertext) carrying the encrypted opening the ASP decrypts to screen the label.

Variants

  • Yield deposit: shield the value as ppUSDC shares that earn Aave interest.
  • Swap and deposit: enter from any wallet token, with the swap and the deposit in one transaction.

What's next

  • Manage notes: discovery promotes the attested note into your spendable set.
  • Transfer: spend the note privately inside the pool.
  • Withdraw: exit the value to a public address.
  • Ragequit: the recovery path if the ASP rejects the deposit.