@note-systems/sdk
One call in. Six things happen before it reaches the chain.
A typed TypeScript client over viem. Reads batch through Multicall3, writes simulate before they sign, gas is estimated with the vault's fee accrual forced to run, and every result is read from the contract's own events. Every revert comes back with its name.
Quick start
From install to a tagged deposit
- ClientsA viem public client for reads and a wallet client for writes. The SDK never holds a key.
- DiscoverThe first listed vault, then
verifyBinding before anything is trusted.
- Quote
summary for the mandate and previewDeposit for the share count, both before signing.
- DepositApprove, then deposit with your partner id. The id follows the shares;
tagged tells you it stuck.
- HandleCatch
NoteError and branch on decoded.name.
import { createPublicClient, createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { NoteError, createNoteClient, partnerId, robinhoodTestnet } from '@note-systems/sdk';
// 1. clients
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const publicClient = createPublicClient({ chain: robinhoodTestnet, transport: http() });
const walletClient = createWalletClient({ chain: robinhoodTestnet, transport: http(), account });
const note = createNoteClient({ publicClient, walletClient });
// 2. discover and verify
const [vault] = await note.factory.list(0n, 20n);
if (!vault || !(await note.vaults.verifyBinding(vault))) throw new Error('no bound vault');
// 3. quote
const summary = await note.vaults.summary(vault);
const assets = 100_000_000n; // 100 USDG, six decimals
const quoted = await note.vaults.previewDeposit(vault, assets);
// 4. deposit with attribution
try {
await note.vaults.approve(vault, assets);
const tx = await note.vaults.deposit({ vault, assets, receiver: account.address, partnerId: partnerId('wallet.example') });
console.log(summary.name, quoted, tx.result.shares, tx.result.tagged, tx.gasUsed);
} catch (e) {
// 5. handle by name
if (e instanceof NoteError && e.decoded?.name === 'Locked') { /* show the unlock time */ }
else throw e;
}