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 isSUCCESS(or throw). Signeris just{ address, sign(xdr) }. AkeypairSignerships for scripts/bots; browser wallets (Freighter, xBull via@creit.tech/stellar-wallets-kit) satisfy the same shape.- Fail-closed reads surface as
ContractErrorwith.codeparsed fromError(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