Recurve Docs
Website GitHub Open app

Getting started

Quickstart

Install the SDK, point it at a vault, and read its state. Then deposit.

Install

npm install @recurve/sdk viem

viem is a peer dependency. The SDK reuses the client you already have rather than opening its own transport.

Connect

import {createPublicClient, createWalletClient, http} from "viem";
import {privateKeyToAccount} from "viem/accounts";
import {Recurve} from "@recurve/sdk";

const publicClient = createPublicClient({transport: http(RPC_URL)});

const recurve = new Recurve({
  publicClient,
  addresses: {
    vault:    "0x...",
    governor: "0x...",
    registry: "0x...",
  },
});

Leaving out walletClient gives you a read-only instance. Write calls throw immediately instead of failing partway through, which is what you want in an indexer.

Read a vault

const snap = await recurve.vault.snapshot();

snap.totalAssets     // everything the vault owes depositors
snap.float           // what can leave right now
snap.deployedAssets  // committed to a live strategy
snap.sharePrice      // assets per 1e18 shares

float and deployedAssets sum to totalAssets. A position mid-unwind still belongs to depositors, so it stays counted.

Deposit

const walletClient = createWalletClient({
  account: privateKeyToAccount(PRIVATE_KEY),
  transport: http(RPC_URL),
});

const recurve = new Recurve({publicClient, walletClient, addresses});

await recurve.depositor.deposit(1_000_000n);
Why it self-delegates

ERC20Votes weight is zero until delegated. A depositor who skips that step holds shares that cannot veto anything, and only finds out during a live proposal. The SDK delegates for you; pass {skipDelegate: true} if you delegate elsewhere.

Exit

const {instant, requestId} = await recurve.depositor.redeem(500_000n);

if (!instant) {
  await recurve.depositor.claim(requestId);
}

Branch on instant rather than assuming. The float can move between reading it and the transaction landing.