Skip to main content

TypeScript SDK

@leontief/sdk is one hand-written client over @stellar/stellar-sdk. Reads simulate (no keys); writes run the full build → simulate → assemble → sign → send → poll cycle and never resolve until the transaction reaches SUCCESS.

import { LeontiefClient, keypairSigner } from "@leontief/sdk";

const client = new LeontiefClient({
rpcUrl: "https://soroban-testnet.stellar.org",
networkPassphrase: "Test SDF Network ; September 2015",
contracts: { vault, miniPool, oracleAdapter },
assetId: "LEOD",
});

// Reads need no keys (simulateTransaction under the hood):
await client.sharePrice(); // 1_002_100_000_000n (SCALE = 10^12)
await client.quoteShares(100_000_000n); // ≈ ld-shares for 10 LEOD

// Writes take any Signer (raw key here; a browser wallet in the dApp):
const me = keypairSigner(secret, client.config.networkPassphrase);
const { hash, returnValue } = await client.wrap(me, 100_000_000n);

Design

  • One client, two paths. Reads use simulateTransaction, so they need no account or keys. Writes never resolve until the tx is SUCCESS (or throw).
  • Signer is just { address, sign(xdr) }. A keypairSigner ships for scripts/bots; browser wallets (Freighter, xBull via @creit.tech/stellar-wallets-kit) satisfy the same shape.
  • Fail-closed reads surface as ContractError with .code parsed from Error(Contract, #N) — a stale/deviating oracle throws instead of returning a stale price.
  • Pure previews (quoteShares, quoteWithdraw, healthFactor, quoteSeize) mirror the contracts' integer math and are unit-tested against the repo's golden vectors — client math can't drift from chain math.

Surface

Reads (no keys)Writes (Signer)
sharePrice()wrap(signer, amount)
totalAssetsValue()unwrap(signer, shares)
nav()supplyCollateral(signer, shares)
ldBalance(account)withdrawCollateral(signer, shares)
positions(account)borrow(signer, amount)
healthFactor(account)repay(signer, amount)
isWhitelisted(account)liquidate(signer, user, repay)
quoteShares(amount)
previewHealthFactor(...)

Bindings

Raw generated bindings live in packages/bindings/*, regenerated from the live contracts by scripts/gen_bindings.sh after every deploy (and gitignored). Prefer the SDK; drop to the bindings only for a method it doesn't surface.

source deploy.env
pnpm exec tsx packages/sdk/examples/deposit.ts # wrap 10 LEOD
pnpm exec tsx packages/sdk/examples/borrow.ts # supply + borrow USDC
TARGET=G... pnpm exec tsx packages/sdk/examples/liquidate.ts