A complete TypeScript loop against a live Stellar testnet DeFindex vault:
deployTreasuryVault({ caller, manager })→ sign the unsigned XDR with your key →submitTreasuryTxdepositToTreasuryVault({ vault, from, amounts })→ sign →submitTreasuryTxgetTreasuryVault(vault, holder)→ print the idle / invested split
Nirium's SDK never holds a signing key in this path. The Agent only builds and broadcasts XDR.
- Nirium builds unsigned XDR.
deployTreasuryVaultanddepositToTreasuryVaultreturnxdr+signWith. Nothing is submitted until you sign. Agentnever touches a private key on this path. This example constructsnew Agent({ apiKey, baseUrl })— it receives noS...secret. Signing is done locally with@stellar/stellar-sdk(Keypair.fromSecretinsrc/sign.ts).- Every signature comes from the caller's own keypair.
manageris set to your testnet address (the role that can rescue funds, pause strategies, and revoke rebalance). Nirium, if present at all, only holdsRebalanceManager, which cannot withdraw. A browser port would sign with Freighter the same way: the wallet holds the key, the SDK does not.
This issue is deploy + deposit only. It does not call executeTreasuryRebalance or the RebalanceManager endpoints.
- Node.js 20+
- A funded Stellar testnet account you control:
- XLM for fees / contract deploy — Friendbot (
https://friendbot.stellar.org?addr=G...) - A small balance of the vault asset. Default is Blend testnet USDC (
USDC-GATALTG…, contractCAQCFV…) — not Circle USDC. The script opens that trustline if it is missing; then click Faucet on testnet.blend.capital. SetVAULT_ASSET=cetesif you hold testnet CETES instead.
- XLM for fees / contract deploy — Friendbot (
You do not need a Nirium institutional API key. The script requests a public demo token with your G-address.
cd examples/treasury-vault-quickstart
cp .env.example .env
# put your own testnet S... key in .env — never a Nirium key, never mainnet
npm install
npm startThe script prints two stellar.expert/explorer/testnet/tx/<hash> links (deploy + deposit) and the vault's idle / invested amounts.
| Variable | Required | Default |
|---|---|---|
STELLAR_SECRET_KEY |
yes | — (your testnet S... only) |
NIRIUM_API_KEY |
no | public demo-auth token |
NIRIUM_BASE_URL |
no | https://nirium-agent.fly.dev |
VAULT_ASSET |
no | usdc (cetes also supported) |
DEPOSIT_AMOUNT_STROOPS |
no | 10000000 (1.0 with 7 decimals) |
INVEST |
no | false (deposit stays idle so the split is obvious) |
VAULT_ID |
no | Reuse an already-deployed vault and skip deploy |
NETWORK_PASSPHRASE |
no | Test SDF Network ; September 2015 |
Mainnet is out of scope. Setting the public network passphrase is rejected before any signature is produced.
The two that show up in this repo's own history:
- Insufficient balance — missing testnet account, not enough XLM to deploy, or not enough of the vault asset to deposit. The script preflights XLM on Horizon and rewrites agent/Horizon errors into a Friendbot + asset hint.
- Wrong network passphrase — signing a testnet XDR with the public passphrase (or pointing
NETWORK_PASSPHRASEat mainnet).src/sign.tsrefuses to sign unless the passphrase is exactly testnet.
npm test
npm run typechecksrc/index.ts end-to-end loop (deploy → sign → submit → deposit → sign → submit → read)
src/sign.ts local keypair signing; testnet passphrase guard
src/auth.ts demo-auth + optional Bearer header
src/errors.ts insufficient-balance / passphrase error mapping
src/usdc.ts BlendUSDC trustline + balance preflight (not Circle USDC)
SDK methods used: Agent.deployTreasuryVault, Agent.depositToTreasuryVault, Agent.submitTreasuryTx, Agent.getTreasuryVault, Agent.getTreasuryInfo (nirium@0.12.0).