Quickstart

Make your first private deposit and private transfer with Senddy in five minutes.

This gets a private transfer working end to end on Base: install, create a client, deposit, send, and read the balance. Every guide builds on it.

1. Install#

Terminal
npm install @senddy/client @senddy/core viem

2. Get an API key#

Create a key in the Developer Dashboard. Keep it on your server. Browsers should use a short-lived session token instead, which Authentication explains.

3. Create the client#

The client needs a viem PublicClient for reads and the user's WalletClient, which signs deposits and derives the user's private keys.

TypeScript
import { createSenddyClient, SHARED_CONTRACTS, V3_CONTRACTS } from '@senddy/client';

const senddy = createSenddyClient({
  publicClient,
  walletClient,
  chainId: 8453,
  pool: V3_CONTRACTS.Pool,
  usdc: SHARED_CONTRACTS.USDC,
  subgraphUrl: V3_CONTRACTS.Subgraph[0],
  apiUrl: V3_CONTRACTS.ApiEndpoint,
  apiKey: process.env.SENDDY_API_KEY,
});

await senddy.init();

init() derives the user's private keys from a wallet signature, opens local storage and syncs. The keys never leave the device.

For Robinhood Chain, swap in its addresses from Choose a chain.

4. Deposit#

One call moves USDC from the user's wallet into their private balance. It's a single signature: no approval, and no gas.

TypeScript
import { toUSDC } from '@senddy/client';

const deposit = await senddy.deposit(toUSDC('25'));
console.log(deposit.txHash);

5. Send privately#

Every user has a private receive address that starts with senddy1. Send to it:

TypeScript
const recipient = 'senddy1…'; // from the recipient's senddy.getReceiveAddress()

const sent = await senddy.transfer(recipient, toUSDC('10'), { memo: 'Dinner' });
console.log(sent.txHash);

The proof is made on the device, which takes a few seconds in a browser. Onchain, nobody can see the amount, the memo, the sender or the recipient.

6. Read the balance#

TypeScript
const { estimatedUSDC, noteCount } = await senddy.getBalance();
console.log(Number(estimatedUSDC) / 1e6, 'USDC');

senddy.on('balanceChange', (balance) => {
  console.log('Balance is now', balance.estimatedUSDC);
});

The balance includes yield, which accrues on its own. See Earn yield on balances.

Next#