npm package: @sequence0/sdk
Description: Sequence0 Network SDK — Decentralized threshold signatures for any blockchain
Author: Sequence0 Network
Latest version: 3.7.6

# @sequence0/sdk

> **Decentralized threshold signatures for any blockchain.**
> Create wallets, sign transactions, and broadcast to 81 chains — no private keys required.

## Install

```bash
npm install @sequence0/sdk
```

## Quick Start

```typescript
import { Sequence0 } from '@sequence0/sdk';

// 1. Initialize the SDK
const s0 = new Sequence0({ network: 'mainnet' });

// 2. Create a threshold wallet (DKG ceremony with 24 agents)
const wallet = await s0.createWallet({ chain: 'ethereum' });
console.log('Address:', wallet.address);
console.log('Threshold:', wallet.threshold); // { t: 16, n: 24 }

// 3. Sign and send a transaction
const txHash = await wallet.sendTransaction({
  to: '0xRecipientAddress',
  value: '1000000000000000000', // 1 ETH in wei
});
console.log('TX Hash:', txHash);
```

## What's New in v3.6.2

### Bitcoin Taproot (P2TR) Support

Full Bitcoin Taproot transaction lifecycle: address derivation, UTXO management, transaction building, FROST Schnorr signing, and broadcast. FROST-secp256k1 produces BIP-340 compatible Schnorr signatures that are native to Taproot key-path spends.

```typescript
import { BitcoinTaprootAdapter } from '@sequence0/sdk';

const btc = new BitcoinTaprootAdapter({ network: 'mainnet' });

// Derive a Taproot address from a FROST group public key
const addr = btc.deriveAddress('02abcdef...');
console.log(addr.address); // bc1p...

// Get balance and UTXOs
const balance = await btc.getBalance('bc1p...');
const utxos = await btc.getUTXOs('bc1p...');

// Build a transaction
const unsignedTx = await btc.buildTransaction(
  { to: 'bc1p...recipient', amount: 50000, feeRate: 15 },
  'bc1p...sender'
);

// Or use via the Wallet class for automatic signing
const wallet = await s0.createWallet({ chain: 'bitcoin' });
const txHash = await wallet.sendTransaction({
  to: 'bc1p...recipient',
  amount: 50000,
  feeRate: 15,
});
```

### ERC-4337 Account Abstraction

Smart accounts backed by FROST threshold signing. Enables gas-sponsored transactions, batch calls, and programmable transaction validation.

```typescript
import { Sequence0Account } from '@sequence0/sdk';

// Create a new AA wallet backed by FROST
const account = await Sequence0Account.create({
  threshold: 16,
  committeeSize: 24,
  chain: 'ethereum',
  ownerPrivateKey: '0x...',
  bundlerUrl: 'https://api.pimlico.io/v2/1/rpc?apikey=YOUR_KEY',
});

console.log('Smart Account:', account.getAddress());

// Send a single transaction
const txHash = await account.sendTransaction({
  to: '0xRecipient',
  value: BigInt('1000000000000000000'),
});

// Batch multiple calls
const txHash2 = await account.sendBatchTransaction([
  { to: '0xTokenA', data: '0xa9059cbb...' },
  { to: '0xTokenB', data: '0xa9059cbb...' },
]);

// Sign messages
const sig = await account.signMessage('Hello from Sequence0 AA!');
```

## Features

| Feature | Description |
|---------|-------------|
| **Multi-Chain** | Ethereum, Bitcoin, Solana, Polygon, Arbitrum, Base, and 75+ more (81 total) |
| **Threshold Signing** | FROST (t-of-n) — no single point of failure |
| **No Private Keys** | Keys are sharded across the agent network |
| **Bitcoin Taproot** | Native P2TR support with BIP-340 Schnorr signatures |
| **Account Abstraction** | ERC-4337 smart accounts with batched transactions |
| **ERC-20 Tokens** | Build and sign ERC-20 transfers, approvals, and balance queries |
| **Real-Time Events** | WebSocket subscriptions for signing progress |
| **Chain Adapters** | Auto-builds chain-native transactions |

## Supported Chains

### EVM (secp256k1)
Ethereum, Polygon, Arbitrum, Optimism, Base, BSC, Avalanche, and 40+ more

### Bitcoin (Taproot/Schnorr)
Full P2TR lifecycle: address derivation, UTXO selection, transaction building, Schnorr signing, and broadcast via the `BitcoinTaprootAdapter`.

### Solana (Ed25519)
Native SOL transfers with versioned transactions.

> **Note:** Dogecoin and Litecoin support wallet creation and raw message signing via `sign()`. Full `sendTransaction()` support for these UTXO chains is coming soon.

## API Reference

### `Sequence0` -- Main Client

```typescript
const s0 = new Sequence0({
  network: 'mainnet',    // 'mainnet' | 'testnet'
  agentUrl: '...',       // Agent node URL (optional)
  timeout: 30000,        // Request timeout (optional)
});
```

### Ownership Verification

Every `/sign` request requires an ownership proof. Configure an `ownerSigner` or `ownerPrivateKey` when creating the SDK instance:

```typescript
// Option 1: Private key (SDK derives signer automatically)
const s0 = new Sequence0({
  network: 'mainnet',
  ownerPrivateKey: '0xYourPrivateKey...',
});

// Option 2: Custom signer function
const s0 = new Sequence0({
  network: 'mainnet',
  ownerSigner: async (digest: Uint8Array) => {
    // Sign the 32-byte digest and return 65-byte hex signature
    return myWallet.signDigest(digest);
  },
});
```

When creating a wallet, pass the `creator` address to record ownership on-chain:
```typescript
const wallet = await s0.createWallet({
  chain: 'ethereum',
  creator: '0xYourAddress...',
});
```

#### Methods

| Method | Returns | Description |
|--------|---------|-------------|
| `createWallet(options)` | `Promise<Wallet>` | Create a new threshold wallet via DKG |
| `getWallet(walletId)` | `Promise<Wallet>` | Get an existing wallet |
| `listWallets()` | `Promise<WalletDetail[]>` | List all wallets |
| `requestSignature(walletId, message)` | `Promise<string>` | Submit a signing request (returns requestId) |
| `signAndWait(walletId, message, timeout?)` | `Promise<string>` | Sign and wait for result |
| `getStatus()` | `Promise<StatusResponse>` | Get network status |
| `health()` | `Promise<HealthResponse>` | Health check |
| `subscribe(walletId?)` | `Promise<WsClient>` | Subscribe to real-time events |
| `refreshKeys(walletId)` | `Promise<void>` | Proactive key rotation |

### `Wallet` -- Threshold Wallet

```typescript
const wallet = await s0.createWallet({
  chain: 'ethereum',
  threshold: { t: 16, n: 24 },  // optional, default shown
  curve: 'secp256k1',            // auto-detected from chain
});
```

#### Methods

| Method | Returns | Description |
|--------|---------|-------------|
| `sign(transaction)` | `Promise<SignedTransaction>` | Sign a transaction |
| `sendTransaction(transaction)` | `Promise<string>` | Sign + broadcast (returns tx hash) |
| `broadcast(signedTx)` | `Promise<string>` | Broadcast a signed transaction |
| `signMessage(message)` | `Promise<string>` | Sign a message (EIP-191 for EVM) |
| `signTypedData(typedData)` | `Promise<string>` | Sign EIP-712 typed data |
| `getBalance()` | `Promise<string>` | Get native token balance |
| `info()` | `Record<string, unknown>` | Get wallet summary |

### `BitcoinTaprootAdapter` -- Bitcoin P2TR

```typescript
import { BitcoinTaprootAdapter } from '@sequence0/sdk';

const btc = new BitcoinTaprootAdapter({ network: 'mainnet' });
```

| Method | Returns | Description |
|--------|---------|-------------|
| `deriveAddress(pubkeyHex)` | `TaprootAddressInfo` | Derive bc1p... address from FROST public key |
| `getBalance(address)` | `Promise<string>` | Get balance in satoshis |
| `getUTXOs(address)` | `Promise<TaprootUtxo[]>` | Fetch unspent outputs |
| `getFeeRates()` | `Promise<FeeRateEstimate>` | Get recommended fee rates |
| `buildTransaction(tx, from)` | `Promise<string>` | Build unsigned transaction |
| `buildUnsignedTx(inputs, outputs, feeRate)` | `UnsignedTaprootTx` | Build with explicit inputs/outputs |
| `attachSignature(unsignedTx, sig)` | `Promise<string>` | Attach FROST Schnorr signature |
| `broadcast(signedTx)` | `Promise<string>` | Broadcast to Bitcoin network |
| `getTransaction(txid)` | `Promise<any>` | Get transaction details |
| `getBlockHeight()` | `Promise<number>` | Get current block height |

### `Sequence0Account` -- ERC-4337 Smart Account

```typescript
import { Sequence0Account } from '@sequence0/sdk';

const account = await Sequence0Account.create({
  threshold: 16,
  committeeSize: 24,
  chain: 'ethereum',
  ownerPrivateKey: '0x...',
  bundlerUrl: 'https://bundler.example.com',
});
```

| Method | Returns | Description |
|--------|---------|-------------|
| `Sequence0Account.create(options)` | `Promise<Sequence0Account>` | Create new AA wallet via DKG |
| `Sequence0Account.fromExisting(walletId, pubkey, options)` | `Promise<Sequence0Account>` | Reconnect to existing wallet |
| `getAddress()` | `string` | Get smart account address |
| `sendTransaction(tx)` | `Promise<string>` | Build, sign, submit UserOperation |
| `sendBatchTransaction(txs)` | `Promise<string>` | Batch multiple calls |
| `signMessage(message)` | `Promise<string>` | Sign with EIP-191 prefix |
| `buildUserOp(callData)` | `Promise<PackedUserOperation>` | Build unsigned UserOp |
| `submitUserOp(userOp, bundlerUrl?)` | `Promise<string>` | Submit to bundler |
| `estimateUserOpGas(userOp)` | `Promise<UserOperationGasEstimate>` | Estimate gas |
| `waitForUserOp(hash, timeout?)` | `Promise<UserOperationReceipt>` | Wait for inclusion |
| `getBalance()` | `Promise<string>` | Get native token balance |
| `isDeployed()` | `boolean` | Check if deployed on-chain |

### Chain Adapters

Use chain adapters directly for advanced control:

```typescript
import {
  EthereumAdapter,
  BitcoinTaprootAdapter,
  SolanaAdapter,
} from '@sequence0/sdk';

const eth = new EthereumAdapter('ethereum', 'https://eth.llamarpc.com');
const btc = new BitcoinTaprootAdapter({ network: 'mainnet' });
const sol = new SolanaAdapter('mainnet');
```

### WebSocket Events

```typescript
const ws = await s0.subscribe('my-wallet-id');

ws.on('SigningStarted', (e) => console.log('Signing started:', e));
ws.on('SigningComplete', (e) => console.log('Signature:', e.signature));
ws.on('WalletCreated', (e) => console.log('New wallet:', e.public_key));
ws.on('FeeCollected', (e) => console.log('Fee collected:', e.tx_hash));
ws.on('Heartbeat', (e) => console.log('Peers:', e.connected_peers));
```

## ERC-20 Token Transfers

Send ERC-20 tokens (USDC, WETH, DAI, etc.) from a threshold wallet. The SDK builds the unsigned `transfer` or `approve` calldata, produces the signing hash for FROST, and the wallet handles the rest.

```typescript
import { Sequence0, buildTokenTransfer, getTokenBalance } from '@sequence0/sdk';

const s0 = new Sequence0({ network: 'mainnet', ownerPrivateKey: '0x...' });
const wallet = await s0.createWallet({ chain: 'ethereum' });

// Check USDC balance
const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
const balance = await getTokenBalance('https://eth.llamarpc.com', USDC, wallet.address);
console.log(`${balance.balance} ${balance.symbol}`); // "1234.56 USDC"

// Build an unsigned USDC transfer
const { unsignedTx, messageHash } = await buildTokenTransfer(
  'https://eth.llamarpc.com',
  USDC,
  wallet.address,
  '0xRecipient...',
  '100.0',  // human-readable amount
  1,        // Ethereum mainnet chainId
);

// Sign via the threshold network
const signature = await s0.signAndWait(wallet.walletId, messageHash);
```

### Approvals

```typescript
import { buildTokenApproval, getTokenAllowance } from '@sequence0/sdk';

// Approve a DEX to spend USDC
const { unsignedTx, messageHash } = await buildTokenApproval(
  'https://eth.llamarpc.com',
  USDC,
  wallet.address,
  '0xDexRouter...',
  '1000.0',
  1,
);
const signature = await s0.signAndWait(wallet.walletId, messageHash);

// Check current allowance
const allowance = await getTokenAllowance(
  'https://eth.llamarpc.com',
  USDC,
  wallet.address,
  '0xDexRouter...',
);
console.log(`Allowance: ${allowance.allowance} ${allowance.symbol}`);
```

### Using with `wallet.sendTransaction`

For the simplest path, encode the ERC-20 calldata into a standard EVM transaction:

```typescript
import { ethers } from 'ethers';

const iface = new ethers.Interface(['function transfer(address to, uint256 amount)']);
const data = iface.encodeFunctionData('transfer', [
  '0xRecipient...',
  ethers.parseUnits('100', 6), // 100 USDC (6 decimals)
]);

const txHash = await wallet.sendTransaction({
  to: USDC,    // token contract as the "to" address
  data,        // encoded transfer calldata
  value: '0',  // no ETH value for token transfers
});
```

## Merkle Batch Signing

Batch up to 1024 transactions into a single Merkle tree and sign the root once. Proofs for individual transactions are verified on-chain via the BatchVerifier contract. This provides a 1000x throughput multiplier.

```typescript
import { buildMerkleTree, verifyMerkleProof, generateBatchId, computeBatchMessage } from '@sequence0/sdk';

// Build a Merkle tree from transaction hashes
const txHashes = ['0xabc...', '0xdef...', '0x123...']; // up to 1024
const { root, proofs, leafCount } = buildMerkleTree(txHashes);

// Verify a single leaf locally before submitting on-chain
const proof = proofs.get(0)!;
const valid = verifyMerkleProof(root, txHashes[0], proof);
console.log('Proof valid:', valid); // true

// Generate a batch ID and compute the signing message
const batchId = generateBatchId(txHashes, Date.now());
const message = computeBatchMessage(batchId, root, leafCount, 800801);

// Sign the batch message with a threshold wallet
const sig = await wallet.signMessage(message);
```

## Committee Discovery

When the network is sharded into committees, use `CommitteeDiscovery` to find the agents assigned to a specific wallet's committee. This enables parallel signing across committees for higher throughput.

```typescript
import { CommitteeDiscovery } from '@sequence0/sdk';

const committee = new CommitteeDiscovery({
    rpcUrl: 'https://rpc.sequence0.network',
    registryAddress: '0xDeFA5AB7ea6a87ac51628f4CdE55Bb4D49e62f50',
    committeeRegistryAddress: '0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e',
});

// Get the committee assigned to a wallet
const committeeId = await committee.getCommitteeForWallet('my-wallet-id');

// Get agents in that committee
const agents = await committee.getCommitteeAgents(committeeId);
console.log(`Committee ${committeeId}: ${agents.length} agents`);

// Select a healthy agent for signing
const agentUrl = await committee.selectSigningAgent(committeeId);
```

## Error Handling

```typescript
import { Sequence0Error, DkgError, SigningError, TimeoutError } from '@sequence0/sdk';

try {
  await wallet.sendTransaction({ to: '0x...', value: '100' });
} catch (e) {
  if (e instanceof TimeoutError) {
    console.log('Signing network busy, try again');
  } else if (e instanceof SigningError) {
    console.log('Signing failed:', e.message);
  }
}
```

## Any Language (HTTP)

This SDK wraps an internal **HTTP + JSON** interface exposed by every agent node. The SDK handles connection and discovery automatically, but you can also integrate from **any language** -- Python, Go, Rust, Java, etc. -- by calling the agent's HTTP endpoint directly:

```bash
# Health check
curl http://AGENT_HOST:8080/health

# Create a wallet (DKG)
curl -X POST http://AGENT_HOST:8080/dkg/initiate \
  -H 'Content-Type: application/json' \
  -d '{"wallet_id":"my-wallet","participants":["peer1","peer2"],"threshold":2,"curve":"secp256k1"}'

# Sign a message
curl -X POST http://AGENT_HOST:8080/sign \
  -H 'Content-Type: application/json' \
  -d '{"wallet_id":"my-wallet","message":"48656c6c6f"}'

# Poll for signature
curl http://AGENT_HOST:8080/sign/REQUEST_ID
```

**Testnet agents**: Operated by Sequence0 at `52.14.62.162` (ports 8080-8103).
**Mainnet**: Auto-discover agents from the on-chain AgentRegistry, or connect to a known agent URL.

Full HTTP reference: [sequence0.network/docs](https://sequence0.network/docs#app-developer-sdk)

## Networks

| | Mainnet | Testnet |
|---|---|---|
| **Chain ID** | 800801 | 800800 |
| **RPC** | `https://rpc.sequence0.network` | `https://testnet-rpc.sequence0.network` |
| **Explorer** | `https://explorer.sequence0.network` | `https://testnet.sequence0.network` |

## Economics

Signing fees are collected on the **target chain in its native token** (ETH on Ethereum, SOL on Solana, BTC on Bitcoin, etc.). The fee is built into the signed transaction itself. The FeeCollector contract on the Sequence0 chain handles governance (fee rates, split ratios) and accounting.

## License

MIT (c) Sequence0 Network