All notable changes to @zkcoins/sdk are documented here. The format
follows Keep a Changelog and the
project adheres to Semantic Versioning.
ZkCoinsClient.getTransaction(id, address)—GET /api/history/{id}→TxDetail. The full per-transaction detail behind the wallet's transaction-detail page: everyTxItemcore field plus the decoded account-state snapshot of the mutation (balance_after/balance_before/num_sends_after/commitment_public_key), the verifiercircuit_digest, and the on-chaincommit_output_value. Scoped byaddress(a wrong-address or internal row 404s asApiError).TxDetailSchema/TxDetail— the wire schema,extendingTxItemSchemaso the shared list/detail core cannot drift. Mirrors the node'srouter::TxDetailserde.
Purely additive — no breaking changes to the 0.3.x surface.
JobResultSchema.successis now optional. The node'sawaiting_signaturesend-job result (node #195) carries onlyaccount_state_hash/output_coins_rootand omitssuccess(seejob_dispatcher.rs::set_awaiting_signature). Parsingsuccessas required threw aZodErroron every realawaiting_signaturepoll, which stalledZkCoinsAccount.pay()in the proving/awaiting phase and blocked the send lifecycle end-to-end. Verified against a live local node (Mutinynet) with #195 —pay()now completes the two-phase send.
Endpoint-coverage completion. The SDK now mirrors every node endpoint a wallet legitimately reads or drives, hardens error handling across the new surface, and documents the receive pattern and the (deliberate) absence of a fee API. Purely additive — no breaking changes to the 0.2.0 surface.
- Service + health client methods on
ZkCoinsClient:root()—GET /→RootResponse(service id + advertised endpoint map + docs pointer).health()—GET /health→ the plain-text"ok"liveness body.ready()—GET /health/ready→ReadyResponse. Returns the body for both the 200 (ready) and 503 (not-ready) branches — a not-ready node is a valid readiness answer, not a transport error; any other non-2xx still throwsApiError.publisherHealth()—GET /health/publisher→PublisherHealthResponse({address, utxo_count, total_sats}), the only fee-relevant figure the node exposes.
- Read client methods:
addresses()(GET /api/address, feature- gated) andinscription(txid)(GET /api/inscriptions/:txid). ZkCoinsAccount.waitForIncoming(opts?)— an optional balance- polling helper for the receive pattern: reads a baseline (or an explicitfromBalance), then resolves with the updatedBalanceResponseon the first observed increase. Throws on timeout (never returns a stale balance). PuregetBalance()on a timer — no signing, no extra trust assumption.- New schemas / types:
RootResponse(Schema),RootEndpoints(Schema),ReadyResponse(Schema),PublisherHealthResponse(Schema),AddressesResponse(Schema),InscriptionSummary(Schema),InscriptionKind(Schema), andWaitForIncomingOpts.
- README gains a full
ZkCoinsClientendpoint-reference table, a Receiving section (share address → poll balance/history), and a Fees section stating plainly that there is no client fee API and the SDK fabricates none. - Documented the deliberately-omitted endpoints and why:
GET /api/proof/:id(binary bincode, not decodable in pure TS and not needed — the wallet readsash/ocrfrom the job result),POST /api/receive(legacy plumbing), andGET /api/admin/r2-probe/history(operator telemetry, out of scope).
Migration to the asynchronous Jobs API. The node removed the
synchronous /api/{mint,send,commit} routes; this release replaces the
SDK's synchronous methods with the job lifecycle.
- Sync → Jobs API.
ZkCoinsClient.mint/.send/.commit(the synchronous/api/{mint,send,commit}calls) are removed. Use the new job methods (mintJob,sendJob,getJob,commitJob,cancelJob,streamJob) or the high-levelZkCoinsAccount.mint/.pay, which drive the lifecycle and poll for you. Capabilitiesfields changed. Now{ address_list, username_claim, lnurl, multi_asset }(was{ address_list, faucet, usernames, lnurl }) — matching the node'srouter::Capabilities. Code readingcapabilities.faucet/.usernamesmust move to.username_claim/.multi_asset.getTransactions/historyno longer throw. TheNotImplementedErrorplaceholder (and theHISTORY_TRACKING_URLconstant) are removed —/api/historyis live, so the methods perform a real request.- Removed schemas.
SendResponseSchema,MintResponseSchema,CommitResponseSchema(and their type aliases) are gone — they only described the removed synchronous endpoints. UseJobAcceptedSchema,JobStatusSchema, andJobResultSchemainstead. PayResultshape changed to{ jobId, proofId };MintResult({ jobId, proofId }) is new.TxItemnullables.txid,counterparty,block_height,memoare now.nullable()(the node emits explicitnull), and a new requiredid: numberfield was added — matchingrouter::HistoryItem.
- Jobs-API client methods on
ZkCoinsClient:mintJob,sendJob,getJob/getJobWithRetry(surfaces theRetry-Afterbackoff),commitJob,cancelJob, andstreamJob(SSEAsyncGenerator). - High-level account flows
ZkCoinsAccount.mint(amountSats, assetId?)andpay(recipient, amountSats, assetId?), pluswaitForJob(jobId, stopAt, opts?)(polls to a terminal/target status, respectsRetry-After, throws onfailed/cancelled). getTransactions(opts?)/ZkCoinsClient.history(address, opts?)— liveGET /api/historywith{ limit, offset }pagination.bitcoin_networkonInfoResponse— typed'mainnet' | 'mutinynet'network switch (optional, fail-open for nodes that predate it), with aBitcoinNetworkSchemaexport.num_sendsonBalanceResponse— the authoritative BIP-32 child-index counter; seedsetNumPubkeys(balance.num_sends)to re-hydrate local state.asset_id(multi-asset) — optional 32-byte-hex selector onmint/payand on theMintRequest/SendRequest/SignedSendRequestshapes; a malformed value hard-fails server-side (no fallback to native). Gated bycapabilities.multi_asset.newIdempotencyKey()— RFC-4122 v4 UUID from@noble/hashesrandomBytes(notcrypto.randomUUID, for React Native parity); reuse one per logical operation across retries.JobFailedError— thrown when a job endsfailed/cancelled, distinct fromApiError(the HTTP call succeeded; the job failed).- New schemas/types:
JobAccepted(Schema),JobStatus(Schema),JobStatusValue(Schema),JobKind(Schema),JobResult(Schema),JobErrorResponse(Schema),BitcoinNetwork(Schema).
ApiErrornow also extracts the Jobs-API{ error }envelope (in addition to the legacy{ success: false, error }shape).NotImplementedErrorremoved (no longer needed).
- Toolchain modernization (eslint 10 flat config, TypeScript 6, noble/scure 2.x, zod 4). No public API change.
- Initial implementation: BIP-39/32 derivation, BIP-340 Schnorr signing, typed REST client, high-level account adapter.