Skip to main content

SDK Quickstart

@novatip/sdk is the TypeScript package consumed by both the Novatip backend and frontend. It provides typed contract bindings, transaction builders, event parsers, and wallet adapters so you never need to touch raw XDR.


Installation​

npm install @novatip/sdk

For browser apps that use the Freighter wallet extension:

npm install @novatip/sdk @stellar/freighter-api

Requirements: Node.js >= 18


1. Read a Jar (no wallet needed)​

import { TipSplitterClient, getNetwork } from "@novatip/sdk";

const client = new TipSplitterClient({
contractId: "C...", // your deployed contract ID
network: getNetwork("testnet"),
});

const jar = await client.getJar("@alice");
console.log(jar.owner); // G... Stellar address
console.log(jar.splits); // [{ to: "G...", bps: 10000 }]

2. Send a Tip (browser + Freighter)​

import {
TipSplitterClient,
FreighterAdapter,
getNetwork,
usdcToStroops,
} from "@novatip/sdk";

const network = getNetwork("testnet");
const wallet = new FreighterAdapter();
const client = new TipSplitterClient({ contractId: "C...", network });

// Connect wallet
const publicKey = await wallet.getPublicKey();

// Send $2.50 USDC to @alice
await client.tip(
{
from: publicKey,
jarId: "@alice",
amount: usdcToStroops("2.50"), // 25_000_000n stroops
message: "Great stream!",
},
{
signTransaction: (xdr) =>
wallet.signTransaction(xdr, network.passphrase),
},
);

3. Create a Jar with Splits​

import { validateSplitsBps } from "@novatip/sdk";

const splits = [
{ to: "G...alice", bps: 7000 }, // 70%
{ to: "G...bob", bps: 3000 }, // 30%
];

// Validate before sending on-chain
if (!validateSplitsBps(splits.map((s) => s.bps))) {
throw new Error("Splits must sum to 10,000 bps");
}

await client.createJar(
{ owner: publicKey, jarId: "@band", splits },
{
signTransaction: (xdr) =>
wallet.signTransaction(xdr, network.passphrase),
},
);

4. Fetch Tip Events (backend / indexer)​

import { fetchTipEvents, getNetwork } from "@novatip/sdk";

const events = await fetchTipEvents({
contractId: "C...",
network: getNetwork("testnet"),
jarId: "@alice", // omit to fetch all jars
startLedger: 1000000, // resume from a known ledger
limit: 50,
});

for (const event of events) {
console.log(
`${event.from} tipped ${event.amount} stroops to ${event.jarId}:`,
`"${event.message}"`,
);
}

5. Format USDC Amounts​

import { usdcToStroops, stroopsToUsdc, formatUsdc } from "@novatip/sdk";

usdcToStroops("1.50") // 15_000_000n
stroopsToUsdc(15_000_000n) // "1.5000000"
formatUsdc(15_000_000n, 2) // "1.50"

6. Use a Custom Network​

import { networkFromEnv, TipSplitterClient } from "@novatip/sdk";

const network = networkFromEnv({
name: "testnet",
rpcUrl: process.env.SOROBAN_RPC_URL,
horizonUrl: process.env.HORIZON_URL,
passphrase: process.env.NETWORK_PASSPHRASE,
usdcContractId: process.env.USDC_CONTRACT_ID,
});

const client = new TipSplitterClient({
contractId: process.env.TIP_SPLITTER_CONTRACT_ID!,
network,
});

7. Handle Errors​

import {
NovatipContractError,
NovatipSdkError,
ContractErrorCode,
} from "@novatip/sdk";

try {
await client.tip(params, opts);
} catch (err) {
if (err instanceof NovatipContractError) {
switch (err.code) {
case ContractErrorCode.JarNotFound:
console.error("Jar does not exist:", params.jarId);
break;
case ContractErrorCode.InvalidAmount:
console.error("Amount must be greater than zero");
break;
default:
console.error("Contract error:", err.message);
}
} else if (err instanceof NovatipSdkError) {
console.error("SDK error (network/signing):", err.message);
}
}

Network Presets​

NetworkRPC URLPassphrase
testnethttps://soroban-testnet.stellar.orgTest SDF Network ; September 2015
mainnethttps://mainnet.stellar.validationcloud.io/v1/soroban/rpcPublic Global Stellar Network ; September 2015
localhttp://localhost:8000/soroban/rpcStandalone Network ; February 2017

Next Steps​