inkswap-sdk
v1.0.12
Published
InkSwap SDK — cross-chain swaps, gasless deposits, presign signing, and per-developer keepers. Zero-dependency, fetch-first, fully typed.
Maintainers
Readme
inkswap-sdk
Zero-dependency TypeScript SDK for the InkSwap platform — cross-chain swaps, gasless deposits, presign signing, and per-developer keepers.
npm i inkswap-sdkQuick start (under 5 minutes)
import { InkSwapClient } from "inkswap-sdk";
// 1. Auth — one line. Your wallet address IS the identity (no API keys).
const client = await InkSwapClient.forWallet(
"https://presigns.useink.xyz",
wallet.publicKey.toBase58(),
);
// 2. Quote — fee tier + expected output come from the live on-chain quote.
const quote = await client.quote({ amount: "1000000", destinationAddress: "0x…" });
// 3. Create the swap.
const intent = await client.createIntent({
amount: quote.amount,
destinationAddress: quote.destinationAddress,
destChainId: 10143, // Monad
});
// 4. Get the server-built deposit tx — gasless (keeper pays the Solana fee).
const dep = await client.depositTx(intent.swapId, true);
// 5. Sign locally with your own wallet, hand the partial tx back.
const partial = await wallet.signTransaction(dep.txBase64);
await client.submitSponsoredDeposit(intent.swapId, partial.signedTxBase64);
// 6. Wait for settlement (typed states, throws on timeout).
const snap = await client.waitFor(intent.swapId, ["settled"]);Authentication
Three ways — in increasing order of ceremony:
| Style | When | Code |
| --- | --- | --- |
| Open (recommended) | Any wallet, testnet/demo | InkSwapClient.forWallet(baseUrl, wallet) — deterministic tw-<wallet> credentials, same wallet → same creds forever |
| Env | Server deployments | INK_SWAP_BASE_URL, INK_SWAP_APP_ID, INK_SWAP_SECRET — then new InkSwapClient({}) |
| Operator | Partners with webhooks | InkSwapClient.registerApp(baseUrl, { operatorKey, … }) |
Common operations
| You want to… | Use |
| --- | --- |
| Check the fee before committing | client.quote({ amount, destinationAddress, destChainId }) |
| Create a swap | client.createIntent({ amount, destinationAddress }) — returns swapId |
| Build the deposit tx | client.depositTx(swapId) or client.depositTx(swapId, true) (gasless) |
| Submit a gasless deposit | client.submitSponsoredDeposit(swapId, partialTx) |
| Poll until done | client.waitFor(swapId, ["settled"], timeoutMs) |
| Provision a keeper (fee account) | client.provisionKeeper({ chains: ["solana", "evm", "sui"] }) |
| Verify a settle on-chain | verifySettledOnChain({ rpcUrl, chainId, pool, swapIdHex, settleTx }) |
| Verify a webhook | verifyWebhookSignature(secret, rawBody, signature) |
| Sign offline, submit later | OfflineTicket.stamp(client, signer, params, store) → ticket.submit(client) |
Errors
Every failure throws a typed error. Catch the class, not the message:
import { InkSwapAuthError, InkSwapRateLimitError, InkSwapNotFoundError } from "inkswap-sdk";
try {
await client.getSwap(swapId);
} catch (e) {
if (e instanceof InkSwapNotFoundError) return res.redirect("/new-swap");
if (e instanceof InkSwapRateLimitError) return res.retryAfter(e.retryAfterMs);
if (e instanceof InkSwapAuthError) return res.redirect("/login");
throw e;
}| Class | HTTP | Meaning |
| --- | --- | --- |
| InkSwapValidationError | 400 / 409 / 422 | Request rejected — the message tells you the fix |
| InkSwapAuthError | 401 / 403 | Bad/absent appId + secret |
| InkSwapRateLimitError | 429 | Slow down — retryAfterMs has the server hint |
| InkSwapNotFoundError | 404 | Wrong swapId / keeperId |
| InkSwapApiError | other | Base class — always thrown by the platform |
The SDK retries transient failures automatically (network blips, 429, 5xx) with exponential backoff + jitter; it never retries a rejected 4xx.
Conventions
- Amounts are raw 6-decimal units (
"1000000"= 1 USDC). UseusdcToRaw("1.5")/rawToUsdc("1500000")to convert. - Addresses: pass a plain
0x…EVM address —pad32()right-aligns it internally. 32-byte pre-padded values pass through. - Everything is typed:
Quote,Intent,DepositTx,SwapSnapshot,Keeper, … — your editor knows the response shape. - Webhooks are HMAC-signed;
verifyWebhookSignatureis constant-time.
Environments
fetch-first: runs in Node 18+, Deno, Bun, Cloudflare Workers, and browsers.
No polyfills, no node-only built-ins in the client path.
Development
npx tsx sdk/liveTest.ts # full suite against the live deploymentSee CHANGELOG.md for version history.
