Typed TypeScript HTTP client for the USDx wallet API.
Zero production dependencies. Runs everywhere. Strict by default.
USDx is the stable settlement currency of the Interchained network — the financial bloodstream that connects creators, node operators, traders, and builders.
On the server,
interchained-usdxguards every balance with atomic Lua scripts running inside Redis. No locks. No races. No double-spends.This package is the client side of that contract — a zero-dependency TypeScript SDK that speaks fluent HTTP to any server built on the Python package. Fully typed. Strict. Runs in every JavaScript runtime that ships native
fetch.Whether you're building a Next.js dashboard, a React Native wallet, or a serverless Cloudflare Worker — this is how you talk to USDx.
# npm
npm install @interchained/usdx
# pnpm
pnpm add @interchained/usdx
# yarn
yarn add @interchained/usdx
# bun
bun add @interchained/usdx┌──────────────────────────────────────────────────────────────┐
│ Your TypeScript / Next.js / React Native / Cloudflare app │
│ │
│ import { USDxClient } from "@interchained/usdx" │
│ │
│ ✓ zero production deps ✓ native fetch │
│ ✓ strict TypeScript ✓ Node • Browser • Deno • Bun │
└──────────────────────┬───────────────────────────────────────┘
│ HTTP / REST
│ (JSON, standard HTTP status codes)
┌──────────────────────▼───────────────────────────────────────┐
│ FastAPI wallet server (interchained-usdx Python package) │
│ │
│ from usdx import USDxWallet, NowPaymentsService, … │
│ │
│ ✓ Lua atomic scripts ✓ NowPayments IPN handler │
│ ✓ PSBT payout builder ✓ OTC rate engine │
└──────────────────────┬───────────────────────────────────────┘
│
┌───────▼────────┐
│ Redis 6+ │
│ (the source │
│ of truth) │
└────────────────┘
import { USDxClient } from "@interchained/usdx";
const client = new USDxClient({
baseUrl: "https://api.yourapp.com",
apiKey: "your-api-key", // optional — sent as X-Api-Key
timeoutMs: 10_000,
});
// ── Balance ───────────────────────────────────────────────────
const { balance } = await client.getBalance("alice");
console.log(balance); // 20.74
const info = await client.getInfo("alice");
console.log(info.is_frozen); // false
console.log(info.total_credited); // 50.00
const history = await client.getHistory("alice", { limit: 10 });
// → Transaction[]
// ── Credit / Debit ────────────────────────────────────────────
const tx = await client.credit({
userId: "alice",
amount: 10.00,
description: "Article view earnings",
txType: "view_reward",
multiplier: 1.5, // 1.5× for premium — applied atomically server-side
});
console.log(tx.amount); // 15.0
console.log(tx.balance_after); // 35.74
// Both InsufficientBalance and AccountFrozen are first-class error types
try {
await client.debit({ userId: "alice", amount: 3.99, description: "Subscription" });
} catch (e) {
if (e instanceof InsufficientBalance) console.log("Not enough funds");
if (e instanceof AccountFrozen) console.log("Account is locked");
}
// ── Transfer ──────────────────────────────────────────────────
const { debit, credit } = await client.transfer({
fromUser: "alice",
toUser: "bob",
amount: 5.00,
description: "Tip",
});
console.log(debit.balance_after, credit.balance_after);
// ── Freeze / Unfreeze (fraud protection) ─────────────────────
await client.freeze("alice");
await client.unfreeze("alice");
// ── NowPayments crypto deposits ───────────────────────────────
const invoice = await client.createDeposit({
userId: "alice",
amount: 25.00,
currency: "usdttrc20", // any of 22 supported coins
});
console.log(invoice.payment_url); // Redirect user here ↗
const status = await client.checkPayment("payment_id_here");
console.log(status.status); // "waiting" | "confirming" | "finished" | "failed"
const result = await client.claimPayment("payment_id_here");
// result.already_processed === true if already claimed (idempotent)
// ── OTC rate engine ───────────────────────────────────────────
const rate = await client.getOtcRate(); // ITC per 1 USDx (e.g. 10.5)
const stats = await client.getOtcStats(); // { itc_reserve, usdx_supply, current_rate, … }new USDxClient({
baseUrl: string, // required — your wallet server URL
apiKey?: string, // sent as X-Api-Key header
headers?: Record<string, string>, // merged into every request
timeoutMs?: number, // default: 30_000 ms
fetch?: typeof fetch, // swap in a polyfill or test mock
})| Method | Signature | Returns |
|---|---|---|
getBalance |
(userId: string) |
Promise<{ user_id: string; balance: number }> |
getInfo |
(userId: string) |
Promise<BalanceInfo> |
getHistory |
(userId: string, opts?: { limit?, offset? }) |
Promise<Transaction[]> |
credit |
(opts: CreditOptions) |
Promise<Transaction> |
debit |
(opts: DebitOptions) |
Promise<Transaction> |
transfer |
(opts: TransferOptions) |
Promise<TransferResult> |
freeze |
(userId: string) |
Promise<void> |
unfreeze |
(userId: string) |
Promise<void> |
| Method | Signature | Returns |
|---|---|---|
createDeposit |
(opts: DepositOptions) |
Promise<DepositInvoice> |
checkPayment |
(paymentId: string) |
Promise<PaymentStatus> |
claimPayment |
(paymentId: string) |
Promise<ClaimResult> |
| Method | Signature | Returns |
|---|---|---|
getOtcRate |
() |
Promise<number> |
getOtcStats |
() |
Promise<OtcStats> |
All types are exported from the package root. Import only what you need.
import type {
// Core wallet
Transaction,
BalanceInfo,
TransferResult,
// Deposits
DepositInvoice,
PaymentStatus,
ClaimResult,
// OTC
OtcStats,
// Request option shapes
CreditOptions,
DebitOptions,
TransferOptions,
DepositOptions,
} from "@interchained/usdx";interface Transaction {
id: string;
user_id: string;
direction: "credit" | "debit";
tx_type: string;
amount: number;
balance_after: number;
description: string;
metadata: Record<string, unknown> | null;
created_at: string; // ISO 8601
}
interface BalanceInfo {
user_id: string;
balance: number;
total_credited: number;
total_debited: number;
is_frozen: boolean;
created_at: string | null;
last_updated: string | null;
}All SDK errors extend USDxError. Each is a concrete class you can instanceof against.
import { USDxError, InsufficientBalance, AccountFrozen, HttpError } from "@interchained/usdx";
try {
await client.debit({ userId: "alice", amount: 999_999, description: "YOLO" });
} catch (e) {
if (e instanceof InsufficientBalance) {
// HTTP 422 — balance too low
console.log("Not enough funds:", e.message);
}
else if (e instanceof AccountFrozen) {
// HTTP 403 — account is locked by fraud protection
console.log("Account locked:", e.message);
}
else if (e instanceof HttpError) {
// Any other non-2xx response
console.log(`HTTP ${e.statusCode}:`, e.message);
}
else if (e instanceof USDxError) {
// Network timeout, DNS failure, etc.
console.log("SDK error:", e.message);
}
}The client accepts a custom fetch function — useful for testing, polyfilling, or logging every request.
// ── Test mocking ──────────────────────────────────────────────
const client = new USDxClient({
baseUrl: "http://localhost:8000",
fetch: async (url, init) => {
// intercept, inspect, or stub any request
return mockFetch(url, init);
},
});
// ── Node.js < 18 polyfill ────────────────────────────────────
import nodeFetch from "node-fetch";
const client = new USDxClient({ baseUrl: "...", fetch: nodeFetch as typeof fetch });
// ── Request logging middleware ────────────────────────────────
const client = new USDxClient({
baseUrl: "...",
fetch: async (url, init) => {
console.log("→", init?.method, url);
const res = await fetch(url, init);
console.log("←", res.status);
return res;
},
});See examples/ for runnable code:
| Example | Description |
|---|---|
quickstart.ts |
End-to-end Node.js script covering every USDxClient method |
express-wallet-app/ |
Express skeleton that uses USDxClient as a proxy layer — add your auth, validation, and business logic on top |
npm install
npm run build # compiles to dist/ (ESM .js + .d.ts)
npm run check # tsc --noEmit (strict, zero warnings)This SDK is the client half of the USDx stack. The server half is built with the Python package:
pip install interchained-usdxSee interchained-usdx on PyPI and the
usdx-py repo for the full wallet engine, NowPayments IPN handler, PSBT builder, and OTC rate engine.
- Fork → branch → make your changes
npm run check— zero TypeScript errorsnpm run build— clean build with no new.jsartifacts committed- Open a PR with a clear description of what changed and why
Please report security issues via private message, not public issues.
GNU General Public License v3.0 or later. See LICENSE for the full text.
@interchained/usdx Copyright (C) 2024 Interchained
This program comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under the terms of the GPLv3.