Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
S

sphere-sdk

> DevOps
Open source

The SDK for autonomous economic agents. Give an agent an identity, a wallet, and the ability to find, negotiate with, and settle with other agents - peer-to-pee

5.4K stars0 likes0 views
WebsiteGitHub

About

The SDK for autonomous economic agents. Give an agent an identity, a wallet, and the ability to find, negotiate with, and settle with other agents - peer-to-pee

Sphere SDK

A modular TypeScript SDK for Unicity wallet operations (Unicity state transition network).

Features

  • Wallet Management - BIP39/BIP32 key derivation; optional password encryption (PBKDF2)
  • Payments - Engine-certified token transfers over the wallet-api vertical (durable server-side intents, mailbox delivery, crash-safe resume under the same transferId); server custody — the backend holds inventory, keys stay local
  • Payment Requests - Request payments over the wallet-api rail with encrypted memos and durable settling
  • Market (Intents) - Signed intent bulletin board with semantic search and live feed
  • Group Chat - NIP-29 relay-based group messaging with moderation
  • Messaging (Nostr) - NIP-17 DMs + NIP-29 group chat and nametag publishing — messaging only; not the payment rail
  • Multi-Address - HD address derivation (BIP32/BIP44)
  • Connect Protocol - dApp ↔ wallet communication via ConnectClient / ConnectHost (browser extension + popup)
  • CLI - Comprehensive command-line interface with shell auto-completion

Installation

npm install @unicitylabs/sphere-sdk

Quick Start Guides

Choose your platform:

Platform Guide Required Optional
Browser QUICKSTART-BROWSER.md SDK only IndexedDB storage
Node.js QUICKSTART-NODEJS.md SDK + ws File storage
CLI @unicity-sphere/cli Separate package -
dApp integration CONNECT.md SDK only Sphere extension

CLI (Command Line Interface)

The CLI has moved to a dedicated package: @unicity-sphere/cli.

npm install -g @unicity-sphere/cli
sphere --help

See docs/QUICKSTART-CLI.md for the full command reference.

Quick Start

Setup is two provider layers, not one. createBrowserProviders / createNodeProviders build only the base (storage + transport + oracle). You must then attach the wallet-api transport config with createWalletApiProviders — money moves only through the wallet-api vertical. Skipping it fails loudly: Sphere.init throws INVALID_CONFIG.

…

What just happened (the provider model)

A wallet is composed from swappable ports, layered in two steps:

Layer Built by What it supplies
Base createBrowserProviders / createNodeProviders storage (keys/identity/journals), transport (Nostr — messaging/nametags only), oracle (gateway/trust base)
wallet-api transport createWalletApiProviders(base, …) walletApi — the transport CONFIG ({ network, baseUrl, deviceId?, fetchFn?, webSocketFactory?, paymentsV2Transport? }) the payments vertical is composed from
  • The rail is wallet-api, not Nostr. Transfers are certified on-chain by the token engine and the finished token is deposited into the recipient's wallet-api mailbox. Nostr carries messaging/nametags — it does not move payments.
  • Custody is server-side. The wallet-api backend holds your token inventory; your keys never leave the client. (Own-storage custody was rescinded — there is no local token store.)
  • The money ports are contract-enforced. StoragePort/DeliveryPort (modules/payments-v2/ports.ts) have wallet-api implementations; the paymentsV2Transport seam in the walletApi config lets tests/custom hosts inject a whole replacement bundle.
  • network placement. Required on createBrowserProviders/createNodeProviders, in the walletApi config, AND on Sphere.init — the three must agree. Sphere.init resolves the payments composition and the token registry from its own network, so omitting it or letting it disagree with walletApi.network throws INVALID_CONFIG before any storage write.

For manual/advanced provider wiring, see Custom Providers Configuration. For the deeper integration guide, see docs/INTEGRATION.md.

Send result (TransferResult)

send() resolves with a TransferResult:

Field Meaning
status 'completed' on success. ('pending' | 'submitted' | 'confirmed' | 'delivered' | 'failed' also exist for in-flight/terminal states.)
deliveryPending true when the spend is certified on-chain but the recipient's mailbox delivery was deferred (a full inbox / transient outage). This is success, not failure — the token is finalized and the finished blob is journaled and re-delivered automatically.
deliveryState 'landed' (delivered) or 'pending-delivery' (deferred, as above).

Treat status === 'completed' as sent. Use deliveryPending only to show a "delivery pending" hint — never as an error. A stale-but-spent source is self-healed (the next live coin is selected automatically).

Handling send() rejections — CERTIFICATION_UNCONFIRMED is NOT re-sendable (money-safety)

send() throws for genuine failures (INVALID_RECIPIENT, insufficient balance, a TransferConflictError lost race) and for one indeterminate case you must handle specially: a ProofUnconfirmedError (code: 'CERTIFICATION_UNCONFIRMED', mayHaveCertified: true). It means the spend may already be on-chain but the proof fetch was inconclusive — the SDK keeps the intent open and completes it later under the same transferId.

  • ⚠️ Never re-issue send() on CERTIFICATION_UNCONFIRMED. A fresh send() mints a new transferId on a different source, so the original resumes and the retry sends → the recipient is double-paid. Treat it as "sent, pending confirmation."
  • Recovery is automatic. The open intent is replayed under the same transferId (recovers the proof + delivery, or records the spend if a rival tx won; never a second spend): partially-committed outcomes converge in-process, and every remaining open intent is resumed when the vertical starts (Sphere.init / Sphere.load / an address switch). There is no public resume API to call.
import { isSphereError } from '@unicitylabs/sphere-sdk';

try {
  const result = await sphere.payments.send({ recipient: '@bob', amount, coinId });
  // result.status === 'completed' (or result.deliveryPending === true) → sent
} catch (err) {
  if (isSphereError(err) && err.code === 'CERTIFICATION_UNCONFIRMED') {
    // Possibly already sent on-chain — DO NOT re-send. Resume finishes it.
  } else {
    // genuine failure — safe to surface to the user / retry
  }
}

Migrating off sphere.paymentsV2

The deprecated sphere.paymentsV2 alias and the paymentsV2: true init flag are removed in 0.15.0. sphere.payments is the only accessor, and it is the same facade the alias returned.

One behavioural difference matters: while no vertical is running (init in flight, mid address-switch, destroyed) the alias returned null and sphere.payments throws SphereError with code: 'NOT_INITIALIZED'. Call sites that leaned on the nullish alias — sphere.paymentsV2?.tokens(), ?? fallback, if (sphere.paymentsV2) as a readiness probe — silently degraded to "no payments" before and now throw, so catch NOT_INITIALIZED where you used to check for null. Code that runs after await Sphere.init(…) and before destroy() — everything else in this README — reads sphere.payments directly.

The accounting: / swap: options are not part of this cleanup: they still throw a typed INVALID_CONFIG, deliberately, because 0.15.0 is the release where consumers re-integrate.

Network Configuration

The SDK ships network presets that configure all services automatically. network is required — there is no default:

Network Aggregator (gateway) Nostr Relay
testnet gateway.testnet2.unicity.network (v2) nostr-relay.testnet.unicity.network
testnet2 alias of testnet (same configuration) nostr-relay.testnet.unicity.network
mainnet gateway.mainnet.unicity.network (v3) nostr-relay.testnet.unicity.network (shared until mainnet has its own)

Live networks are testnet2 and mainnet. testnet is an alias of testnet2 (network id 4, taken from the trust base; own testnet2 token registry); mainnet is network id 1. The v1 network is discontinued — the old goggregator-test testnet spoke the removed v1 protocol, and the dev network that aliased its trust base has been removed along with every other v1 pointer. Mainnet has no wallet-api deployment yet, so its money path is not reachable even though the chain and gateway are live. The transfer wire payload is the finished token blob — the base SDK's own Token.toCBOR() bytes, with no sphere envelope around them — deposited into the recipient's wallet-api mailbox.

The network name (testnet2) and the base-SDK major (3.x since 0.15.0) are separate axes: testnet2 is still testnet2 after the 3.0.1 bump. What the bump changes is the bytes on that network — a gateway serving the v3 protocol accepts nothing a 2.x client writes, and vice versa.

// Use testnet for all services
const providers = createBrowserProviders({ network: 'testnet' });

// Override specific services while using network preset
const providers = createBrowserProviders({
  network: 'testnet',
  oracle: { url: 'https://custom-gateway.example.com' }, // custom testnet2 gateway
});

API Key

The SDK bundles no default API key. Pass the gateway key via oracle: { apiKey } — without it, gateway requests are unauthenticated and money movement on testnet2 fails.

const providers = createBrowserProviders({
  network: 'testnet',
  oracle: { apiKey: 'sk_...' },
});

The testnet2 key is not a secret — it is published in .env.example and safe to keep in docs and client code. A mainnet key, by contrast, IS a secret: keep it in your deploy environment only.

Testnet2 endpoints (the values we build with)

The testnet preset wires most of these automatically — you only pass network, oracle.apiKey, and the wallet-api baseUrl. The full set, for reference and manual wiring:

What Value
Network testnet (alias testnet2), networkId 4
Aggregator / gateway (token engine) https://gateway.testnet2.unicity.network
Aggregator API key (public — not a secret) sk_ddc3cfcc001e4a28ac3fad7407f99590
wallet-api (delivery + token storage) https://wallet-api.unicity.network
Nostr relay (messaging / nametags) wss://nostr-relay.testnet.unicity.network
Group-chat relay (NIP-29) wss://sphere-relay.unicity.network
Token registry https://raw.githubusercontent.com/unicitynetwork/unicity-ids/refs/heads/main/unicity-ids.testnet2.json

The aggregator key above is the testnet2 key only and is safe in client code; a mainnet key is a real secret and must never be committed.

Price Provider (Optional)

Enable fiat price display by adding a price config. Currently supports CoinGecko API (free and pro tiers).

…

Without price config, the price fields in assets() are null. All other functionality works normally.

You can also set the price provider after initialization — price is a composition-time property of the payments vertical, so verticals composed after the call (the next address switch) pick it up:

import { createPriceProvider } from '@unicitylabs/sphere-sdk';

sphere.setPriceProvider(createPriceProvider({
  platform: 'coingecko',
  apiKey: 'CG-xxx',
}));

Test Tokens on Testnet (Self-Mint)

There is no faucet. On testnet you top up your wallet by self-minting fungible tokens via the t

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

TypeScriptai-agentsartificial-intelligenceblockchaincommerce

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
CategoryDevOps
PricingOpen source

> Related tools

D
Docker
容器化平台,标准化应用交付
G
GitHub Actions
GitHub 原生 CI/CD 工作流
N
Nginx
高性能 Web 服务器与反向代理