Deposit
Depositing tokens moves them from the public EVM world into the shielded pool.
Direct deposit
The standard deposit requires the user to have AVAX for gas.
import { deposit, waitForDeposit } from '@shroud/sdk';
const { tx, pendingNote } = await deposit({
signer,
provider,
poolAddress: "0x91c912eac...",
tokenAddress: "0xE4e328Fc6...",
amount: 100n, // 100 tokens (whole units)
ownerPublicKey: keypair.publicKey,
});
const note = await waitForDeposit(tx, pendingNote, provider, poolAddress);
Flow
- SDK generates random:
secret,nullifier_preimage,blinding - Computes Pedersen commitment:
C = amount * G + blinding * H - Computes note commitment:
Poseidon(C.x, C.y, secret, nullifier_preimage, pk.x) - Approves ERC20 transfer to the pool contract
- Calls
pool.deposit(amount, noteCommitment) - Contract transfers tokens via
transferFrom - Contract inserts commitment into Merkle tree
- SDK stores full note data locally
Gasless deposit (relay)
No AVAX required (after one-time token approval).
import { relayDeposit, waitForRelayDeposit } from '@shroud/sdk';
const fee = amount / 1000n; // 0.1% fee
const { relay, pendingNote } = await relayDeposit({
signer,
provider,
poolAddress: "0x91c912eac...",
tokenAddress: "0xE4e328Fc6...",
amount: 100n,
ownerPublicKey: keypair.publicKey,
fee,
metaTxRelayerAddress: "0xF994781eC...",
});
const note = await waitForRelayDeposit(relay, pendingNote, provider, poolAddress);
Gasless flow
- SDK checks token allowance for MetaTxRelayer, approves if needed (one-time gas cost)
- SDK reads nonce from MetaTxRelayer contract
- User signs EIP-712 typed data (wallet popup — no gas)
- SDK POSTs signature + data to relay API
- Relay wallet submits transaction and pays gas
- Fee deducted from user's token balance
warning
Deposit amounts are visible on-chain because the ERC20 transferFrom is a public transaction. Privacy begins after the deposit is complete.