@toon-protocol/client 0.9.1 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +168 -34
- package/dist/anon-proxy-W3KMM7GU.js +23 -0
- package/dist/chunk-WHAEQLIW.js +276 -0
- package/dist/chunk-WHAEQLIW.js.map +1 -0
- package/dist/gateway-QOK47RKS.js +13 -0
- package/dist/gateway-QOK47RKS.js.map +1 -0
- package/dist/index.d.ts +1671 -35
- package/dist/index.js +2800 -425
- package/dist/index.js.map +1 -1
- package/dist/socks5-WTJBYGME.js +136 -0
- package/dist/socks5-WTJBYGME.js.map +1 -0
- package/package.json +12 -6
- package/LICENSE +0 -190
- package/dist/chunk-5WRI5ZAA.js +0 -31
- package/dist/mina-signer-J7GFWOGO.js +0 -6317
- package/dist/mina-signer-J7GFWOGO.js.map +0 -1
- /package/dist/{chunk-5WRI5ZAA.js.map → anon-proxy-W3KMM7GU.js.map} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,75 @@
|
|
|
1
1
|
import * as _toon_protocol_core from '@toon-protocol/core';
|
|
2
|
-
import { IlpPeerInfo, IlpSendResult, IlpClient, ConnectorAdminClient, ConnectorChannelClient, OpenChannelParams, OpenChannelResult, ChannelState } from '@toon-protocol/core';
|
|
3
|
-
import { NostrEvent } from 'nostr-tools/pure';
|
|
2
|
+
import { IlpPeerInfo, NetworkFamilyStatus, IlpSendResult, IlpClient, ConnectorAdminClient, ConnectorChannelClient, OpenChannelParams, OpenChannelResult, ChannelState } from '@toon-protocol/core';
|
|
3
|
+
import { NostrEvent, EventTemplate } from 'nostr-tools/pure';
|
|
4
4
|
import { PrivateKeyAccount } from 'viem/accounts';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Solana payment-channel parameters supplied via `ToonClientConfig.solanaChannel`.
|
|
8
|
+
*
|
|
9
|
+
* Mirrors the `SolanaChannelConfig` consumed by `OnChainChannelClient`, minus
|
|
10
|
+
* the Ed25519 keypair (derived from the client's `mnemonic`, see
|
|
11
|
+
* `ToonClientConfig.solanaChannel`).
|
|
12
|
+
*/
|
|
13
|
+
interface SolanaChannelClientOptions {
|
|
14
|
+
/** Solana JSON-RPC URL used to open the channel + read PDA state. */
|
|
15
|
+
rpcUrl: string;
|
|
16
|
+
/** Deployed payment-channel program id (base58). */
|
|
17
|
+
programId: string;
|
|
18
|
+
/**
|
|
19
|
+
* Default SPL token mint (base58) for PDA derivation. The per-channel
|
|
20
|
+
* negotiated token (the peer's preferred token) takes precedence when present.
|
|
21
|
+
*/
|
|
22
|
+
tokenMint?: string;
|
|
23
|
+
/** Challenge-period duration (seconds) for `initialize_channel`. */
|
|
24
|
+
challengeDuration?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Optional on-chain deposit when opening the channel: `amount` in base units
|
|
27
|
+
* (string) drawn from `payerTokenAccount` (the client's funded SPL token
|
|
28
|
+
* account / ATA, base58). When omitted, the channel is opened without a
|
|
29
|
+
* deposit (connector accepts on `opened` status + participant membership).
|
|
30
|
+
*/
|
|
31
|
+
deposit?: {
|
|
32
|
+
amount: string;
|
|
33
|
+
payerTokenAccount: string;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Mina payment-channel parameters supplied via `ToonClientConfig.minaChannel`.
|
|
38
|
+
*
|
|
39
|
+
* Mirrors the `MinaChannelConfig` consumed by `OnChainChannelClient`, minus the
|
|
40
|
+
* Mina private key (derived from the client's `mnemonic`, the same key that
|
|
41
|
+
* produces the registered Mina signer — so the channel-open key and the
|
|
42
|
+
* claim-signing key are guaranteed identical).
|
|
43
|
+
*
|
|
44
|
+
* ────────────────────────────────────────────────────────────────────────────
|
|
45
|
+
* PHASE-2 STAGE-3: the client's Mina claim now matches connector 3.9.0's
|
|
46
|
+
* `MinaClaimMessage` contract — `{ zkAppAddress, tokenId, balanceCommitment,
|
|
47
|
+
* proof (base64), salt, nonce }`, with the proof a Pallas Schnorr signature over
|
|
48
|
+
* the connector's `Poseidon([balA,balB,salt]) / Poseidon(zkApp.x)` commitment
|
|
49
|
+
* (verified field-by-field against the connector's o1js verify). A
|
|
50
|
+
* Mina-denominated paid publish is ACCEPTED at `validateClaimMessage` and the
|
|
51
|
+
* apex FULFILLs to town. On-chain SETTLE remains gated for non-EVM dynamic
|
|
52
|
+
* hidden-service peers by connector#88 (`No chain configured for peer`).
|
|
53
|
+
* `zkAppAddress` must be a REAL deployed payment-channel zkApp the apex's Mina
|
|
54
|
+
* provider can resolve on-chain (the e2e harness deploys it deterministically).
|
|
55
|
+
* ────────────────────────────────────────────────────────────────────────────
|
|
56
|
+
*/
|
|
57
|
+
interface MinaChannelClientOptions {
|
|
58
|
+
/** Mina GraphQL URL used to open the channel + read zkApp state. */
|
|
59
|
+
graphqlUrl: string;
|
|
60
|
+
/** Deployed payment-channel zkApp address (B62 base58). */
|
|
61
|
+
zkAppAddress: string;
|
|
62
|
+
/** Channel settlement timeout in slots for `initializeChannel` (default 86400). */
|
|
63
|
+
challengeDuration?: number;
|
|
64
|
+
/** Mina token id field (decimal string) for `initializeChannel` (default '1'). */
|
|
65
|
+
tokenId?: string;
|
|
66
|
+
/** Optional on-chain deposit (base units, string) after the channel opens. */
|
|
67
|
+
deposit?: {
|
|
68
|
+
amount: string;
|
|
69
|
+
};
|
|
70
|
+
/** Mina network id for the account/Schnorr prefix (default 'devnet'). */
|
|
71
|
+
networkId?: 'devnet' | 'mainnet';
|
|
72
|
+
}
|
|
6
73
|
/**
|
|
7
74
|
* Configuration for ToonClient.
|
|
8
75
|
*
|
|
@@ -43,9 +110,41 @@ interface ToonClientConfig {
|
|
|
43
110
|
* Reserved for future implementation.
|
|
44
111
|
*/
|
|
45
112
|
connector?: unknown;
|
|
113
|
+
/**
|
|
114
|
+
* BIP-39 mnemonic phrase to derive a full multi-chain identity from.
|
|
115
|
+
*
|
|
116
|
+
* When provided, the client derives the Nostr (NIP-06) + EVM keys
|
|
117
|
+
* synchronously at construction and the Solana (Ed25519) + Mina (Pallas) keys
|
|
118
|
+
* lazily in `start()`, registering per-chain signers so balance-proof claims
|
|
119
|
+
* can be settled on any of those chains. This is the recommended way to use
|
|
120
|
+
* non-EVM settlement (the raw `secretKey` path is secp256k1-only).
|
|
121
|
+
*
|
|
122
|
+
* Cannot be combined with `secretKey` (ambiguous Nostr identity). May be
|
|
123
|
+
* combined with `evmPrivateKey` to use a separate EVM key (e.g. hardware
|
|
124
|
+
* wallet) while still deriving Solana/Mina from the phrase.
|
|
125
|
+
*
|
|
126
|
+
* SECURITY: JavaScript strings are immutable and cannot be zeroed from
|
|
127
|
+
* memory — the phrase may persist in the heap until GC. Prefer
|
|
128
|
+
* passing a pre-derived `secretKey`/identity in high-security contexts.
|
|
129
|
+
*/
|
|
130
|
+
mnemonic?: string;
|
|
131
|
+
/**
|
|
132
|
+
* BIP-44 account index used when deriving the multi-chain identity from
|
|
133
|
+
* `mnemonic`. Defaults to 0 (back-compat). A non-zero index derives a
|
|
134
|
+
* dedicated wallet from a shared mnemonic, producing the SAME addresses as
|
|
135
|
+
* the SDK's `fromMnemonicFull(mnemonic, { accountIndex })`:
|
|
136
|
+
* - Nostr (secp256k1): m/44'/1237'/0'/0/{index}
|
|
137
|
+
* - EVM (secp256k1): same key as Nostr
|
|
138
|
+
* - Solana (Ed25519): m/44'/501'/{index}'/0' (SLIP-0010)
|
|
139
|
+
* - Mina (Pallas): m/44'/12586'/{index}'/0/0
|
|
140
|
+
*
|
|
141
|
+
* Ignored unless `mnemonic` is provided.
|
|
142
|
+
*/
|
|
143
|
+
mnemonicAccountIndex?: number;
|
|
46
144
|
/**
|
|
47
145
|
* 32-byte Nostr private key (hex or Uint8Array).
|
|
48
|
-
* Optional — if omitted, a keypair is auto-generated in applyDefaults()
|
|
146
|
+
* Optional — if omitted, a keypair is auto-generated in applyDefaults()
|
|
147
|
+
* (or derived from `mnemonic` when that is provided instead).
|
|
49
148
|
*/
|
|
50
149
|
secretKey?: Uint8Array;
|
|
51
150
|
/** ILP peer information for this client */
|
|
@@ -65,6 +164,27 @@ interface ToonClientConfig {
|
|
|
65
164
|
* (e.g., hardware wallet, custodial key, or legacy key separation).
|
|
66
165
|
*/
|
|
67
166
|
evmPrivateKey?: string | Uint8Array;
|
|
167
|
+
/**
|
|
168
|
+
* Named network tier. When set (and != `'custom'`), the client defaults all
|
|
169
|
+
* settlement-related config — RPC/GraphQL URLs, supported chain identifiers,
|
|
170
|
+
* preferred tokens, EVM TokenNetwork addresses, and the Solana/Mina channel
|
|
171
|
+
* params (programId / zkApp) — from the shared core presets
|
|
172
|
+
* (`resolveClientNetwork`), so the caller no longer hand-wires every address.
|
|
173
|
+
* This is the client-side mirror of the townhouse node's `network` selector;
|
|
174
|
+
* both resolve the SAME deployed contracts.
|
|
175
|
+
*
|
|
176
|
+
* Precedence: any explicit per-chain field (`supportedChains`,
|
|
177
|
+
* `chainRpcUrls`, `settlementAddresses`, `preferredTokens`, `tokenNetworks`,
|
|
178
|
+
* `solanaChannel`, `minaChannel`) you also pass OVERRIDES the preset for that
|
|
179
|
+
* field. `'custom'` keeps the fully-manual path (no preset defaults). When
|
|
180
|
+
* unset, behaviour is unchanged (fully backward compatible).
|
|
181
|
+
*
|
|
182
|
+
* - `mainnet` — Base mainnet + public Solana/Mina (TOON contracts not yet
|
|
183
|
+
* deployed → settlement unconfigured, relay-only).
|
|
184
|
+
* - `testnet` / `devnet` — Base Sepolia + Solana/Mina devnet with the LIVE
|
|
185
|
+
* deployed TOON settlement contracts.
|
|
186
|
+
*/
|
|
187
|
+
network?: 'mainnet' | 'testnet' | 'devnet' | 'custom';
|
|
68
188
|
/** Supported settlement chain identifiers (e.g., ["evm:anvil:31337"]) */
|
|
69
189
|
supportedChains?: string[];
|
|
70
190
|
/** Maps chain identifier to EVM settlement address */
|
|
@@ -79,6 +199,27 @@ interface ToonClientConfig {
|
|
|
79
199
|
btpAuthToken?: string;
|
|
80
200
|
/** Peer ID for BTP connection (used in connector env var BTP_PEER_{ID}_SECRET) */
|
|
81
201
|
btpPeerId?: string;
|
|
202
|
+
/**
|
|
203
|
+
* ILP-over-HTTP one-shot endpoint of the uplink connector (the `POST /ilp`
|
|
204
|
+
* URL, e.g. "http://localhost:3000/ilp"). When set, the client prefers the
|
|
205
|
+
* stateless {@link HttpIlpClient} transport for one-shot writes instead of
|
|
206
|
+
* opening a persistent BTP WebSocket.
|
|
207
|
+
*
|
|
208
|
+
* This mirrors the `httpEndpoint` field a peer advertises in discovery
|
|
209
|
+
* (`IlpPeerInfo`, toon PR #29). It is surfaced here as explicit config so the
|
|
210
|
+
* default runtime can opt into ILP-over-HTTP before connectors advertise the
|
|
211
|
+
* field on-wire. Leave unset to keep the existing BTP-only behavior (the safe
|
|
212
|
+
* default — no connector advertises an httpEndpoint until the connector + a
|
|
213
|
+
* core release with these fields ship).
|
|
214
|
+
*/
|
|
215
|
+
connectorHttpEndpoint?: string;
|
|
216
|
+
/**
|
|
217
|
+
* Whether the uplink connector accepts a BTP `Upgrade` over its HTTP endpoint
|
|
218
|
+
* (mirrors `IlpPeerInfo.supportsUpgrade`, toon PR #29). Only consulted when
|
|
219
|
+
* `connectorHttpEndpoint` is set and a duplex session is required. Defaults to
|
|
220
|
+
* false (no upgrade) when omitted.
|
|
221
|
+
*/
|
|
222
|
+
connectorSupportsUpgrade?: boolean;
|
|
82
223
|
/**
|
|
83
224
|
* ILP destination address for event publishing.
|
|
84
225
|
* Defaults to the connector's local address (derived from connectorUrl host).
|
|
@@ -94,8 +235,66 @@ interface ToonClientConfig {
|
|
|
94
235
|
initialDeposit?: string;
|
|
95
236
|
/** Challenge period in seconds (default: 86400) */
|
|
96
237
|
settlementTimeout?: number;
|
|
238
|
+
/**
|
|
239
|
+
* Solana payment-channel parameters for opening a REAL on-chain channel and
|
|
240
|
+
* signing a connector-format Solana balance proof.
|
|
241
|
+
*
|
|
242
|
+
* When present (and the client has a Solana signer — i.e. it was constructed
|
|
243
|
+
* from a `mnemonic`), `ToonClient.start()` wires these into the on-chain
|
|
244
|
+
* channel client so that negotiating a `solana:*` chain opens an on-chain
|
|
245
|
+
* channel at the connector-parity PDA and pays a Solana-denominated claim.
|
|
246
|
+
*
|
|
247
|
+
* The Ed25519 keypair is NOT carried here — it is derived from the same
|
|
248
|
+
* `mnemonic` that produces the Solana signer, so the channel-open key and the
|
|
249
|
+
* claim-signing key are guaranteed identical.
|
|
250
|
+
*/
|
|
251
|
+
solanaChannel?: SolanaChannelClientOptions;
|
|
252
|
+
/**
|
|
253
|
+
* Mina payment-channel parameters (graphqlUrl + zkAppAddress). When present
|
|
254
|
+
* (and the client has a Mina signer — i.e. it was constructed from a
|
|
255
|
+
* `mnemonic` AND `mina-signer` is installed), `ToonClient.start()` wires these
|
|
256
|
+
* into the on-chain channel client so negotiating a `mina:*` chain routes
|
|
257
|
+
* through `openMinaChannel` and pays a Mina-denominated claim.
|
|
258
|
+
*
|
|
259
|
+
* The Mina private key is NOT carried here — it is derived from the same
|
|
260
|
+
* `mnemonic` that produces the Mina signer.
|
|
261
|
+
*
|
|
262
|
+
* NOTE (Phase-2 Stage-3 gate): see `MinaChannelClientOptions` — supplying this
|
|
263
|
+
* wires the negotiation path but the resulting claim does not yet satisfy
|
|
264
|
+
* connector 3.9.0's Mina claim contract, so a live loop is claim-validation
|
|
265
|
+
* gated (distinct from the connector #88 on-chain-settle gate).
|
|
266
|
+
*/
|
|
267
|
+
minaChannel?: MinaChannelClientOptions;
|
|
97
268
|
/** File path for persisting payment channel nonce/amount state across restarts */
|
|
98
269
|
channelStorePath?: string;
|
|
270
|
+
/**
|
|
271
|
+
* Transport configuration for privacy-preserving connections.
|
|
272
|
+
*
|
|
273
|
+
* - `direct` (default): No privacy overlay, connect directly.
|
|
274
|
+
* - `socks5`: Route connections through a SOCKS5 proxy (Node.js only).
|
|
275
|
+
* Requires `socks5h://` scheme for DNS leak prevention.
|
|
276
|
+
* - `gateway`: Route connections through an ator gateway URL (browser-compatible).
|
|
277
|
+
* The gateway proxies through ator server-side.
|
|
278
|
+
*/
|
|
279
|
+
transport?: ClientTransportConfig;
|
|
280
|
+
/**
|
|
281
|
+
* Self-managed `anon` (anyone-protocol / ATOR) SOCKS5h proxy (Node.js only).
|
|
282
|
+
*
|
|
283
|
+
* When the `btpUrl` host ends in `.anyone` and NO explicit proxy is configured
|
|
284
|
+
* (`transport.socksProxy` / `transport.type === 'gateway'`) and the
|
|
285
|
+
* `ANYONE_PROXY_URLS` env var is unset, the SDK auto-downloads + spawns its own
|
|
286
|
+
* `anon` daemon, waits for it to bootstrap + bind a loopback SOCKS5 port, and
|
|
287
|
+
* routes BTP/HTTP through it — ZERO manual proxy setup. `client.stop()` tears
|
|
288
|
+
* the daemon down.
|
|
289
|
+
*
|
|
290
|
+
* - `undefined` (default): auto — managed proxy starts for `.anyone` hosts.
|
|
291
|
+
* - `false`: opt out — never auto-start (you must supply your own proxy).
|
|
292
|
+
*
|
|
293
|
+
* Ignored in browser bundles (the node-only daemon module is never loaded).
|
|
294
|
+
*/
|
|
295
|
+
managedAnonProxy?: boolean;
|
|
296
|
+
/** Loopback SOCKS port the managed `anon` daemon binds. Default 9050. */
|
|
297
|
+
managedAnonSocksPort?: number;
|
|
99
298
|
/** Nostr relay URL for peer discovery. Default: 'ws://localhost:7100' */
|
|
100
299
|
relayUrl?: string;
|
|
101
300
|
/**
|
|
@@ -166,7 +365,149 @@ interface SignedBalanceProof extends BalanceProofParams {
|
|
|
166
365
|
tokenNetworkAddress: string;
|
|
167
366
|
/** ERC-20 token address (e.g. USDC) for self-describing claim verification */
|
|
168
367
|
tokenAddress?: string;
|
|
368
|
+
/**
|
|
369
|
+
* Counterparty settlement address the balance proof is bound to.
|
|
370
|
+
*
|
|
371
|
+
* Required for Solana/Mina, where the canonical balance-proof message folds
|
|
372
|
+
* the recipient in (`balanceProofHashSolana` / `balanceProofFieldsMina`).
|
|
373
|
+
* Unused for the client's EVM path (EIP-712 `BalanceProof` has no recipient
|
|
374
|
+
* term). Carried here so it flows from signing through to `buildClaimMessage`.
|
|
375
|
+
*/
|
|
376
|
+
recipient?: string;
|
|
377
|
+
/**
|
|
378
|
+
* Mina payment-channel claim fields (connector 3.9.0 `MinaClaimMessage`).
|
|
379
|
+
*
|
|
380
|
+
* Populated only by {@link MinaSigner}, which produces the connector's
|
|
381
|
+
* `Poseidon([balA,balB,salt])` balance commitment + a Pallas Schnorr `proof`
|
|
382
|
+
* over `[commitment, Field(nonce), Poseidon(zkApp.x)]` rather than reusing the
|
|
383
|
+
* generic `signature` field. Carried so they flow from signing through to
|
|
384
|
+
* `MinaSigner.buildClaimMessage`. Absent for EVM/Solana.
|
|
385
|
+
*/
|
|
386
|
+
mina?: {
|
|
387
|
+
/** `Poseidon([balanceA, balanceB, salt]).toString()`. */
|
|
388
|
+
balanceCommitment: string;
|
|
389
|
+
/** base64-encoded JSON proof `{ commitment, signature: { r, s }, nonce, signerPublicKey }`. */
|
|
390
|
+
proof: string;
|
|
391
|
+
/** Decimal salt string. */
|
|
392
|
+
salt: string;
|
|
393
|
+
/** Mina token id (default `'MINA'`). */
|
|
394
|
+
tokenId: string;
|
|
395
|
+
};
|
|
169
396
|
}
|
|
397
|
+
/**
|
|
398
|
+
* Transport configuration for privacy-preserving connections.
|
|
399
|
+
*
|
|
400
|
+
* Node.js: Use `socks5` to route WebSocket and HTTP through a SOCKS5 proxy.
|
|
401
|
+
* Browser: Use `gateway` to route through a server-side ator gateway.
|
|
402
|
+
*/
|
|
403
|
+
type ClientTransportConfig = {
|
|
404
|
+
type: 'direct';
|
|
405
|
+
} | {
|
|
406
|
+
type: 'socks5';
|
|
407
|
+
/** SOCKS5 proxy URL. MUST use `socks5h://` scheme (DNS leak prevention). */
|
|
408
|
+
socksProxy: string;
|
|
409
|
+
} | {
|
|
410
|
+
type: 'gateway';
|
|
411
|
+
/** Gateway base URL that proxies connections through ator server-side. */
|
|
412
|
+
gatewayUrl: string;
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Client-side helper for kind:5094 Arweave blob storage DVM requests.
|
|
417
|
+
*
|
|
418
|
+
* This composes the three steps a caller previously had to wire by hand:
|
|
419
|
+
* 1. Build the kind:5094 event via `buildBlobStorageRequest()` (@toon-protocol/core).
|
|
420
|
+
* 2. Publish it to the DVM destination over ILP via `ToonClient.publishEvent()`
|
|
421
|
+
* (reusing the existing claim / channel plumbing).
|
|
422
|
+
* 3. Decode the FULFILL `data` field into the Arweave transaction ID.
|
|
423
|
+
*
|
|
424
|
+
* ## FULFILL data contract
|
|
425
|
+
*
|
|
426
|
+
* For a successful single-packet (non-chunked) blob upload, the DVM provider
|
|
427
|
+
* returns the Arweave transaction ID as a **UTF-8 string, base64-encoded** in
|
|
428
|
+
* the ILP FULFILL `data` field (the connector validates that FULFILL data is
|
|
429
|
+
* base64). An Arweave tx ID is a 43-character base64url string (32 raw bytes).
|
|
430
|
+
*
|
|
431
|
+
* So the decode is:
|
|
432
|
+
* `txId = utf8(base64decode(result.data))`
|
|
433
|
+
*
|
|
434
|
+
* See `packages/sdk/src/arweave/arweave-dvm-handler.ts` for the server side and
|
|
435
|
+
* `packages/client/tests/e2e/docker-arweave-dvm-e2e.test.ts` for the reference
|
|
436
|
+
* end-to-end flow this helper mirrors.
|
|
437
|
+
*
|
|
438
|
+
* Chunked uploads (multi-packet, via `uploadId` / `chunkIndex` / `totalChunks`
|
|
439
|
+
* params) are intentionally out of scope for this single-packet helper — the
|
|
440
|
+
* provider returns `ack:<n>` for intermediate chunks and the tx ID only on the
|
|
441
|
+
* final chunk. Callers needing chunking should drive `publishEvent()` directly
|
|
442
|
+
* (see the chunked case in the reference E2E test). Tracked as a follow-up.
|
|
443
|
+
*/
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Parameters for {@link requestBlobStorage}.
|
|
447
|
+
*/
|
|
448
|
+
interface RequestBlobStorageParams {
|
|
449
|
+
/** The raw blob data to store on Arweave. */
|
|
450
|
+
blobData: Uint8Array;
|
|
451
|
+
/**
|
|
452
|
+
* MIME type of the blob. Defaults to `'application/octet-stream'`
|
|
453
|
+
* (matching `buildBlobStorageRequest`).
|
|
454
|
+
*/
|
|
455
|
+
contentType?: string;
|
|
456
|
+
/**
|
|
457
|
+
* Bid amount in USDC micro-units, as a string (declared in the event's
|
|
458
|
+
* `bid` tag). Defaults to the stringified `ilpAmount` when omitted.
|
|
459
|
+
*
|
|
460
|
+
* At least one of `bid` / `ilpAmount` should be provided so the declared
|
|
461
|
+
* bid and the paid ILP amount agree.
|
|
462
|
+
*/
|
|
463
|
+
bid?: string;
|
|
464
|
+
/**
|
|
465
|
+
* ILP destination address of the DVM that performs the upload
|
|
466
|
+
* (e.g. `'g.toon.peer1'`). Falls back to the client's configured
|
|
467
|
+
* `destinationAddress` when omitted.
|
|
468
|
+
*/
|
|
469
|
+
destination?: string;
|
|
470
|
+
/**
|
|
471
|
+
* Pre-signed balance proof claim for this packet. When omitted, the
|
|
472
|
+
* client's channel manager auto-opens a channel and auto-signs a claim
|
|
473
|
+
* (same lazy-channel behavior as `publishEvent`).
|
|
474
|
+
*/
|
|
475
|
+
claim?: SignedBalanceProof;
|
|
476
|
+
/**
|
|
477
|
+
* Explicit ILP payment amount (bigint micro-units). When omitted,
|
|
478
|
+
* `publishEvent` computes it from the encoded event size. When `bid`
|
|
479
|
+
* is omitted, this value is stringified to populate the event's bid tag.
|
|
480
|
+
*/
|
|
481
|
+
ilpAmount?: bigint;
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Typed result of {@link requestBlobStorage}.
|
|
485
|
+
*/
|
|
486
|
+
interface RequestBlobStorageResult {
|
|
487
|
+
/** Whether the upload succeeded and a tx ID was decoded. */
|
|
488
|
+
success: boolean;
|
|
489
|
+
/** The Arweave transaction ID (43-char base64url) when `success` is true. */
|
|
490
|
+
txId?: string;
|
|
491
|
+
/** The id of the kind:5094 event that was published. */
|
|
492
|
+
eventId?: string;
|
|
493
|
+
/** Error message when `success` is false. */
|
|
494
|
+
error?: string;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Requests permanent Arweave blob storage from a DVM in a single ILP packet.
|
|
498
|
+
*
|
|
499
|
+
* Mirrors the single-packet flow in
|
|
500
|
+
* `packages/client/tests/e2e/docker-arweave-dvm-e2e.test.ts`: builds a signed
|
|
501
|
+
* kind:5094 event, publishes it through the supplied {@link ToonClient}
|
|
502
|
+
* (reusing its claim/channel plumbing), and decodes the FULFILL `data` field
|
|
503
|
+
* into an Arweave transaction ID.
|
|
504
|
+
*
|
|
505
|
+
* @param client - A started `ToonClient` (call `client.start()` first).
|
|
506
|
+
* @param secretKey - The Nostr secret key used to sign the kind:5094 event.
|
|
507
|
+
* @param params - Blob, content type, bid, destination, and payment options.
|
|
508
|
+
* @returns `{ success, txId?, eventId?, error? }`.
|
|
509
|
+
*/
|
|
510
|
+
declare function requestBlobStorage(client: ToonClient, secretKey: Uint8Array, params: RequestBlobStorageParams): Promise<RequestBlobStorageResult>;
|
|
170
511
|
|
|
171
512
|
/**
|
|
172
513
|
* ToonClient - High-level client for interacting with TOON network.
|
|
@@ -209,6 +550,20 @@ declare class ToonClient {
|
|
|
209
550
|
private readonly config;
|
|
210
551
|
private state;
|
|
211
552
|
private readonly evmSigner?;
|
|
553
|
+
private solanaSigner?;
|
|
554
|
+
/**
|
|
555
|
+
* Ed25519 signing seed (32 bytes) derived from the mnemonic for the Solana
|
|
556
|
+
* identity. Retained so `start()` can inject it into the on-chain channel
|
|
557
|
+
* client's Solana config (same key as `solanaSigner`).
|
|
558
|
+
*/
|
|
559
|
+
private solanaSeed?;
|
|
560
|
+
private minaSigner?;
|
|
561
|
+
/**
|
|
562
|
+
* Mina private key (big-endian hex scalar, as `deriveFullIdentity` emits)
|
|
563
|
+
* derived from the mnemonic. Retained so `start()` can inject it into the
|
|
564
|
+
* on-chain channel client's Mina config (same key as `minaSigner`).
|
|
565
|
+
*/
|
|
566
|
+
private minaPrivateKey?;
|
|
212
567
|
private channelManager?;
|
|
213
568
|
private readonly peerNegotiations;
|
|
214
569
|
/**
|
|
@@ -232,10 +587,58 @@ declare class ToonClient {
|
|
|
232
587
|
* Works before start() is called.
|
|
233
588
|
*/
|
|
234
589
|
getPublicKey(): string;
|
|
590
|
+
/**
|
|
591
|
+
* Sign an unsigned Nostr event template with the client's Nostr secret key,
|
|
592
|
+
* returning a fully-signed event (id + pubkey + sig).
|
|
593
|
+
*
|
|
594
|
+
* This is the key primitive behind the daemon's sign-and-publish path: a UI
|
|
595
|
+
* or agent supplies only `{ kind, content, tags, created_at }` and never holds
|
|
596
|
+
* the private key — signing happens here, inside the key owner.
|
|
597
|
+
*/
|
|
598
|
+
signEvent(template: EventTemplate): NostrEvent;
|
|
599
|
+
/**
|
|
600
|
+
* Upload bytes to Arweave via the kind:5094 blob-storage DVM (single-packet),
|
|
601
|
+
* signing the request with this client's Nostr key and paying through its
|
|
602
|
+
* existing channel. Returns the Arweave tx id on success.
|
|
603
|
+
*
|
|
604
|
+
* Backs the daemon's `upload-media` path: the key and claim/channel plumbing
|
|
605
|
+
* stay inside the client; callers pass only the bytes.
|
|
606
|
+
*/
|
|
607
|
+
uploadBlob(params: {
|
|
608
|
+
blobData: Uint8Array;
|
|
609
|
+
contentType?: string;
|
|
610
|
+
bid?: string;
|
|
611
|
+
destination?: string;
|
|
612
|
+
ilpAmount?: bigint;
|
|
613
|
+
}): Promise<RequestBlobStorageResult>;
|
|
614
|
+
/**
|
|
615
|
+
* Per-chain settlement readiness for the configured `network` tier, mirroring
|
|
616
|
+
* the townhouse node's status. Returns `undefined` when no named `network` is
|
|
617
|
+
* set (or `network: 'custom'`), since there is no preset tier to report on.
|
|
618
|
+
*/
|
|
619
|
+
getNetworkStatus(): NetworkFamilyStatus | undefined;
|
|
235
620
|
/**
|
|
236
621
|
* Gets the EVM address derived from the Nostr secret key (or explicit evmPrivateKey override).
|
|
237
622
|
*/
|
|
238
623
|
getEvmAddress(): string | undefined;
|
|
624
|
+
/**
|
|
625
|
+
* Gets the Solana (base58) address, when the client was constructed from a
|
|
626
|
+
* `mnemonic`. Available only AFTER `start()` (Solana keys are derived
|
|
627
|
+
* asynchronously). Returns undefined otherwise.
|
|
628
|
+
*/
|
|
629
|
+
getSolanaAddress(): string | undefined;
|
|
630
|
+
/**
|
|
631
|
+
* Gets the Mina (base58) address, when the client was constructed from a
|
|
632
|
+
* `mnemonic` AND `mina-signer` is installed. Available only AFTER `start()`.
|
|
633
|
+
* Returns undefined otherwise.
|
|
634
|
+
*/
|
|
635
|
+
getMinaAddress(): string | undefined;
|
|
636
|
+
/**
|
|
637
|
+
* Derive the Solana/Mina keys from the mnemonic and register their signers on
|
|
638
|
+
* the ChannelManager. Mirrors how the EVM signer is wired, but for the
|
|
639
|
+
* non-secp256k1 chains. Skips any chain whose optional dependency is missing.
|
|
640
|
+
*/
|
|
641
|
+
private registerMnemonicChainSigners;
|
|
239
642
|
/**
|
|
240
643
|
* Starts the ToonClient.
|
|
241
644
|
*
|
|
@@ -263,7 +666,58 @@ declare class ToonClient {
|
|
|
263
666
|
publishEvent(event: NostrEvent, options?: {
|
|
264
667
|
destination?: string;
|
|
265
668
|
claim?: SignedBalanceProof;
|
|
669
|
+
ilpAmount?: bigint;
|
|
266
670
|
}): Promise<PublishEventResult>;
|
|
671
|
+
/**
|
|
672
|
+
* Sends a raw swap ILP packet (Story 12.5) to a Mill peer with an attached
|
|
673
|
+
* balance-proof claim. This is a lower-level surface than `publishEvent`:
|
|
674
|
+
* it forwards the raw `IlpSendResult` so the sender (`streamSwap()`) can
|
|
675
|
+
* decode FULFILL metadata itself.
|
|
676
|
+
*
|
|
677
|
+
* Claim resolution mirrors `publishEvent`:
|
|
678
|
+
* (a) explicit `params.claim` -> use it,
|
|
679
|
+
* (b) `channelManager` present -> auto-open + auto-sign for the peer
|
|
680
|
+
* matching `destination`,
|
|
681
|
+
* (c) neither -> throw MISSING_CLAIM.
|
|
682
|
+
*
|
|
683
|
+
* @throws {ToonClientError} INVALID_STATE / NO_BTP_CLIENT / MISSING_CLAIM
|
|
684
|
+
*/
|
|
685
|
+
sendSwapPacket(params: {
|
|
686
|
+
destination: string;
|
|
687
|
+
amount: bigint;
|
|
688
|
+
toonData: Uint8Array;
|
|
689
|
+
timeout?: number;
|
|
690
|
+
claim?: SignedBalanceProof;
|
|
691
|
+
}): Promise<IlpSendResult>;
|
|
692
|
+
/**
|
|
693
|
+
* Build a BTP claim message from a pre-signed balance proof using the
|
|
694
|
+
* CHAIN-APPROPRIATE signer.
|
|
695
|
+
*
|
|
696
|
+
* The explicit-claim path (caller signs the balance proof, then passes
|
|
697
|
+
* `{ claim }`) must wrap the proof with the signer matching the channel's
|
|
698
|
+
* chain. Hardcoding `EvmSigner.buildClaimMessage` here produced an EVM
|
|
699
|
+
* `BTPClaimMessage` for a Solana/Mina balance proof — no `blockchain`
|
|
700
|
+
* discriminator and the base58 channel account placed in the EVM
|
|
701
|
+
* `channelId` field — which the connector's inbound validator classifies
|
|
702
|
+
* as EVM and rejects with F06 (`Invalid channelId format`).
|
|
703
|
+
*
|
|
704
|
+
* When the proof's `channelId` is tracked we use
|
|
705
|
+
* `getSignerForChannel(channelId).buildClaimMessage`, which emits the
|
|
706
|
+
* correct per-chain envelope (e.g. `blockchain:'solana'` + base58
|
|
707
|
+
* `channelAccount`). When it is not tracked we fall back to the EVM signer
|
|
708
|
+
* to preserve prior behavior for lightweight/EVM-only callers.
|
|
709
|
+
*
|
|
710
|
+
* EVM output is byte-identical to the previous hardcoded path (the EVM
|
|
711
|
+
* adapter in `getSignerForChannel` delegates to the same
|
|
712
|
+
* `EvmSigner.buildClaimMessage`).
|
|
713
|
+
*/
|
|
714
|
+
private buildClaimMessageForProof;
|
|
715
|
+
/**
|
|
716
|
+
* Shared claim-resolution logic used by `publishEvent` and `sendSwapPacket`.
|
|
717
|
+
* TODO(12.5 followup): also factor `publishEvent`'s inline claim resolution
|
|
718
|
+
* to call this helper. Kept duplicated for now to minimize regression risk.
|
|
719
|
+
*/
|
|
720
|
+
private resolveClaimForDestination;
|
|
267
721
|
/**
|
|
268
722
|
* Signs a balance proof for the given channel with the specified amount.
|
|
269
723
|
* Delegates to ChannelManager which auto-increments nonce and tracks cumulative amount.
|
|
@@ -274,6 +728,22 @@ declare class ToonClient {
|
|
|
274
728
|
* @throws {ToonClientError} If no EVM signer configured or channel not tracked
|
|
275
729
|
*/
|
|
276
730
|
signBalanceProof(channelId: string, amount: bigint): Promise<SignedBalanceProof>;
|
|
731
|
+
/**
|
|
732
|
+
* Eagerly open (or return existing) payment channel for the given destination.
|
|
733
|
+
*
|
|
734
|
+
* Channels are normally opened lazily on the first `publishEvent()` /
|
|
735
|
+
* `sendSwapPacket()` call. This method exposes the lazy-open path so
|
|
736
|
+
* callers (and E2E tests) that need a tracked `channelId` BEFORE publishing
|
|
737
|
+
* can force the open. Idempotent — returns the existing channel ID for the
|
|
738
|
+
* peer if one is already open.
|
|
739
|
+
*
|
|
740
|
+
* @param destination - Optional ILP destination address. Defaults to
|
|
741
|
+
* `config.destinationAddress`.
|
|
742
|
+
* @returns The channel ID of the (now) open channel.
|
|
743
|
+
* @throws {ToonClientError} If client not started, no channel manager
|
|
744
|
+
* configured, or peer negotiation metadata missing.
|
|
745
|
+
*/
|
|
746
|
+
openChannel(destination?: string): Promise<string>;
|
|
277
747
|
/**
|
|
278
748
|
* Gets list of tracked payment channel IDs.
|
|
279
749
|
*/
|
|
@@ -343,6 +813,48 @@ declare class ToonClient {
|
|
|
343
813
|
getDiscoveredPeers(): _toon_protocol_core.DiscoveredPeer[];
|
|
344
814
|
}
|
|
345
815
|
|
|
816
|
+
/**
|
|
817
|
+
* Hidden-service hostname validation for the anyone-protocol / ATOR network.
|
|
818
|
+
*
|
|
819
|
+
* The `anon` binary routes hidden-service hostnames under the **`.anyone`** TLD
|
|
820
|
+
* ONLY. A `<host>.anon` name is NOT recognized as a hidden service — anon treats
|
|
821
|
+
* it as a clearnet name and tries to exit-resolve it, which fails
|
|
822
|
+
* (`resolve failed` / `HostUnreachable`). Only `<host>.anyone` triggers anon's
|
|
823
|
+
* `parse_extended_hostname: Anyone dns address lookup` and is validated.
|
|
824
|
+
*
|
|
825
|
+
* Historically the client and the toon-client pod accepted BOTH `.anon` and
|
|
826
|
+
* `.anyone`, so a `.anon` address was silently accepted and then failed deep in
|
|
827
|
+
* the transport with an opaque error. This module makes `.anyone` the single
|
|
828
|
+
* accepted/routable HS TLD and rejects `.anon` up front with an actionable
|
|
829
|
+
* message (see issue #201).
|
|
830
|
+
*
|
|
831
|
+
* This is a pure, browser-safe helper (no Node built-ins) so it can be imported
|
|
832
|
+
* from any transport path.
|
|
833
|
+
*/
|
|
834
|
+
/**
|
|
835
|
+
* A `<host>.anyone` hidden-service hostname. The label is base32 (`a-z2-7`),
|
|
836
|
+
* matching the on-wire onion-style address alphabet anon uses.
|
|
837
|
+
*/
|
|
838
|
+
declare const HS_HOSTNAME_REGEX: RegExp;
|
|
839
|
+
/** Max length of an HS hostname (defensive bound against pathological input). */
|
|
840
|
+
declare const HS_HOSTNAME_MAX_LENGTH = 80;
|
|
841
|
+
/**
|
|
842
|
+
* Returns true iff `s` is a routable `.anyone` hidden-service hostname.
|
|
843
|
+
* Does NOT accept the legacy `.anon` TLD (see {@link assertRoutableHsHostname}).
|
|
844
|
+
*/
|
|
845
|
+
declare function isRoutableHsHostname(s: unknown): s is string;
|
|
846
|
+
/**
|
|
847
|
+
* Validates that `hostname` is a routable `.anyone` hidden-service address.
|
|
848
|
+
*
|
|
849
|
+
* - `<host>.anyone` → returns the hostname unchanged.
|
|
850
|
+
* - `<host>.anon` → throws with an actionable message pointing at `.anyone`
|
|
851
|
+
* (anon does NOT route `.anon`; it would silently fail in the transport).
|
|
852
|
+
* - anything else → throws a generic format error.
|
|
853
|
+
*
|
|
854
|
+
* @throws {Error} if the hostname is not a routable `.anyone` HS address.
|
|
855
|
+
*/
|
|
856
|
+
declare function assertRoutableHsHostname(hostname: unknown): string;
|
|
857
|
+
|
|
346
858
|
/**
|
|
347
859
|
* Base error class for all TOON client errors.
|
|
348
860
|
*/
|
|
@@ -679,6 +1191,8 @@ interface BtpRuntimeClientConfig {
|
|
|
679
1191
|
maxRetries?: number;
|
|
680
1192
|
/** Delay between reconnection attempts in ms (default: 1000) */
|
|
681
1193
|
retryDelay?: number;
|
|
1194
|
+
/** Custom WebSocket constructor (for SOCKS5 proxy support). */
|
|
1195
|
+
createWebSocket?: (url: string) => WebSocket;
|
|
682
1196
|
}
|
|
683
1197
|
/**
|
|
684
1198
|
* BTP transport implementing IlpClient.
|
|
@@ -722,6 +1236,14 @@ declare class BtpRuntimeClient implements IlpClient {
|
|
|
722
1236
|
data: string;
|
|
723
1237
|
timeout?: number;
|
|
724
1238
|
}, claim: Record<string, unknown>): Promise<IlpSendResult>;
|
|
1239
|
+
/**
|
|
1240
|
+
* Send a standalone `payment-channel-claim` BTP MESSAGE (no ILP packet
|
|
1241
|
+
* attached). The connector's ClaimReceiver consumes this fire-and-forget
|
|
1242
|
+
* to register cumulative claim state independently of the per-packet
|
|
1243
|
+
* forwarding path. Auto-reconnects on connection errors.
|
|
1244
|
+
*/
|
|
1245
|
+
sendClaimMessage(claim: Record<string, unknown>): Promise<void>;
|
|
1246
|
+
private _sendClaimMessageOnce;
|
|
725
1247
|
/**
|
|
726
1248
|
* Single-attempt ILP packet send. Reconnects if not connected.
|
|
727
1249
|
*/
|
|
@@ -732,6 +1254,216 @@ declare class BtpRuntimeClient implements IlpClient {
|
|
|
732
1254
|
private _sendIlpPacketWithClaimOnce;
|
|
733
1255
|
}
|
|
734
1256
|
|
|
1257
|
+
/**
|
|
1258
|
+
* ILP-over-HTTP (RFC-0035) transport for the TOON client.
|
|
1259
|
+
*
|
|
1260
|
+
* The connector now serves ILP-over-HTTP on the SAME port as BTP (connector
|
|
1261
|
+
* PR #181). This adapter lets a client do stateless one-shot writes over HTTP
|
|
1262
|
+
* (`POST /ilp`) and upgrade to a duplex BTP session when it needs to receive
|
|
1263
|
+
* server-initiated packets or act as a peer.
|
|
1264
|
+
*
|
|
1265
|
+
* Wire contract (targets connector PR #181's `/ilp`):
|
|
1266
|
+
* - One-shot write: `POST /ilp`
|
|
1267
|
+
* body: OER-encoded ILP PREPARE (`application/octet-stream`)
|
|
1268
|
+
* header: `ILP-Payment-Channel-Claim: base64(JSON of the claim)` — the
|
|
1269
|
+
* SAME claim JSON the BTP path attaches as the
|
|
1270
|
+
* `payment-channel-claim` protocolData entry.
|
|
1271
|
+
* optional: `ILP-Peer-Id` + `Authorization: Bearer <secret>` identity.
|
|
1272
|
+
* response: `200 OK` with an OER FULFILL or REJECT body. HTTP non-2xx is
|
|
1273
|
+
* reserved for TRANSPORT errors (400/401/413/5xx); ILP-level
|
|
1274
|
+
* rejects come back as a 200 + REJECT body.
|
|
1275
|
+
* - Upgrade to BTP: standard HTTP `Upgrade` with `Sec-WebSocket-Protocol: btp`
|
|
1276
|
+
* plus the same `ILP-Peer-Id` + `Authorization` headers. The connector
|
|
1277
|
+
* pre-authenticates the BTP session from those headers (continuity), so
|
|
1278
|
+
* after `101` we send BTP frames WITHOUT a separate in-band auth frame.
|
|
1279
|
+
* Omitting the auth headers falls back to the normal BTP auth-frame flow.
|
|
1280
|
+
*
|
|
1281
|
+
* Reuses `serializeIlpPrepare`/`deserializeIlpPacket` from `btp/protocol.ts` —
|
|
1282
|
+
* the SAME OER codec the BTP path uses. Claim signing/construction is owned by
|
|
1283
|
+
* the caller (BootstrapService); this transport never builds or signs claims.
|
|
1284
|
+
*/
|
|
1285
|
+
|
|
1286
|
+
/** Header carrying the base64(JSON) payment-channel claim. */
|
|
1287
|
+
declare const ILP_CLAIM_HEADER = "ILP-Payment-Channel-Claim";
|
|
1288
|
+
/** Header carrying a NIP-59 wrapped (gift-wrapped) claim. */
|
|
1289
|
+
declare const ILP_CLAIM_WRAPPED_HEADER = "ILP-Payment-Channel-Claim-Wrapped";
|
|
1290
|
+
/** Header carrying the peer identity. */
|
|
1291
|
+
declare const ILP_PEER_ID_HEADER = "ILP-Peer-Id";
|
|
1292
|
+
interface HttpIlpClientConfig {
|
|
1293
|
+
/** The peer's `POST /ilp` URL (the `httpEndpoint` from discovery). */
|
|
1294
|
+
httpEndpoint: string;
|
|
1295
|
+
/**
|
|
1296
|
+
* Optional peer identity. With no `peerId`/`authToken` the connector treats
|
|
1297
|
+
* the request as an anonymous no-auth peer (permissionless default) and
|
|
1298
|
+
* derives an ephemeral id from the claim signer.
|
|
1299
|
+
*/
|
|
1300
|
+
peerId?: string;
|
|
1301
|
+
/** Bearer secret for `Authorization`. Omit for the no-auth peer path. */
|
|
1302
|
+
authToken?: string;
|
|
1303
|
+
/** Request timeout in milliseconds (default: 30000). */
|
|
1304
|
+
timeout?: number;
|
|
1305
|
+
/** Max retry attempts for transport-level network failures (default: 3). */
|
|
1306
|
+
maxRetries?: number;
|
|
1307
|
+
/** Initial retry delay in milliseconds (default: 1000). */
|
|
1308
|
+
retryDelay?: number;
|
|
1309
|
+
/** Custom fetch implementation (SOCKS5 mode / testing). */
|
|
1310
|
+
httpClient?: typeof fetch;
|
|
1311
|
+
/**
|
|
1312
|
+
* Custom WebSocket constructor for the BTP upgrade path (SOCKS5 mode).
|
|
1313
|
+
* Forwarded to the underlying BtpRuntimeClient.
|
|
1314
|
+
*/
|
|
1315
|
+
createWebSocket?: (url: string) => WebSocket;
|
|
1316
|
+
}
|
|
1317
|
+
/**
|
|
1318
|
+
* Stateless ILP-over-HTTP transport implementing `IlpClient`.
|
|
1319
|
+
*
|
|
1320
|
+
* Use this for pure one-shot consumers (publish-and-forget writes). When the
|
|
1321
|
+
* client needs a duplex session — to receive server-initiated packets or to act
|
|
1322
|
+
* as a peer — call {@link upgradeToBtp} to obtain a connected BtpRuntimeClient
|
|
1323
|
+
* that reuses the existing BTP code path.
|
|
1324
|
+
*/
|
|
1325
|
+
declare class HttpIlpClient implements IlpClient {
|
|
1326
|
+
private readonly httpEndpoint;
|
|
1327
|
+
private readonly peerId;
|
|
1328
|
+
private readonly authToken;
|
|
1329
|
+
private readonly timeout;
|
|
1330
|
+
private readonly retryConfig;
|
|
1331
|
+
private readonly httpClient;
|
|
1332
|
+
private readonly createWebSocket;
|
|
1333
|
+
constructor(config: HttpIlpClientConfig);
|
|
1334
|
+
/**
|
|
1335
|
+
* Send an ILP PREPARE via `POST /ilp` WITHOUT a claim. The connector accepts
|
|
1336
|
+
* this only on free/zero-amount routes; paid writes must use
|
|
1337
|
+
* {@link sendIlpPacketWithClaim}. Satisfies the IlpClient interface.
|
|
1338
|
+
*/
|
|
1339
|
+
sendIlpPacket(params: {
|
|
1340
|
+
destination: string;
|
|
1341
|
+
amount: string;
|
|
1342
|
+
data: string;
|
|
1343
|
+
timeout?: number;
|
|
1344
|
+
}): Promise<IlpSendResult>;
|
|
1345
|
+
/**
|
|
1346
|
+
* Send an ILP PREPARE via `POST /ilp` with the payment-channel claim attached
|
|
1347
|
+
* as the `ILP-Payment-Channel-Claim` header. `claim` is the SAME JSON object
|
|
1348
|
+
* the BTP path attaches as the `payment-channel-claim` protocolData entry —
|
|
1349
|
+
* we base64(JSON.stringify(claim)) it, byte-for-byte identical to BTP.
|
|
1350
|
+
*/
|
|
1351
|
+
sendIlpPacketWithClaim(params: {
|
|
1352
|
+
destination: string;
|
|
1353
|
+
amount: string;
|
|
1354
|
+
data: string;
|
|
1355
|
+
timeout?: number;
|
|
1356
|
+
}, claim: unknown): Promise<IlpSendResult>;
|
|
1357
|
+
/**
|
|
1358
|
+
* Upgrade to a duplex BTP session over the SAME endpoint.
|
|
1359
|
+
*
|
|
1360
|
+
* Derives the `ws(s)://` URL from `httpEndpoint`, opens a WebSocket with
|
|
1361
|
+
* `Sec-WebSocket-Protocol: btp` and the same `ILP-Peer-Id` + `Authorization`
|
|
1362
|
+
* headers, and returns a connected {@link BtpRuntimeClient}. When auth headers
|
|
1363
|
+
* are present the connector pre-authenticates the session (no in-band auth
|
|
1364
|
+
* frame); without them the BtpRuntimeClient falls back to the normal BTP
|
|
1365
|
+
* auth-frame flow.
|
|
1366
|
+
*
|
|
1367
|
+
* NOTE: passing per-connection headers + a subprotocol to a WebSocket is
|
|
1368
|
+
* Node-only (the `ws` package). Browsers cannot set arbitrary request headers
|
|
1369
|
+
* on a WebSocket handshake, so a browser consumer must use the gateway
|
|
1370
|
+
* transport or BTP-with-auth-frame instead.
|
|
1371
|
+
*/
|
|
1372
|
+
upgradeToBtp(): Promise<BtpRuntimeClient>;
|
|
1373
|
+
private authHeaders;
|
|
1374
|
+
/**
|
|
1375
|
+
* Single attempt: serialize the PREPARE, POST it, and map the response.
|
|
1376
|
+
* @throws {NetworkError} On connection/timeout failures (retried).
|
|
1377
|
+
* @throws {ConnectorError} On non-retryable transport errors (5xx / unexpected).
|
|
1378
|
+
*/
|
|
1379
|
+
private postPrepare;
|
|
1380
|
+
/**
|
|
1381
|
+
* Map a `200 OK` body (OER FULFILL/REJECT) to an IlpSendResult; map a non-2xx
|
|
1382
|
+
* to a transport error. Per the wire contract, ILP-level rejects arrive as a
|
|
1383
|
+
* 200 + REJECT body — only HTTP non-2xx means a transport-layer failure.
|
|
1384
|
+
*/
|
|
1385
|
+
private mapResponse;
|
|
1386
|
+
private mapTransportError;
|
|
1387
|
+
}
|
|
1388
|
+
/**
|
|
1389
|
+
* Derive the BTP WebSocket URL from a `POST /ilp` HTTP endpoint. The connector
|
|
1390
|
+
* serves BTP on the SAME path, so we only swap the scheme (http→ws, https→wss).
|
|
1391
|
+
*/
|
|
1392
|
+
declare function httpEndpointToBtpUrl(httpEndpoint: string): string;
|
|
1393
|
+
|
|
1394
|
+
/**
|
|
1395
|
+
* Transport selection policy for the client ILP layer.
|
|
1396
|
+
*
|
|
1397
|
+
* The connector serves ILP-over-HTTP (`POST /ilp`) and BTP on the SAME port
|
|
1398
|
+
* (connector PR #181). A peer advertises this in discovery via the toon-core
|
|
1399
|
+
* `IlpPeerInfo` fields added in toon PR #29:
|
|
1400
|
+
* - `httpEndpoint?: string` — the `POST /ilp` URL.
|
|
1401
|
+
* - `supportsUpgrade?: boolean` — whether the host accepts the BTP upgrade.
|
|
1402
|
+
*
|
|
1403
|
+
* Those fields may not yet exist on the installed `@toon-protocol/core`
|
|
1404
|
+
* `IlpPeerInfo` type, so we read them defensively here (see `DiscoveredIlpPeer`).
|
|
1405
|
+
*
|
|
1406
|
+
* Policy:
|
|
1407
|
+
* - Pure one-shot consumers (`needsDuplex: false`) prefer HTTP when the peer
|
|
1408
|
+
* advertises an `httpEndpoint` — stateless, no persistent socket.
|
|
1409
|
+
* - Clients that must receive server-initiated packets or act as a peer
|
|
1410
|
+
* (`needsDuplex: true`) use BTP. If the peer only exposes `httpEndpoint`
|
|
1411
|
+
* and `supportsUpgrade` is true, we go HTTP-then-upgrade; otherwise we
|
|
1412
|
+
* connect to the BTP endpoint directly.
|
|
1413
|
+
*/
|
|
1414
|
+
/**
|
|
1415
|
+
* The subset of discovery fields this policy reads. Structurally compatible with
|
|
1416
|
+
* core's `IlpPeerInfo`; `httpEndpoint`/`supportsUpgrade` are optional so a
|
|
1417
|
+
* pre-PR-#29 `IlpPeerInfo` can be passed through a cast.
|
|
1418
|
+
*/
|
|
1419
|
+
interface DiscoveredIlpPeer {
|
|
1420
|
+
/** BTP WebSocket endpoint (always present on a TOON peer). */
|
|
1421
|
+
btpEndpoint?: string;
|
|
1422
|
+
/** `POST /ilp` URL (toon PR #29). */
|
|
1423
|
+
httpEndpoint?: string;
|
|
1424
|
+
/** Whether the host accepts the BTP upgrade over the HTTP endpoint (toon PR #29). */
|
|
1425
|
+
supportsUpgrade?: boolean;
|
|
1426
|
+
}
|
|
1427
|
+
type IlpTransportChoice =
|
|
1428
|
+
/** Stateless one-shot writes via `POST /ilp`. */
|
|
1429
|
+
{
|
|
1430
|
+
kind: 'http';
|
|
1431
|
+
httpEndpoint: string;
|
|
1432
|
+
canUpgrade: boolean;
|
|
1433
|
+
}
|
|
1434
|
+
/** Duplex BTP session via the WebSocket endpoint. */
|
|
1435
|
+
| {
|
|
1436
|
+
kind: 'btp';
|
|
1437
|
+
btpEndpoint: string;
|
|
1438
|
+
}
|
|
1439
|
+
/**
|
|
1440
|
+
* Open HTTP first (one-shot writes) but upgrade to BTP when duplex is needed.
|
|
1441
|
+
* Only chosen when the peer exposes `httpEndpoint` + `supportsUpgrade` and no
|
|
1442
|
+
* separate `btpEndpoint`.
|
|
1443
|
+
*/
|
|
1444
|
+
| {
|
|
1445
|
+
kind: 'http-upgradable';
|
|
1446
|
+
httpEndpoint: string;
|
|
1447
|
+
};
|
|
1448
|
+
interface SelectIlpTransportOptions {
|
|
1449
|
+
/**
|
|
1450
|
+
* Whether the client needs a duplex session (receive server-initiated
|
|
1451
|
+
* packets / act as a peer). Default: false (pure one-shot consumer).
|
|
1452
|
+
*/
|
|
1453
|
+
needsDuplex?: boolean;
|
|
1454
|
+
}
|
|
1455
|
+
/**
|
|
1456
|
+
* Read discovery fields defensively from a (possibly pre-PR-#29) peer info
|
|
1457
|
+
* object. Accepts core's `IlpPeerInfo` or any structurally-compatible shape.
|
|
1458
|
+
*/
|
|
1459
|
+
declare function readDiscoveredIlpPeer(peer: unknown): DiscoveredIlpPeer;
|
|
1460
|
+
/**
|
|
1461
|
+
* Choose the ILP transport for a discovered peer given the consumer's needs.
|
|
1462
|
+
*
|
|
1463
|
+
* @throws {Error} If the peer advertises no usable endpoint at all.
|
|
1464
|
+
*/
|
|
1465
|
+
declare function selectIlpTransport(peer: DiscoveredIlpPeer, options?: SelectIlpTransportOptions): IlpTransportChoice;
|
|
1466
|
+
|
|
735
1467
|
/**
|
|
736
1468
|
* Chain-specific metadata (discriminated union).
|
|
737
1469
|
*/
|
|
@@ -761,36 +1493,92 @@ interface ChainSigner {
|
|
|
761
1493
|
transferredAmount: bigint;
|
|
762
1494
|
lockedAmount: bigint;
|
|
763
1495
|
locksRoot: string;
|
|
1496
|
+
/**
|
|
1497
|
+
* Counterparty settlement address the proof is bound to. Required for
|
|
1498
|
+
* Solana/Mina (folded into the canonical balance-proof message); the EVM
|
|
1499
|
+
* adapter ignores it (EIP-712 has no recipient term).
|
|
1500
|
+
*/
|
|
1501
|
+
recipient: string;
|
|
764
1502
|
metadata: ChainMetadata;
|
|
1503
|
+
/**
|
|
1504
|
+
* On-chain channel `depositTotal` (base units). When supplied (>0), a Mina
|
|
1505
|
+
* signer binds the conserved `balanceB = depositTotal − balanceA` commitment
|
|
1506
|
+
* required to settle on a funded zkApp (connector#133); EVM/Solana signers
|
|
1507
|
+
* ignore it. When omitted, a Mina signer self-resolves it from chain if it
|
|
1508
|
+
* was configured with a GraphQL URL (#223), else falls back to the legacy
|
|
1509
|
+
* `balanceB = 0` form.
|
|
1510
|
+
*/
|
|
1511
|
+
depositTotal?: bigint;
|
|
765
1512
|
}): Promise<SignedBalanceProof>;
|
|
766
1513
|
buildClaimMessage(proof: SignedBalanceProof, senderId: string): ClaimMessage;
|
|
767
1514
|
}
|
|
768
1515
|
type ClaimMessage = EVMClaimMessage | SolanaClaimMessage | MinaClaimMessage;
|
|
1516
|
+
/**
|
|
1517
|
+
* Solana payment-channel claim — wire-compatible with the connector's
|
|
1518
|
+
* `SolanaClaimMessage` (`@toon-protocol/connector` `btp/btp-claim-types.ts`).
|
|
1519
|
+
* Field names match the connector's `validateSolanaClaim` exactly:
|
|
1520
|
+
* `channelAccount` (base58 PDA), `signerPublicKey` (base58), base64 `signature`.
|
|
1521
|
+
*/
|
|
769
1522
|
interface SolanaClaimMessage {
|
|
770
1523
|
version: '1.0';
|
|
771
1524
|
blockchain: 'solana';
|
|
772
1525
|
messageId: string;
|
|
773
1526
|
timestamp: string;
|
|
774
1527
|
senderId: string;
|
|
775
|
-
|
|
1528
|
+
/** On-chain PDA account address for the payment channel (base58). */
|
|
1529
|
+
channelAccount: string;
|
|
776
1530
|
nonce: number;
|
|
1531
|
+
/** Cumulative transferred amount (string for bigint precision). */
|
|
777
1532
|
transferredAmount: string;
|
|
1533
|
+
/** Ed25519 signature over the 48-byte balance-proof message (base64). */
|
|
778
1534
|
signature: string;
|
|
779
|
-
|
|
1535
|
+
/** Base58-encoded Ed25519 public key of the signer. */
|
|
1536
|
+
signerPublicKey: string;
|
|
1537
|
+
/** Solana program id for the payment-channel program (base58). */
|
|
780
1538
|
programId: string;
|
|
781
1539
|
}
|
|
1540
|
+
/**
|
|
1541
|
+
* Mina payment-channel claim — wire-compatible with the connector's
|
|
1542
|
+
* `MinaClaimMessage` (`@toon-protocol/connector` `btp/btp-claim-types.ts`).
|
|
1543
|
+
* Field names + types match `validateMinaClaim` exactly: `zkAppAddress`
|
|
1544
|
+
* (B62-prefixed 55-char base58, the channel id), `tokenId`, `balanceCommitment`
|
|
1545
|
+
* (`Poseidon([balA,balB,salt])` decimal string), integer `nonce`, base64 `proof`,
|
|
1546
|
+
* and `salt`. `transferredAmount`/`balanceB`/`signatureB`/`network` are OPTIONAL
|
|
1547
|
+
* at validation; the apex-as-recipient single-direction claim sends party-A only.
|
|
1548
|
+
*/
|
|
782
1549
|
interface MinaClaimMessage {
|
|
783
1550
|
version: '1.0';
|
|
784
1551
|
blockchain: 'mina';
|
|
785
1552
|
messageId: string;
|
|
786
1553
|
timestamp: string;
|
|
787
1554
|
senderId: string;
|
|
788
|
-
|
|
789
|
-
nonce: number;
|
|
790
|
-
transferredAmount: string;
|
|
791
|
-
commitment: string;
|
|
792
|
-
signerAddress: string;
|
|
1555
|
+
/** Deployed payment-channel zkApp address (B62 base58) — the channel id. */
|
|
793
1556
|
zkAppAddress: string;
|
|
1557
|
+
/** Mina token id (default `'MINA'`). */
|
|
1558
|
+
tokenId: string;
|
|
1559
|
+
/** `Poseidon([balanceA, balanceB, salt]).toString()`. */
|
|
1560
|
+
balanceCommitment: string;
|
|
1561
|
+
nonce: number;
|
|
1562
|
+
/** base64-encoded JSON `{ commitment, signature: { r, s }, nonce, signerPublicKey }`. */
|
|
1563
|
+
proof: string;
|
|
1564
|
+
/** Commitment salt (decimal string). */
|
|
1565
|
+
salt: string;
|
|
1566
|
+
/** Cumulative transferred amount (optional; string for bigint precision). */
|
|
1567
|
+
transferredAmount?: string;
|
|
1568
|
+
/**
|
|
1569
|
+
* Signer's Mina public key (B62 base58) — the claiming participant.
|
|
1570
|
+
*
|
|
1571
|
+
* Surfaced top-level (in addition to being embedded in `proof`) so the
|
|
1572
|
+
* connector's `SettlementExecutor` can resolve participant keys for the
|
|
1573
|
+
* on-chain `claimFromChannel` on an externally-opened (inbound) channel. The
|
|
1574
|
+
* connector reads `latestClaim.signerPublicKey` directly (not the proof blob);
|
|
1575
|
+
* without it the Mina SDK's `claimFromChannel` throws `ACCOUNT_NOT_FOUND`
|
|
1576
|
+
* ("Participant keys not found in cache and none were supplied"). The
|
|
1577
|
+
* connector accepts this as an optional `MinaClaimMessage` field.
|
|
1578
|
+
*/
|
|
1579
|
+
signerPublicKey?: string;
|
|
1580
|
+
/** Mina network id — defaults to `devnet` connector-side when omitted. */
|
|
1581
|
+
network?: 'mainnet' | 'devnet' | 'berkeley' | 'lightnet';
|
|
794
1582
|
}
|
|
795
1583
|
|
|
796
1584
|
/**
|
|
@@ -862,17 +1650,33 @@ declare class EvmSigner {
|
|
|
862
1650
|
}
|
|
863
1651
|
|
|
864
1652
|
/**
|
|
865
|
-
* Solana signer for
|
|
1653
|
+
* Solana signer for the connector payment-channel claim path.
|
|
866
1654
|
*
|
|
867
|
-
* Signs
|
|
868
|
-
*
|
|
1655
|
+
* Signs the connector's on-chain payment-channel balance-proof message — the
|
|
1656
|
+
* raw 48-byte `channel_pda(32) || nonce(8 LE) || transferredAmount(8 LE)` (see
|
|
1657
|
+
* `@toon-protocol/connector` `SolanaPaymentChannelSDK._buildBalanceProofMessage`
|
|
1658
|
+
* + `solana-payment-channel-provider.verifyBalanceProof`). The produced 64-byte
|
|
1659
|
+
* Ed25519 signature verifies on the connector's `verifySolanaClaim` path, which
|
|
1660
|
+
* is what makes a client-issued Solana payment-channel claim (paying the apex
|
|
1661
|
+
* to write) acceptable on connector 3.9.0.
|
|
1662
|
+
*
|
|
1663
|
+
* NOTE: this is a DIFFERENT message from the Mill ↔ sender swap-claim wire
|
|
1664
|
+
* contract (`balanceProofHashSolana`, SDK `verifyEd25519Signature`). The client
|
|
1665
|
+
* here is paying a payment-channel claim to the apex, not issuing a swap claim,
|
|
1666
|
+
* so it must sign the connector's on-chain payment-channel message. `channelId`
|
|
1667
|
+
* MUST be the base58 channel PDA (produced by `OnChainChannelClient.openChannel`).
|
|
869
1668
|
*/
|
|
870
1669
|
declare class SolanaSigner implements ChainSigner {
|
|
871
1670
|
readonly chainType: "solana";
|
|
1671
|
+
/** 32-byte Ed25519 seed. */
|
|
872
1672
|
private readonly privateKey;
|
|
873
|
-
private publicKey?;
|
|
874
1673
|
private pubkeyBase58Cache?;
|
|
875
|
-
|
|
1674
|
+
/**
|
|
1675
|
+
* @param privateKey - 32-byte Ed25519 seed (e.g. `identity.solana.secretKey.slice(0, 32)`).
|
|
1676
|
+
* @param publicKeyBase58 - Optional base58 public key (e.g. `identity.solana.publicKey`).
|
|
1677
|
+
* When omitted it is derived lazily from `privateKey`.
|
|
1678
|
+
*/
|
|
1679
|
+
constructor(privateKey: Uint8Array, publicKeyBase58?: string);
|
|
876
1680
|
private ensurePublicKey;
|
|
877
1681
|
get signerIdentifier(): string;
|
|
878
1682
|
signBalanceProof(params: {
|
|
@@ -881,44 +1685,170 @@ declare class SolanaSigner implements ChainSigner {
|
|
|
881
1685
|
transferredAmount: bigint;
|
|
882
1686
|
lockedAmount: bigint;
|
|
883
1687
|
locksRoot: string;
|
|
1688
|
+
recipient: string;
|
|
884
1689
|
metadata: ChainMetadata;
|
|
885
1690
|
}): Promise<SignedBalanceProof>;
|
|
886
1691
|
buildClaimMessage(proof: SignedBalanceProof, senderId: string): ClaimMessage;
|
|
887
1692
|
}
|
|
888
1693
|
|
|
1694
|
+
/** Reads a channel zkApp's on-chain `depositTotal` (base units). */
|
|
1695
|
+
type MinaDepositReader = (zkAppAddress: string) => Promise<bigint>;
|
|
1696
|
+
/** Optional `MinaSigner` wiring for on-chain `depositTotal` resolution. */
|
|
1697
|
+
interface MinaSignerOptions {
|
|
1698
|
+
/**
|
|
1699
|
+
* Mina GraphQL URL used to read the channel's on-chain `depositTotal` when a
|
|
1700
|
+
* caller doesn't supply it to `signBalanceProof`. Enables conserved
|
|
1701
|
+
* `balanceB = depositTotal − balanceA` claims (settleable on funded zkApps).
|
|
1702
|
+
*/
|
|
1703
|
+
graphqlUrl?: string;
|
|
1704
|
+
/** Inject a deposit reader (tests / custom transport). Overrides `graphqlUrl`. */
|
|
1705
|
+
depositReader?: MinaDepositReader;
|
|
1706
|
+
}
|
|
889
1707
|
/**
|
|
890
|
-
* Mina signer for
|
|
1708
|
+
* Mina (Pallas) signer for the connector payment-channel claim path.
|
|
1709
|
+
*
|
|
1710
|
+
* Produces the connector 3.9.0 `MinaClaimMessage` contract — `{ zkAppAddress,
|
|
1711
|
+
* tokenId, balanceCommitment, proof (base64), salt, nonce }` — by reproducing
|
|
1712
|
+
* `MinaPaymentChannelSDK.signBalanceProof` exactly (via
|
|
1713
|
+
* {@link buildMinaPaymentChannelProof}):
|
|
1714
|
+
*
|
|
1715
|
+
* commitment = Poseidon([Field(balanceA), Field(0), Field(salt)])
|
|
1716
|
+
* channelHashField = Poseidon([participantA.x, participantB.x, 0]) (see below)
|
|
1717
|
+
* proof = base64(JSON{ commitment, signature: { r, s }, nonce, signerPublicKey })
|
|
891
1718
|
*
|
|
892
|
-
*
|
|
893
|
-
*
|
|
1719
|
+
* with the Schnorr signature computed over `[commitment, Field(nonce),
|
|
1720
|
+
* channelHashField]` using the Mina `'devnet'` network id (matching o1js's
|
|
1721
|
+
* hardcoded `Signature.create` prefix). Verified field-by-field against the
|
|
1722
|
+
* connector's o1js `Signature.fromJSON({r,s}).verify` (see the package tests).
|
|
1723
|
+
*
|
|
1724
|
+
* `channelHashField` is the ON-CHAIN participant form
|
|
1725
|
+
* (`Poseidon([client.x, apex.x, 0])`, participantA=client, participantB=apex)
|
|
1726
|
+
* whenever the apex's Mina pubkey is known (the negotiated `recipient`), so the
|
|
1727
|
+
* claim can SETTLE on-chain via the zkApp's `claimFromChannel` (which only
|
|
1728
|
+
* verifies the participant form). When the apex pubkey is unavailable the signer
|
|
1729
|
+
* falls back to the legacy zkApp-x form (`Poseidon([zkApp.x])`); the connector's
|
|
1730
|
+
* off-chain `verifyBalanceProof` accepts EITHER, so off-chain store/FULFILL works
|
|
1731
|
+
* in both cases — only on-chain settle requires the participant form.
|
|
1732
|
+
*
|
|
1733
|
+
* NOTE: this is a DIFFERENT message + format from the Mill ↔ sender swap-claim
|
|
1734
|
+
* wire contract (`balanceProofFieldsMina` in `@toon-protocol/core`, verified by
|
|
1735
|
+
* the SDK's `verifyMinaSignature`). The client here pays a payment-channel claim
|
|
1736
|
+
* to the apex, so it signs the connector's on-chain payment-channel scheme; the
|
|
1737
|
+
* swap-format hash is left untouched (mirrors the Solana #105 separation).
|
|
1738
|
+
*
|
|
1739
|
+
* `channelId` MUST be the deployed payment-channel zkApp B62 address (the same
|
|
1740
|
+
* address the apex's Mina provider resolves on-chain via `getChannelState`),
|
|
1741
|
+
* which is what `OnChainChannelClient.openMinaChannel` returns.
|
|
1742
|
+
*
|
|
1743
|
+
* `mina-signer` is an OPTIONAL dependency: its crypto (Poseidon, Pallas Schnorr,
|
|
1744
|
+
* the base58 signature codec) is loaded dynamically so the client builds and runs
|
|
1745
|
+
* for non-Mina users without it installed, and WITHOUT pulling the o1js WASM
|
|
1746
|
+
* circuit runtime.
|
|
894
1747
|
*/
|
|
895
1748
|
declare class MinaSigner implements ChainSigner {
|
|
896
1749
|
readonly chainType: "mina";
|
|
897
|
-
private
|
|
898
|
-
private
|
|
899
|
-
|
|
1750
|
+
/** Big-endian hex scalar (or already-`EK…` base58) Mina private key. */
|
|
1751
|
+
private readonly privateKey;
|
|
1752
|
+
private publicKeyBase58?;
|
|
1753
|
+
private readonly depositReader?;
|
|
1754
|
+
/** Per-zkApp `depositTotal` cache (deposits are rare; the connector re-reads). */
|
|
1755
|
+
private readonly depositCache;
|
|
1756
|
+
/**
|
|
1757
|
+
* @param privateKey - Mina private key as big-endian hex scalar (the form
|
|
1758
|
+
* `deriveFullIdentity()` emits, `identity.mina.privateKey`) or an `EK…`
|
|
1759
|
+
* base58 key. Converted to the base58check form mina-signer requires.
|
|
1760
|
+
* @param publicKeyBase58 - Optional base58 public key (e.g.
|
|
1761
|
+
* `identity.mina.publicKey`). When omitted it is derived during signing.
|
|
1762
|
+
* @param options - Optional on-chain `depositTotal` resolution (graphqlUrl or
|
|
1763
|
+
* an injected reader) so claims conserve balances on funded zkApps.
|
|
1764
|
+
*/
|
|
1765
|
+
constructor(privateKey: string, publicKeyBase58?: string, options?: MinaSignerOptions);
|
|
1766
|
+
/**
|
|
1767
|
+
* Resolve the channel's on-chain `depositTotal`, caching per zkApp. Returns
|
|
1768
|
+
* `undefined` when no reader is configured or the read fails — callers then
|
|
1769
|
+
* fall back to the legacy `balanceB = 0` commitment.
|
|
1770
|
+
*/
|
|
1771
|
+
private resolveDepositTotal;
|
|
900
1772
|
get signerIdentifier(): string;
|
|
901
|
-
private
|
|
1773
|
+
/** Derive this signer's B62 public key from its (base58) private key. */
|
|
1774
|
+
private deriveOwnPublicKey;
|
|
902
1775
|
signBalanceProof(params: {
|
|
903
1776
|
channelId: string;
|
|
904
1777
|
nonce: number;
|
|
905
1778
|
transferredAmount: bigint;
|
|
906
1779
|
lockedAmount: bigint;
|
|
907
1780
|
locksRoot: string;
|
|
1781
|
+
recipient: string;
|
|
908
1782
|
metadata: ChainMetadata;
|
|
1783
|
+
/**
|
|
1784
|
+
* On-chain channel `depositTotal`. When provided (>0), the signed commitment
|
|
1785
|
+
* binds `balanceB = depositTotal − balanceA` (the funder's remaining
|
|
1786
|
+
* balance), matching the connector's claimFromChannel reconstruction
|
|
1787
|
+
* (toon-protocol/connector#133) and the on-chain circuit's
|
|
1788
|
+
* `balanceA + balanceB == depositTotal` invariant. Omitted/0 keeps the
|
|
1789
|
+
* legacy `balanceB = 0` form (off-chain-store-only, non-settleable).
|
|
1790
|
+
*/
|
|
1791
|
+
depositTotal?: bigint;
|
|
909
1792
|
}): Promise<SignedBalanceProof>;
|
|
910
1793
|
buildClaimMessage(proof: SignedBalanceProof, senderId: string): ClaimMessage;
|
|
911
1794
|
}
|
|
912
1795
|
|
|
913
1796
|
interface SolanaChannelConfig {
|
|
914
1797
|
rpcUrl: string;
|
|
1798
|
+
/**
|
|
1799
|
+
* Ed25519 keypair material. Accepts either a 32-byte seed or a 64-byte
|
|
1800
|
+
* `secretKey` (seed || pubkey, as produced by `deriveFullIdentity`). The first
|
|
1801
|
+
* 32 bytes are the signing seed; the public key is derived from it.
|
|
1802
|
+
*/
|
|
915
1803
|
keypair: Uint8Array;
|
|
916
1804
|
programId: string;
|
|
1805
|
+
/**
|
|
1806
|
+
* SPL token mint (base58) for PDA derivation. Optional — the per-channel
|
|
1807
|
+
* negotiated token (`OpenChannelParams.token`) takes precedence when present.
|
|
1808
|
+
*/
|
|
1809
|
+
tokenMint?: string;
|
|
1810
|
+
/**
|
|
1811
|
+
* Challenge-period duration in seconds for `initialize_channel`. Defaults to
|
|
1812
|
+
* `OpenChannelParams.settlementTimeout` or 86400.
|
|
1813
|
+
*/
|
|
1814
|
+
challengeDuration?: number;
|
|
1815
|
+
/**
|
|
1816
|
+
* Optional deposit amount (base units, string) + the payer's funded SPL token
|
|
1817
|
+
* account (ATA, base58). When omitted, the channel is opened (initialized)
|
|
1818
|
+
* without an on-chain deposit — the connector accepts the claim on channel
|
|
1819
|
+
* `opened` status + participant membership; deposit is only consumed at
|
|
1820
|
+
* on-chain claim/settle time.
|
|
1821
|
+
*/
|
|
1822
|
+
deposit?: {
|
|
1823
|
+
amount: string;
|
|
1824
|
+
payerTokenAccount: string;
|
|
1825
|
+
};
|
|
917
1826
|
}
|
|
918
1827
|
interface MinaChannelConfig {
|
|
919
1828
|
graphqlUrl: string;
|
|
920
1829
|
privateKey: string;
|
|
921
1830
|
zkAppAddress: string;
|
|
1831
|
+
/**
|
|
1832
|
+
* Channel settlement timeout in slots for `initializeChannel`. Defaults to
|
|
1833
|
+
* `OpenChannelParams.settlementTimeout` or 86400.
|
|
1834
|
+
*/
|
|
1835
|
+
challengeDuration?: number;
|
|
1836
|
+
/**
|
|
1837
|
+
* Mina token id field (decimal string) for `initializeChannel`. Default '1'
|
|
1838
|
+
* (native MINA). The connector reads this only as on-chain channel metadata.
|
|
1839
|
+
*/
|
|
1840
|
+
tokenId?: string;
|
|
1841
|
+
/**
|
|
1842
|
+
* Optional on-chain deposit (base units, string) submitted after the channel
|
|
1843
|
+
* is initialized. When omitted, the channel is opened (OPEN state) without a
|
|
1844
|
+
* deposit — the connector accepts the claim on `opened` status; deposit is
|
|
1845
|
+
* only consumed at on-chain settle time.
|
|
1846
|
+
*/
|
|
1847
|
+
deposit?: {
|
|
1848
|
+
amount: string;
|
|
1849
|
+
};
|
|
1850
|
+
/** Mina network id for the account/Schnorr prefix. Default 'devnet'. */
|
|
1851
|
+
networkId?: 'devnet' | 'mainnet';
|
|
922
1852
|
}
|
|
923
1853
|
interface OnChainChannelClientConfig {
|
|
924
1854
|
evmSigner: EvmSigner;
|
|
@@ -935,10 +1865,29 @@ interface OnChainChannelClientConfig {
|
|
|
935
1865
|
declare class OnChainChannelClient implements ConnectorChannelClient {
|
|
936
1866
|
private readonly evmSigner;
|
|
937
1867
|
private readonly chainRpcUrls;
|
|
938
|
-
private
|
|
939
|
-
private
|
|
1868
|
+
private solanaConfig?;
|
|
1869
|
+
private minaConfig?;
|
|
940
1870
|
private readonly channelContext;
|
|
941
1871
|
constructor(config: OnChainChannelClientConfig);
|
|
1872
|
+
/**
|
|
1873
|
+
* Late-binds the Solana channel config.
|
|
1874
|
+
*
|
|
1875
|
+
* `ToonClient.start()` derives the Solana Ed25519 keypair from the client's
|
|
1876
|
+
* mnemonic asynchronously (after this client is constructed), so the keypair
|
|
1877
|
+
* is injected here rather than at construction. Same keypair as the
|
|
1878
|
+
* registered Solana signer — guarantees the channel-open key and the
|
|
1879
|
+
* claim-signing key match.
|
|
1880
|
+
*/
|
|
1881
|
+
setSolanaConfig(config: SolanaChannelConfig): void;
|
|
1882
|
+
/**
|
|
1883
|
+
* Late-binds the Mina channel config.
|
|
1884
|
+
*
|
|
1885
|
+
* Parallel to `setSolanaConfig`: `ToonClient.start()` derives the Mina private
|
|
1886
|
+
* key from the client's mnemonic asynchronously (after this client is
|
|
1887
|
+
* constructed), so the key is injected here rather than at construction. Same
|
|
1888
|
+
* key as the registered Mina signer.
|
|
1889
|
+
*/
|
|
1890
|
+
setMinaConfig(config: MinaChannelConfig): void;
|
|
942
1891
|
/**
|
|
943
1892
|
* Parse chain identifier to extract chainId.
|
|
944
1893
|
* Format: "evm:{network}:{chainId}" e.g., "evm:anvil:31337"
|
|
@@ -958,12 +1907,48 @@ declare class OnChainChannelClient implements ConnectorChannelClient {
|
|
|
958
1907
|
*/
|
|
959
1908
|
openChannel(params: OpenChannelParams): Promise<OpenChannelResult>;
|
|
960
1909
|
/**
|
|
961
|
-
* Opens a Solana payment channel
|
|
1910
|
+
* Opens a REAL on-chain Solana payment channel.
|
|
1911
|
+
*
|
|
1912
|
+
* Derives the connector-parity channel PDA
|
|
1913
|
+
* (`[b"channel", min_pubkey, max_pubkey, token_mint]`), submits the
|
|
1914
|
+
* `initialize_channel` instruction (+ optional `deposit`) to the deployed
|
|
1915
|
+
* payment-channel program, and returns the base58 PDA as the channel id. That
|
|
1916
|
+
* PDA is what the claim carries as `channelAccount`, and the on-chain channel
|
|
1917
|
+
* is what the connector's `verifySolanaClaim` reads via
|
|
1918
|
+
* `provider.getChannelState` before accepting the claim.
|
|
1919
|
+
*
|
|
1920
|
+
* Mirrors `openEvmChannel`'s open(+deposit) structure. Idempotent: if the
|
|
1921
|
+
* channel account already exists on-chain, returns its PDA without
|
|
1922
|
+
* re-initializing.
|
|
962
1923
|
*/
|
|
963
1924
|
private openSolanaChannel;
|
|
964
1925
|
/**
|
|
965
|
-
* Opens a Mina payment channel
|
|
966
|
-
*
|
|
1926
|
+
* Opens a REAL on-chain Mina payment channel on the deployed `PaymentChannel`
|
|
1927
|
+
* zkApp.
|
|
1928
|
+
*
|
|
1929
|
+
* The zkApp is deployed out-of-band (the operator/e2e harness deploys it
|
|
1930
|
+
* deterministically and advertises its B62 address). This client then calls
|
|
1931
|
+
* `initializeChannel` on that zkApp so its on-chain `channelState` becomes
|
|
1932
|
+
* `OPEN` — which is what the connector's `MinaPaymentChannelSDK.getChannelState`
|
|
1933
|
+
* reads to return status `'opened'` (claim verification otherwise fails with
|
|
1934
|
+
* `mina_claim_verification_failed`). The deployed zkApp address IS the channel
|
|
1935
|
+
* id: `MinaClaimMessage.zkAppAddress` is both the claim's channel identifier
|
|
1936
|
+
* AND the channel-hash preimage the off-chain proof binds to (see
|
|
1937
|
+
* `mina-payment-channel.ts`), so the channel-open id and the claim's channel id
|
|
1938
|
+
* are guaranteed identical.
|
|
1939
|
+
*
|
|
1940
|
+
* This is the Mina analog of `openSolanaChannel` (connector#105): the client
|
|
1941
|
+
* opens its own per-channel on-chain state (initialize + optional deposit). The
|
|
1942
|
+
* heavyweight o1js + `@toon-protocol/mina-zkapp` proof work is lazily imported
|
|
1943
|
+
* inside `openMinaChannelOnChain` so npm consumers who never open a Mina
|
|
1944
|
+
* channel don't pay the o1js cost.
|
|
1945
|
+
*
|
|
1946
|
+
* Idempotent: if the on-chain channel is already `OPEN`, the opener returns
|
|
1947
|
+
* without re-initializing.
|
|
1948
|
+
*
|
|
1949
|
+
* NOTE: full on-chain Mina SETTLE remains gated by the connector-side
|
|
1950
|
+
* settlement-executor (the same blocker that stops the Solana SETTLE); reaching
|
|
1951
|
+
* `opened` + a stored claim is parity with Solana.
|
|
967
1952
|
*/
|
|
968
1953
|
private openMinaChannel;
|
|
969
1954
|
/**
|
|
@@ -1062,6 +2047,8 @@ declare class ChannelManager {
|
|
|
1062
2047
|
chainId: number;
|
|
1063
2048
|
tokenNetworkAddress: string;
|
|
1064
2049
|
tokenAddress?: string;
|
|
2050
|
+
recipient?: string;
|
|
2051
|
+
depositTotal?: bigint;
|
|
1065
2052
|
}, initialNonce?: number, initialAmount?: bigint): void;
|
|
1066
2053
|
/**
|
|
1067
2054
|
* Signs a balance proof for the given channel.
|
|
@@ -1093,6 +2080,26 @@ declare class ChannelManager {
|
|
|
1093
2080
|
isTracking(channelId: string): boolean;
|
|
1094
2081
|
}
|
|
1095
2082
|
|
|
2083
|
+
/**
|
|
2084
|
+
* Read a Mina payment-channel zkApp's on-chain `depositTotal` via a plain
|
|
2085
|
+
* GraphQL query (no o1js / WASM). Used by {@link MinaSigner} to bind the
|
|
2086
|
+
* conserved `balanceB = depositTotal − balanceA` commitment that a FUNDED zkApp
|
|
2087
|
+
* requires (connector#133); without it the connector's `claimFromChannel`
|
|
2088
|
+
* verification rejects the claim with `F06 - Invalid zk-SNARK proof on claim`.
|
|
2089
|
+
*
|
|
2090
|
+
* The `PaymentChannel` zkApp app-state field order is
|
|
2091
|
+
* `[channelHash, balanceCommitment, nonceField, channelState, depositTotal, …]`
|
|
2092
|
+
* (see `mina-channel-open.ts`), so `depositTotal` is `zkappState[4]`.
|
|
2093
|
+
*/
|
|
2094
|
+
/**
|
|
2095
|
+
* Query `account(publicKey).zkappState` and return the channel's `depositTotal`
|
|
2096
|
+
* (base units). Throws when the account/state is unavailable so callers can fall
|
|
2097
|
+
* back to the legacy `balanceB = 0` behavior.
|
|
2098
|
+
*
|
|
2099
|
+
* @param fetchImpl - injectable for tests; defaults to global `fetch`.
|
|
2100
|
+
*/
|
|
2101
|
+
declare function readMinaDepositTotal(graphqlUrl: string, zkAppAddress: string, fetchImpl?: typeof fetch): Promise<bigint>;
|
|
2102
|
+
|
|
1096
2103
|
/**
|
|
1097
2104
|
* Configuration options for retry behavior with exponential backoff.
|
|
1098
2105
|
*/
|
|
@@ -1130,6 +2137,95 @@ interface RetryOptions {
|
|
|
1130
2137
|
*/
|
|
1131
2138
|
declare function withRetry<T>(operation: () => Promise<T>, options: RetryOptions): Promise<T>;
|
|
1132
2139
|
|
|
2140
|
+
/**
|
|
2141
|
+
* Self-managed `anon` (anyone-protocol / ATOR) SOCKS5h proxy (Node.js only).
|
|
2142
|
+
*
|
|
2143
|
+
* Lets a `@toon-protocol/client` consumer reach a `.anyone` hidden service with
|
|
2144
|
+
* ZERO manual proxy setup: the SDK downloads, verifies, extracts, and spawns its
|
|
2145
|
+
* own `anon` daemon, waits for it to bootstrap + bind a loopback SOCKS5 port, and
|
|
2146
|
+
* hands back a `socks5h://127.0.0.1:<port>` URL. The proven reference is the
|
|
2147
|
+
* server-side pod entrypoint `docker/src/entrypoint-toon-client.ts` (`writeTorrc`,
|
|
2148
|
+
* `spawnAnon`, `waitForAnonSocks`, `tcpProbe`); this module ports that daemon
|
|
2149
|
+
* logic into the client package and adds the binary download + checksum gate so it
|
|
2150
|
+
* works without an OS-level `anon` install.
|
|
2151
|
+
*
|
|
2152
|
+
* BROWSER SAFETY: this module is dynamically imported only from `resolveTransport`
|
|
2153
|
+
* when a managed proxy is actually needed (Node-only path). Every Node built-in is
|
|
2154
|
+
* pulled in lazily via the ESM-safe `require(...)` built off `import.meta.url`
|
|
2155
|
+
* (the same pattern as `socks5.ts`), so a browser bundler that statically analyses
|
|
2156
|
+
* the package never reaches `node:child_process`/`node:fs`/`node:https`/`node:net`.
|
|
2157
|
+
*/
|
|
2158
|
+
/**
|
|
2159
|
+
* Pinned `anon` release. "beta" is the channel slug embedded in the per-platform
|
|
2160
|
+
* zip asset names (e.g. `anon-beta-macos-arm64.zip`).
|
|
2161
|
+
*/
|
|
2162
|
+
declare const ANON_VERSION = "v0.4.10.0-beta";
|
|
2163
|
+
/**
|
|
2164
|
+
* Per-platform `anon` zip asset descriptor. `sha256` is the pinned checksum of the
|
|
2165
|
+
* release zip. All supported platforms are pinned (issue #204); the type stays
|
|
2166
|
+
* `string | null` and the download gate still defensively refuses a `null` entry,
|
|
2167
|
+
* so adding a new (not-yet-hashed) platform fails closed rather than skipping
|
|
2168
|
+
* verification.
|
|
2169
|
+
*/
|
|
2170
|
+
interface AnonAsset {
|
|
2171
|
+
/** Release asset file name, e.g. `anon-beta-macos-arm64.zip`. */
|
|
2172
|
+
assetName: string;
|
|
2173
|
+
/** Pinned sha256 of the zip, or null when not yet pinned (issue #204). */
|
|
2174
|
+
sha256: string | null;
|
|
2175
|
+
}
|
|
2176
|
+
/**
|
|
2177
|
+
* Platform → asset map keyed by `${os.platform()}-${os.arch()}` (Node values).
|
|
2178
|
+
* Only macOS + Linux on x64/arm64 are supported (the `anon` releases that ship a
|
|
2179
|
+
* SOCKS-capable binary). Windows is intentionally absent.
|
|
2180
|
+
*
|
|
2181
|
+
* Pinned checksums (issue #204): all four supported platforms are pinned to the
|
|
2182
|
+
* sha256 of the `v0.4.10.0-beta` release zips (downloaded + hashed; the
|
|
2183
|
+
* darwin-arm64 value matches the previously-verified manual flow).
|
|
2184
|
+
*/
|
|
2185
|
+
declare const ANON_ASSETS: Record<string, AnonAsset>;
|
|
2186
|
+
/**
|
|
2187
|
+
* Resolves the `anon` release asset for a platform/arch pair (Node
|
|
2188
|
+
* `os.platform()` / `os.arch()` values).
|
|
2189
|
+
*
|
|
2190
|
+
* @throws If the platform/arch combination has no known `anon` asset.
|
|
2191
|
+
*/
|
|
2192
|
+
declare function selectAnonAsset(platform: string, arch: string): AnonAsset;
|
|
2193
|
+
/**
|
|
2194
|
+
* Handle returned by `startManagedAnonProxy`. `socksProxy` is the loopback
|
|
2195
|
+
* `socks5h://` URL to wire into `transport: { type: 'socks5', socksProxy }`.
|
|
2196
|
+
* `stop()` SIGTERMs the daemon and is idempotent.
|
|
2197
|
+
*/
|
|
2198
|
+
interface ManagedAnonProxy {
|
|
2199
|
+
socksProxy: string;
|
|
2200
|
+
stop(): Promise<void>;
|
|
2201
|
+
}
|
|
2202
|
+
/**
|
|
2203
|
+
* Options for `startManagedAnonProxy`. All have sensible defaults; tests inject
|
|
2204
|
+
* the deps to avoid real downloads/spawns.
|
|
2205
|
+
*/
|
|
2206
|
+
interface StartManagedAnonProxyOptions {
|
|
2207
|
+
/** Cache dir for the binary + torrc + data. Default: {@link defaultCacheDir}. */
|
|
2208
|
+
cacheDir?: string;
|
|
2209
|
+
/** Loopback SOCKS5 port. Default 9050. */
|
|
2210
|
+
socksPort?: number;
|
|
2211
|
+
/** Bootstrap deadline in ms. Default 180_000. */
|
|
2212
|
+
bootstrapTimeoutMs?: number;
|
|
2213
|
+
/** Logger. Default: no-op. */
|
|
2214
|
+
log?: (msg: string) => void;
|
|
2215
|
+
/** os.platform() override (tests). */
|
|
2216
|
+
platform?: string;
|
|
2217
|
+
/** os.arch() override (tests). */
|
|
2218
|
+
arch?: string;
|
|
2219
|
+
}
|
|
2220
|
+
/**
|
|
2221
|
+
* Downloads (if needed) + spawns a managed `anon` daemon and waits for its SOCKS5
|
|
2222
|
+
* port to bind. Returns a {@link ManagedAnonProxy} whose `socksProxy` is ready for
|
|
2223
|
+
* `transport: { type: 'socks5', socksProxy }`.
|
|
2224
|
+
*
|
|
2225
|
+
* @throws If the platform is unsupported, the checksum fails, or anon never binds.
|
|
2226
|
+
*/
|
|
2227
|
+
declare function startManagedAnonProxy(options?: StartManagedAnonProxyOptions): Promise<ManagedAnonProxy>;
|
|
2228
|
+
|
|
1133
2229
|
/**
|
|
1134
2230
|
* Settlement info produced by buildSettlementInfo().
|
|
1135
2231
|
* Extends the core SettlementConfig shape with ilpAddress for client use.
|
|
@@ -1141,6 +2237,27 @@ interface ClientSettlementInfo {
|
|
|
1141
2237
|
preferredTokens?: Record<string, string>;
|
|
1142
2238
|
tokenNetworks?: Record<string, string>;
|
|
1143
2239
|
}
|
|
2240
|
+
/**
|
|
2241
|
+
* Applies named-network preset defaults to a client config.
|
|
2242
|
+
*
|
|
2243
|
+
* When `config.network` is set and != `'custom'`, the settlement-related
|
|
2244
|
+
* fields are defaulted from the shared core presets (`resolveClientNetwork`):
|
|
2245
|
+
* RPC/GraphQL URLs, supported chain identifiers, preferred tokens, EVM
|
|
2246
|
+
* TokenNetwork addresses, and the Solana/Mina channel params. Any explicit
|
|
2247
|
+
* per-chain field on `config` OVERRIDES the preset (explicit always wins).
|
|
2248
|
+
*
|
|
2249
|
+
* `'custom'` and the unset case both pass `config` through untouched, keeping
|
|
2250
|
+
* the fully-manual path and full backward compatibility.
|
|
2251
|
+
*
|
|
2252
|
+
* @returns A shallow copy with preset defaults merged in (never mutates input).
|
|
2253
|
+
*/
|
|
2254
|
+
declare function applyNetworkPresets(config: ToonClientConfig): ToonClientConfig;
|
|
2255
|
+
/**
|
|
2256
|
+
* Returns per-chain settlement readiness for the configured `network` tier,
|
|
2257
|
+
* mirroring the townhouse node's status. Returns `undefined` when `network` is
|
|
2258
|
+
* unset or `'custom'` (no preset tier to report on).
|
|
2259
|
+
*/
|
|
2260
|
+
declare function getNetworkStatus(config: ToonClientConfig): NetworkFamilyStatus | undefined;
|
|
1144
2261
|
/**
|
|
1145
2262
|
* Validates ToonClient configuration.
|
|
1146
2263
|
*
|
|
@@ -1153,10 +2270,30 @@ declare function validateConfig(config: ToonClientConfig): void;
|
|
|
1153
2270
|
* The resolved config type after defaults are applied.
|
|
1154
2271
|
* secretKey is guaranteed to be present (auto-generated if omitted).
|
|
1155
2272
|
*/
|
|
1156
|
-
type ResolvedConfig = Required<Omit<ToonClientConfig, 'connector' | 'evmPrivateKey' | 'supportedChains' | 'settlementAddresses' | 'preferredTokens' | 'tokenNetworks' | 'btpUrl' | 'btpAuthToken' | 'btpPeerId' | 'chainRpcUrls' | 'initialDeposit' | 'settlementTimeout' | 'channelStorePath' | 'knownPeers' | 'destinationAddress'>> & {
|
|
2273
|
+
type ResolvedConfig = Required<Omit<ToonClientConfig, 'connector' | 'mnemonic' | 'mnemonicAccountIndex' | 'evmPrivateKey' | 'network' | 'supportedChains' | 'settlementAddresses' | 'preferredTokens' | 'tokenNetworks' | 'btpUrl' | 'btpAuthToken' | 'btpPeerId' | 'connectorHttpEndpoint' | 'connectorSupportsUpgrade' | 'chainRpcUrls' | 'initialDeposit' | 'settlementTimeout' | 'solanaChannel' | 'minaChannel' | 'channelStorePath' | 'knownPeers' | 'destinationAddress' | 'transport' | 'managedAnonProxy' | 'managedAnonSocksPort'>> & {
|
|
1157
2274
|
connector?: unknown;
|
|
1158
2275
|
/** Always present after applyDefaults() — derived from secretKey if not explicitly provided */
|
|
1159
2276
|
evmPrivateKey: string | Uint8Array;
|
|
2277
|
+
/**
|
|
2278
|
+
* BIP-39 phrase retained so `ToonClient.start()` can derive the Solana/Mina
|
|
2279
|
+
* keys asynchronously and register the corresponding signers. The Nostr/EVM
|
|
2280
|
+
* keys are already resolved synchronously into `secretKey`/`evmPrivateKey`.
|
|
2281
|
+
*/
|
|
2282
|
+
mnemonic?: string;
|
|
2283
|
+
/**
|
|
2284
|
+
* BIP-44 account index for mnemonic-based derivation (defaults to 0).
|
|
2285
|
+
* Retained so `ToonClient.start()` derives the Solana/Mina signers at the
|
|
2286
|
+
* same index as the synchronously-resolved Nostr/EVM keys.
|
|
2287
|
+
*/
|
|
2288
|
+
mnemonicAccountIndex?: number;
|
|
2289
|
+
/** Transport privacy config (optional — defaults to direct). */
|
|
2290
|
+
transport?: ClientTransportConfig;
|
|
2291
|
+
/** Named network tier, retained for `getNetworkStatus()`. */
|
|
2292
|
+
network?: ToonClientConfig['network'];
|
|
2293
|
+
/** Self-managed `anon` SOCKS5h proxy opt-out (default auto). */
|
|
2294
|
+
managedAnonProxy?: boolean;
|
|
2295
|
+
/** Loopback SOCKS port for the managed `anon` daemon (default 9050). */
|
|
2296
|
+
managedAnonSocksPort?: number;
|
|
1160
2297
|
supportedChains?: string[];
|
|
1161
2298
|
settlementAddresses?: Record<string, string>;
|
|
1162
2299
|
preferredTokens?: Record<string, string>;
|
|
@@ -1164,9 +2301,13 @@ type ResolvedConfig = Required<Omit<ToonClientConfig, 'connector' | 'evmPrivateK
|
|
|
1164
2301
|
btpUrl?: string;
|
|
1165
2302
|
btpAuthToken?: string;
|
|
1166
2303
|
btpPeerId?: string;
|
|
2304
|
+
connectorHttpEndpoint?: string;
|
|
2305
|
+
connectorSupportsUpgrade?: boolean;
|
|
1167
2306
|
chainRpcUrls?: Record<string, string>;
|
|
1168
2307
|
initialDeposit?: string;
|
|
1169
2308
|
settlementTimeout?: number;
|
|
2309
|
+
solanaChannel?: ToonClientConfig['solanaChannel'];
|
|
2310
|
+
minaChannel?: ToonClientConfig['minaChannel'];
|
|
1170
2311
|
channelStorePath?: string;
|
|
1171
2312
|
knownPeers?: {
|
|
1172
2313
|
pubkey: string;
|
|
@@ -1180,12 +2321,412 @@ type ResolvedConfig = Required<Omit<ToonClientConfig, 'connector' | 'evmPrivateK
|
|
|
1180
2321
|
* Auto-generates a Nostr keypair when secretKey is omitted.
|
|
1181
2322
|
* Derives btpUrl from connectorUrl when not provided.
|
|
1182
2323
|
*/
|
|
1183
|
-
declare function applyDefaults(
|
|
2324
|
+
declare function applyDefaults(rawConfig: ToonClientConfig): ResolvedConfig;
|
|
1184
2325
|
/**
|
|
1185
2326
|
* Builds SettlementConfig from client config.
|
|
1186
2327
|
* Returns undefined if no settlement-related config is present.
|
|
1187
2328
|
*/
|
|
1188
|
-
declare function buildSettlementInfo(
|
|
2329
|
+
declare function buildSettlementInfo(rawConfig: ToonClientConfig): ClientSettlementInfo | undefined;
|
|
2330
|
+
|
|
2331
|
+
/**
|
|
2332
|
+
* Pet DVM Client-Side Types
|
|
2333
|
+
*
|
|
2334
|
+
* Locally defined types for pet DVM interaction utilities.
|
|
2335
|
+
* These mirror server-side types but do NOT import from @toon-protocol/pet-dvm,
|
|
2336
|
+
* @toon-protocol/pet-circuit, or @toon-protocol/memvid-node.
|
|
2337
|
+
*
|
|
2338
|
+
* @module pet/types
|
|
2339
|
+
*/
|
|
2340
|
+
/** Plain-number stat values (all clamped to [1, 100]) */
|
|
2341
|
+
interface StatValues {
|
|
2342
|
+
hunger: number;
|
|
2343
|
+
happiness: number;
|
|
2344
|
+
health: number;
|
|
2345
|
+
hygiene: number;
|
|
2346
|
+
energy: number;
|
|
2347
|
+
}
|
|
2348
|
+
/** Metadata for a pet DVM provider discovered via Kind 10035 events */
|
|
2349
|
+
interface PetDvmProvider {
|
|
2350
|
+
/** ILP address of the provider's connector */
|
|
2351
|
+
ilpAddress: string;
|
|
2352
|
+
/** Per-interaction cost from skill.pricing['5900'] */
|
|
2353
|
+
pricing: string;
|
|
2354
|
+
/** Provider's Nostr pubkey (cryptographically bound from event.pubkey) */
|
|
2355
|
+
pubkey: string;
|
|
2356
|
+
/** Feature list from skill.features */
|
|
2357
|
+
features: string[];
|
|
2358
|
+
}
|
|
2359
|
+
/** Parameters for building a Kind 5900 pet interaction request */
|
|
2360
|
+
interface PetInteractionRequestParams {
|
|
2361
|
+
/** Blobbi identifier (non-empty string) */
|
|
2362
|
+
blobbiId: string;
|
|
2363
|
+
/** Action type (0-10, maps to Feed/Play/Clean/etc.) */
|
|
2364
|
+
actionType: number;
|
|
2365
|
+
/** Item identifier (>= 0) */
|
|
2366
|
+
itemId: number;
|
|
2367
|
+
/** Token cost for this interaction (>= 0) */
|
|
2368
|
+
tokenCost: number;
|
|
2369
|
+
/** Whether the pet is currently sleeping */
|
|
2370
|
+
isSleeping: boolean;
|
|
2371
|
+
}
|
|
2372
|
+
/** Unsigned Nostr event structure compatible with nostr-tools finalizeEvent */
|
|
2373
|
+
interface UnsignedNostrEvent {
|
|
2374
|
+
kind: number;
|
|
2375
|
+
created_at: number;
|
|
2376
|
+
tags: string[][];
|
|
2377
|
+
content: string;
|
|
2378
|
+
}
|
|
2379
|
+
/** Parsed result data from Kind 6900 DVM response (base64 JSON in IlpSendResult.data) */
|
|
2380
|
+
interface PetInteractionResultData {
|
|
2381
|
+
/** Current stat values */
|
|
2382
|
+
stats: StatValues;
|
|
2383
|
+
/** Current stage (0=Egg, 1=Baby, 2=Adult) */
|
|
2384
|
+
stage: number;
|
|
2385
|
+
/** Current evolution cycle (>= 0) */
|
|
2386
|
+
cycle: number;
|
|
2387
|
+
/** Unix timestamp of last interaction */
|
|
2388
|
+
lastInteraction: number;
|
|
2389
|
+
/** 64-char hex BLAKE3 hash of brain state */
|
|
2390
|
+
brainHash: string;
|
|
2391
|
+
/** Per-action-type cooldown timestamps */
|
|
2392
|
+
cooldownTimestamps: number[];
|
|
2393
|
+
}
|
|
2394
|
+
/** Stat snapshot used in interaction result content */
|
|
2395
|
+
interface InteractionResultContent {
|
|
2396
|
+
priorStats: StatValues;
|
|
2397
|
+
decayedStats: StatValues;
|
|
2398
|
+
finalStats: StatValues;
|
|
2399
|
+
cycle: number;
|
|
2400
|
+
stage: number;
|
|
2401
|
+
tokenCost: number;
|
|
2402
|
+
}
|
|
2403
|
+
/** Proof status of a Kind 14919 event */
|
|
2404
|
+
type ProofStatus = 'optimistic' | 'proven';
|
|
2405
|
+
/** Parameters for building a Kind 30402 pet-for-sale classified listing */
|
|
2406
|
+
interface PetListingParams {
|
|
2407
|
+
/** Blobbi identifier (non-empty string) — used as the 'd' tag */
|
|
2408
|
+
blobbiId: string;
|
|
2409
|
+
/** Asking price in USDC (> 0) */
|
|
2410
|
+
askPriceUsdc: number;
|
|
2411
|
+
/** 64-char hex lifecycleHash from on-chain PetZkApp state */
|
|
2412
|
+
lifecycleHash: string;
|
|
2413
|
+
/** Cumulative PET tokens spent (numeric string, >= "0") */
|
|
2414
|
+
totalSpent: string;
|
|
2415
|
+
/** Current stage: 0=Egg, 1=Baby, 2=Adult */
|
|
2416
|
+
stage: number;
|
|
2417
|
+
/** Current pet stats */
|
|
2418
|
+
stats: StatValues;
|
|
2419
|
+
/** Seller's Nostr pubkey (64-char hex) */
|
|
2420
|
+
sellerPubkey: string;
|
|
2421
|
+
/** Preferred relay URL for event relay routing */
|
|
2422
|
+
relayUrl: string;
|
|
2423
|
+
/** Listing expiry as unix timestamp */
|
|
2424
|
+
expiresAt: number;
|
|
2425
|
+
}
|
|
2426
|
+
/** A parsed pet-for-sale listing (extends PetListingParams with event metadata) */
|
|
2427
|
+
interface PetListing extends PetListingParams {
|
|
2428
|
+
/** Nostr event ID of the kind:30402 listing event */
|
|
2429
|
+
eventId: string;
|
|
2430
|
+
/** Unix timestamp when the listing event was created */
|
|
2431
|
+
createdAt: number;
|
|
2432
|
+
}
|
|
2433
|
+
/** Filter options for filterPetListings() */
|
|
2434
|
+
interface PetListingFilterOptions {
|
|
2435
|
+
/** Only include listings for pets at or above this stage */
|
|
2436
|
+
minStage?: number;
|
|
2437
|
+
/** Only include listings at or below this USDC price */
|
|
2438
|
+
maxAskPriceUsdc?: number;
|
|
2439
|
+
/** Only include listings where totalSpent >= this value (numeric string comparison) */
|
|
2440
|
+
minTotalSpent?: string;
|
|
2441
|
+
/** Only include listings from this seller pubkey */
|
|
2442
|
+
sellerPubkey?: string;
|
|
2443
|
+
}
|
|
2444
|
+
/** Parameters for building a Kind 5900 pet purchase request (transfer-ownership) */
|
|
2445
|
+
interface PetPurchaseRequestParams {
|
|
2446
|
+
/** Blobbi identifier being purchased */
|
|
2447
|
+
blobbiId: string;
|
|
2448
|
+
/** Nostr event ID of the kind:30402 listing being purchased */
|
|
2449
|
+
listingEventId: string;
|
|
2450
|
+
/** Buyer's Nostr pubkey (64-char hex) */
|
|
2451
|
+
buyerPubkey: string;
|
|
2452
|
+
/** Token cost for the purchase (>= 0) */
|
|
2453
|
+
tokenCost: number;
|
|
2454
|
+
/** Seller's Nostr pubkey — ILP payment routed to this pubkey (64-char hex) */
|
|
2455
|
+
sellerPubkey: string;
|
|
2456
|
+
}
|
|
2457
|
+
/** Parsed data from a Kind 14919 pet interaction event */
|
|
2458
|
+
interface PetInteractionEventData {
|
|
2459
|
+
/** Blobbi identifier from 'd' tag */
|
|
2460
|
+
blobbiId: string;
|
|
2461
|
+
/** Action type from 'action' tag */
|
|
2462
|
+
actionType: number;
|
|
2463
|
+
/** Item identifier from 'item' tag */
|
|
2464
|
+
itemId: number;
|
|
2465
|
+
/** Token cost from 'cost' tag */
|
|
2466
|
+
tokenCost: number;
|
|
2467
|
+
/** Evolution cycle from 'cycle' tag */
|
|
2468
|
+
cycle: number;
|
|
2469
|
+
/** Stage from 'stage' tag */
|
|
2470
|
+
stage: number;
|
|
2471
|
+
/** Brain hash from 'brain_hash' tag */
|
|
2472
|
+
brainHash: string;
|
|
2473
|
+
/** Proof status: 'optimistic' (no proof tag) or 'proven' (has proof + mina_tx tags) */
|
|
2474
|
+
proofStatus: ProofStatus;
|
|
2475
|
+
/** Parsed content JSON (stats before/after) */
|
|
2476
|
+
content: InteractionResultContent | null;
|
|
2477
|
+
/** Base64 proof data (only present when proven) */
|
|
2478
|
+
proof?: string;
|
|
2479
|
+
/** Mina transaction hash (only present when proven) */
|
|
2480
|
+
minaTx?: string;
|
|
2481
|
+
}
|
|
2482
|
+
|
|
2483
|
+
/**
|
|
2484
|
+
* Pet DVM Provider Discovery
|
|
2485
|
+
*
|
|
2486
|
+
* Filters Kind 10035 service discovery events to find providers that
|
|
2487
|
+
* support Pet DVM interactions (Kind 5900).
|
|
2488
|
+
*
|
|
2489
|
+
* @module pet/filterPetDvmProviders
|
|
2490
|
+
*/
|
|
2491
|
+
|
|
2492
|
+
/**
|
|
2493
|
+
* Minimal Nostr event shape needed for filtering.
|
|
2494
|
+
* Using a local interface to avoid importing nostr-tools types.
|
|
2495
|
+
*/
|
|
2496
|
+
interface NostrEventLike$3 {
|
|
2497
|
+
kind: number;
|
|
2498
|
+
pubkey: string;
|
|
2499
|
+
content: string;
|
|
2500
|
+
tags: string[][];
|
|
2501
|
+
id: string;
|
|
2502
|
+
sig: string;
|
|
2503
|
+
created_at: number;
|
|
2504
|
+
}
|
|
2505
|
+
/**
|
|
2506
|
+
* Filter Kind 10035 service discovery events to find pet DVM providers.
|
|
2507
|
+
*
|
|
2508
|
+
* Accepts raw NostrEvent[] and internally parses content via parseServiceDiscovery.
|
|
2509
|
+
* Filters events where skill.kinds includes 5900 (PET_INTERACTION_REQUEST_KIND).
|
|
2510
|
+
* Returns provider metadata sorted by price ascending (cheapest first).
|
|
2511
|
+
*
|
|
2512
|
+
* Handles missing/malformed skill descriptors gracefully (returns empty array, no throw).
|
|
2513
|
+
*
|
|
2514
|
+
* @param events - Array of raw Nostr events (kind:10035)
|
|
2515
|
+
* @returns Array of PetDvmProvider metadata, sorted by price ascending
|
|
2516
|
+
*/
|
|
2517
|
+
declare function filterPetDvmProviders(events: NostrEventLike$3[]): PetDvmProvider[];
|
|
2518
|
+
|
|
2519
|
+
/**
|
|
2520
|
+
* Pet Interaction Request Builder (Kind 5900)
|
|
2521
|
+
*
|
|
2522
|
+
* Builds unsigned Kind 5900 Nostr events for pet DVM interaction requests.
|
|
2523
|
+
* Compatible with nostr-tools/pure finalizeEvent for signing.
|
|
2524
|
+
*
|
|
2525
|
+
* @module pet/buildPetInteractionRequest
|
|
2526
|
+
*/
|
|
2527
|
+
|
|
2528
|
+
/**
|
|
2529
|
+
* Build an unsigned Kind 5900 pet interaction request event.
|
|
2530
|
+
*
|
|
2531
|
+
* All tag values are stringified per Nostr protocol convention.
|
|
2532
|
+
* The returned event is compatible with nostr-tools `finalizeEvent`.
|
|
2533
|
+
*
|
|
2534
|
+
* @param params - Typed interaction parameters
|
|
2535
|
+
* @returns Unsigned Nostr event ready for signing
|
|
2536
|
+
* @throws ValidationError for invalid input
|
|
2537
|
+
*/
|
|
2538
|
+
declare function buildPetInteractionRequest(params: PetInteractionRequestParams): UnsignedNostrEvent;
|
|
2539
|
+
|
|
2540
|
+
/**
|
|
2541
|
+
* Pet Interaction Result Parser (Kind 6900)
|
|
2542
|
+
*
|
|
2543
|
+
* Decodes base64-encoded JSON from IlpSendResult.data field.
|
|
2544
|
+
* Uses browser-safe atob() -- NOT Node.js Buffer -- for ditto React SPA compatibility.
|
|
2545
|
+
*
|
|
2546
|
+
* @module pet/parsePetInteractionResult
|
|
2547
|
+
*/
|
|
2548
|
+
|
|
2549
|
+
/**
|
|
2550
|
+
* Parse base64-encoded JSON result data from a Kind 6900 DVM response.
|
|
2551
|
+
*
|
|
2552
|
+
* Uses atob() for browser compatibility (ditto React SPA).
|
|
2553
|
+
* Returns null for malformed/missing data (no throw).
|
|
2554
|
+
*
|
|
2555
|
+
* Validates:
|
|
2556
|
+
* - brainHash is 64-char hex
|
|
2557
|
+
* - stats has all 5 fields
|
|
2558
|
+
* - cycle >= 0
|
|
2559
|
+
* - stage 0-2
|
|
2560
|
+
*
|
|
2561
|
+
* @param data - Base64-encoded JSON string from IlpSendResult.data
|
|
2562
|
+
* @returns Parsed PetInteractionResultData or null if invalid
|
|
2563
|
+
*/
|
|
2564
|
+
declare function parsePetInteractionResult(data: string): PetInteractionResultData | null;
|
|
2565
|
+
|
|
2566
|
+
/**
|
|
2567
|
+
* Pet Interaction Event Parser (Kind 14919)
|
|
2568
|
+
*
|
|
2569
|
+
* Parses Kind 14919 optimistic/proven pet interaction events.
|
|
2570
|
+
* Detects proof status from presence of 'proof' + 'mina_tx' tags.
|
|
2571
|
+
*
|
|
2572
|
+
* @module pet/parsePetInteractionEvent
|
|
2573
|
+
*/
|
|
2574
|
+
|
|
2575
|
+
/**
|
|
2576
|
+
* Minimal Nostr event shape needed for parsing.
|
|
2577
|
+
*/
|
|
2578
|
+
interface NostrEventLike$2 {
|
|
2579
|
+
kind: number;
|
|
2580
|
+
pubkey: string;
|
|
2581
|
+
content: string;
|
|
2582
|
+
tags: string[][];
|
|
2583
|
+
id: string;
|
|
2584
|
+
sig: string;
|
|
2585
|
+
created_at: number;
|
|
2586
|
+
}
|
|
2587
|
+
/**
|
|
2588
|
+
* Parse a Kind 14919 pet interaction event.
|
|
2589
|
+
*
|
|
2590
|
+
* Extracts all tag values and detects proof status:
|
|
2591
|
+
* - 'optimistic': no 'proof' tag
|
|
2592
|
+
* - 'proven': has 'proof' + 'mina_tx' tags
|
|
2593
|
+
*
|
|
2594
|
+
* Returns null if required tags are missing.
|
|
2595
|
+
*
|
|
2596
|
+
* @param event - A Nostr event (Kind 14919)
|
|
2597
|
+
* @returns Parsed PetInteractionEventData or null if malformed
|
|
2598
|
+
*/
|
|
2599
|
+
declare function parsePetInteractionEvent(event: NostrEventLike$2): PetInteractionEventData | null;
|
|
2600
|
+
|
|
2601
|
+
/**
|
|
2602
|
+
* Pet Listing Event Builder (Kind 30402)
|
|
2603
|
+
*
|
|
2604
|
+
* Builds unsigned Kind 30402 (NIP-99 classified listing) Nostr events
|
|
2605
|
+
* for pet-for-sale marketplace listings. Every listing includes a
|
|
2606
|
+
* verified biography attachment (lifecycleHash + totalSpent) so buyers
|
|
2607
|
+
* can verify the listing against on-chain PetZkApp state.
|
|
2608
|
+
*
|
|
2609
|
+
* Browser-compatible — no Node.js-only imports.
|
|
2610
|
+
*
|
|
2611
|
+
* @module pet/buildPetListingEvent
|
|
2612
|
+
*/
|
|
2613
|
+
|
|
2614
|
+
/**
|
|
2615
|
+
* Build an unsigned Kind 30402 pet-for-sale classified listing event.
|
|
2616
|
+
*
|
|
2617
|
+
* The listing uses the NIP-99 classified listing format with TOON-specific
|
|
2618
|
+
* extension tags for verified biography (lifecycleHash, totalSpent).
|
|
2619
|
+
* The `d` tag is set to `blobbiId` for stable parameterized replaceability —
|
|
2620
|
+
* republishing with the same `d` tag updates the listing on relays.
|
|
2621
|
+
*
|
|
2622
|
+
* The returned event is compatible with nostr-tools `finalizeEvent`.
|
|
2623
|
+
*
|
|
2624
|
+
* @param params - Typed listing parameters
|
|
2625
|
+
* @returns Unsigned Nostr event ready for signing and publishing
|
|
2626
|
+
*/
|
|
2627
|
+
declare function buildPetListingEvent(params: PetListingParams): UnsignedNostrEvent;
|
|
2628
|
+
|
|
2629
|
+
/**
|
|
2630
|
+
* Pet Listing Parser (Kind 30402)
|
|
2631
|
+
*
|
|
2632
|
+
* Parses Kind 30402 (NIP-99 classified listing) Nostr events into
|
|
2633
|
+
* typed PetListing objects. Returns null for invalid or malformed events.
|
|
2634
|
+
*
|
|
2635
|
+
* Browser-compatible — no Node.js-only imports.
|
|
2636
|
+
*
|
|
2637
|
+
* @module pet/parsePetListing
|
|
2638
|
+
*/
|
|
2639
|
+
|
|
2640
|
+
/** Minimal Nostr event shape required for parsing */
|
|
2641
|
+
interface NostrEventLike$1 {
|
|
2642
|
+
id: string;
|
|
2643
|
+
kind: number;
|
|
2644
|
+
pubkey: string;
|
|
2645
|
+
tags: string[][];
|
|
2646
|
+
content: string;
|
|
2647
|
+
created_at: number;
|
|
2648
|
+
}
|
|
2649
|
+
/**
|
|
2650
|
+
* Parse a Kind 30402 pet classified listing event into a PetListing.
|
|
2651
|
+
*
|
|
2652
|
+
* Validation rules:
|
|
2653
|
+
* - event.kind must be 30402
|
|
2654
|
+
* - 'd' tag must be present and non-empty
|
|
2655
|
+
* - 'price' tag must be present with a valid positive numeric first element
|
|
2656
|
+
* - 'lifecycle_hash' tag must be a 64-char hex string
|
|
2657
|
+
* - 'total_spent' tag must be a valid non-negative numeric string
|
|
2658
|
+
* - 'stage' tag must be present
|
|
2659
|
+
*
|
|
2660
|
+
* Stats are parsed from content JSON; unparseable content falls back to DEFAULT_STATS.
|
|
2661
|
+
*
|
|
2662
|
+
* @param event - A Nostr event (expected Kind 30402)
|
|
2663
|
+
* @returns Parsed PetListing or null if invalid
|
|
2664
|
+
*/
|
|
2665
|
+
declare function parsePetListing(event: NostrEventLike$1): PetListing | null;
|
|
2666
|
+
|
|
2667
|
+
/**
|
|
2668
|
+
* Pet Listing Discovery Filter
|
|
2669
|
+
*
|
|
2670
|
+
* Filters and sorts Kind 30402 pet marketplace listing events into
|
|
2671
|
+
* typed PetListing objects. Handles expiry, stage, price, biography
|
|
2672
|
+
* value, and seller filtering. Results sorted by totalSpent descending
|
|
2673
|
+
* (highest biography value first) to surface the most battle-hardened pets.
|
|
2674
|
+
*
|
|
2675
|
+
* Browser-compatible — no Node.js-only imports.
|
|
2676
|
+
*
|
|
2677
|
+
* @module pet/filterPetListings
|
|
2678
|
+
*/
|
|
2679
|
+
|
|
2680
|
+
/** Minimal Nostr event shape accepted by the filter */
|
|
2681
|
+
interface NostrEventLike {
|
|
2682
|
+
id: string;
|
|
2683
|
+
kind: number;
|
|
2684
|
+
pubkey: string;
|
|
2685
|
+
tags: string[][];
|
|
2686
|
+
content: string;
|
|
2687
|
+
created_at: number;
|
|
2688
|
+
}
|
|
2689
|
+
/**
|
|
2690
|
+
* Filter and sort Kind 30402 pet marketplace listing events.
|
|
2691
|
+
*
|
|
2692
|
+
* Parsing is done via parsePetListing — invalid events are silently dropped.
|
|
2693
|
+
* Expired listings (expiration tag < current unix time) are excluded.
|
|
2694
|
+
* Options allow additional filtering by stage, price, biography value, and seller.
|
|
2695
|
+
* Results are sorted by totalSpent descending (highest biography value first).
|
|
2696
|
+
*
|
|
2697
|
+
* @param events - Array of raw Nostr events to filter
|
|
2698
|
+
* @param options - Optional filter criteria
|
|
2699
|
+
* @returns Filtered and sorted array of PetListing objects
|
|
2700
|
+
*/
|
|
2701
|
+
declare function filterPetListings(events: NostrEventLike[], options?: PetListingFilterOptions): PetListing[];
|
|
2702
|
+
|
|
2703
|
+
/**
|
|
2704
|
+
* Pet Purchase Request Builder (Kind 5900, action type 9)
|
|
2705
|
+
*
|
|
2706
|
+
* Builds unsigned Kind 5900 Nostr events for pet transfer-ownership
|
|
2707
|
+
* purchase requests. Action type 9 is a reserved slot in the pet DVM
|
|
2708
|
+
* protocol — this event signals purchase intent and routes ILP payment
|
|
2709
|
+
* to the seller. The actual Mina on-chain ownership transfer (PetZkApp
|
|
2710
|
+
* .transferOperator) is handled by downstream stories.
|
|
2711
|
+
*
|
|
2712
|
+
* Browser-compatible — no Node.js-only imports.
|
|
2713
|
+
*
|
|
2714
|
+
* @module pet/buildPetPurchaseRequest
|
|
2715
|
+
*/
|
|
2716
|
+
|
|
2717
|
+
/**
|
|
2718
|
+
* Build an unsigned Kind 5900 pet purchase request event.
|
|
2719
|
+
*
|
|
2720
|
+
* Reuses the existing pet interaction event kind (5900) with action type 9
|
|
2721
|
+
* (transfer-ownership). The `listing` tag references the kind:30402 listing
|
|
2722
|
+
* event being purchased. The `p` tag routes ILP payment to the seller.
|
|
2723
|
+
*
|
|
2724
|
+
* The returned event is compatible with nostr-tools `finalizeEvent`.
|
|
2725
|
+
*
|
|
2726
|
+
* @param params - Typed purchase request parameters
|
|
2727
|
+
* @returns Unsigned Nostr event ready for signing and publishing
|
|
2728
|
+
*/
|
|
2729
|
+
declare function buildPetPurchaseRequest(params: PetPurchaseRequestParams): UnsignedNostrEvent;
|
|
1189
2730
|
|
|
1190
2731
|
/**
|
|
1191
2732
|
* Full multi-chain identity derived from a single BIP-39 mnemonic.
|
|
@@ -1384,16 +2925,38 @@ declare function generateMnemonic(): string;
|
|
|
1384
2925
|
* Validate a BIP-39 mnemonic phrase.
|
|
1385
2926
|
*/
|
|
1386
2927
|
declare function validateMnemonic(mnemonic: string): boolean;
|
|
2928
|
+
/**
|
|
2929
|
+
* Synchronously derive ONLY the Nostr secp256k1 key (NIP-06) from a mnemonic.
|
|
2930
|
+
*
|
|
2931
|
+
* The EVM key shares this same secp256k1 key. Solana (Ed25519) and Mina
|
|
2932
|
+
* (Pallas) require async dynamic imports — use {@link deriveFullIdentity} for
|
|
2933
|
+
* those. This sync subset exists so `ToonClient`'s synchronous constructor can
|
|
2934
|
+
* resolve the Nostr/EVM identity from a `mnemonic` config field without an
|
|
2935
|
+
* async factory; the client derives Solana/Mina lazily in `start()`.
|
|
2936
|
+
*/
|
|
2937
|
+
declare function deriveNostrKeyFromMnemonic(mnemonic: string, accountIndex?: number): {
|
|
2938
|
+
secretKey: Uint8Array;
|
|
2939
|
+
pubkey: string;
|
|
2940
|
+
};
|
|
1387
2941
|
/**
|
|
1388
2942
|
* Derive a full multi-chain ToonIdentity from a BIP-39 mnemonic.
|
|
1389
2943
|
*
|
|
2944
|
+
* All four chains vary by `accountIndex` (default 0), matching the SDK's
|
|
2945
|
+
* {@link https://www.npmjs.com/package/@toon-protocol/sdk `fromMnemonicFull`}
|
|
2946
|
+
* path-per-index scheme so a non-zero index produces the SAME addresses as
|
|
2947
|
+
* `fromMnemonicFull(mnemonic, { accountIndex })`. Index 0 is unchanged from the
|
|
2948
|
+
* historical fixed paths (back-compat).
|
|
2949
|
+
*
|
|
1390
2950
|
* Chains derived:
|
|
1391
|
-
* - Nostr (secp256k1): m/44'/1237'/0'/0/
|
|
2951
|
+
* - Nostr (secp256k1): m/44'/1237'/0'/0/{accountIndex}
|
|
1392
2952
|
* - EVM (secp256k1): same key as Nostr
|
|
1393
|
-
* - Solana (Ed25519): m/44'/501'/
|
|
1394
|
-
* - Mina (Pallas): m/44'/12586'/
|
|
2953
|
+
* - Solana (Ed25519): m/44'/501'/{accountIndex}'/0' (SLIP-0010)
|
|
2954
|
+
* - Mina (Pallas): m/44'/12586'/{accountIndex}'/0/0
|
|
2955
|
+
*
|
|
2956
|
+
* @param mnemonic - A valid BIP-39 mnemonic (12 or 24 words).
|
|
2957
|
+
* @param accountIndex - BIP-44 account index (default 0).
|
|
1395
2958
|
*/
|
|
1396
|
-
declare function deriveFullIdentity(mnemonic: string): Promise<ToonIdentity>;
|
|
2959
|
+
declare function deriveFullIdentity(mnemonic: string, accountIndex?: number): Promise<ToonIdentity>;
|
|
1397
2960
|
/**
|
|
1398
2961
|
* Derive a partial identity from an nsec (Nostr-only private key).
|
|
1399
2962
|
* Nostr + EVM share the same secp256k1 key.
|
|
@@ -1441,4 +3004,77 @@ declare function parseBackupPayload(content: string): VaultData;
|
|
|
1441
3004
|
*/
|
|
1442
3005
|
declare function isPrfSupported(): boolean;
|
|
1443
3006
|
|
|
1444
|
-
|
|
3007
|
+
/**
|
|
3008
|
+
* Node-only encrypted mnemonic keystore for @toon-protocol/client.
|
|
3009
|
+
*
|
|
3010
|
+
* Mirrors the Townhouse node wallet crypto (`packages/townhouse/src/wallet/
|
|
3011
|
+
* crypto.ts`): a BIP-39 mnemonic is encrypted at rest with scrypt (KDF) +
|
|
3012
|
+
* AES-256-GCM (authenticated encryption), serialized as JSON, and written to
|
|
3013
|
+
* disk with mode 0o600. Decryption requires the operator password; a wrong
|
|
3014
|
+
* password fails the GCM auth-tag verification and throws.
|
|
3015
|
+
*
|
|
3016
|
+
* This is the Node-side counterpart to the browser Passkey/IndexedDB
|
|
3017
|
+
* `KeyManager`/`KeyVault` flow — it does NOT touch those. It is guarded against
|
|
3018
|
+
* browser bundling: every entry point throws if `node:crypto`/`node:fs` are not
|
|
3019
|
+
* available (e.g. when accidentally imported in a browser bundle).
|
|
3020
|
+
*
|
|
3021
|
+
* @module
|
|
3022
|
+
*/
|
|
3023
|
+
/**
|
|
3024
|
+
* Encrypted keystore file format (JSON, all binary fields base64-encoded).
|
|
3025
|
+
* Wire-compatible with Townhouse's `EncryptedWallet`.
|
|
3026
|
+
*/
|
|
3027
|
+
interface EncryptedKeystore {
|
|
3028
|
+
/** scrypt salt (base64). */
|
|
3029
|
+
salt: string;
|
|
3030
|
+
/** AES-GCM initialization vector (base64). */
|
|
3031
|
+
iv: string;
|
|
3032
|
+
/** AES-256-GCM ciphertext (base64). */
|
|
3033
|
+
ciphertext: string;
|
|
3034
|
+
/** AES-GCM authentication tag (base64). */
|
|
3035
|
+
tag: string;
|
|
3036
|
+
/** Envelope version for forward-compat (currently 1). */
|
|
3037
|
+
version?: number;
|
|
3038
|
+
}
|
|
3039
|
+
/**
|
|
3040
|
+
* Encrypt a mnemonic with a password using scrypt + AES-256-GCM.
|
|
3041
|
+
* Returns the JSON-serializable encrypted envelope (does NOT write to disk).
|
|
3042
|
+
*/
|
|
3043
|
+
declare function encryptMnemonic(mnemonic: string, password: string): EncryptedKeystore;
|
|
3044
|
+
/**
|
|
3045
|
+
* Decrypt an encrypted keystore envelope with a password.
|
|
3046
|
+
* Throws on a wrong password (GCM auth-tag verification failure) or corruption.
|
|
3047
|
+
*/
|
|
3048
|
+
declare function decryptMnemonic(encrypted: EncryptedKeystore, password: string): string;
|
|
3049
|
+
/**
|
|
3050
|
+
* Generate a fresh 12-word BIP-39 mnemonic, encrypt it under `password`, and
|
|
3051
|
+
* write the encrypted keystore to `path` with mode 0o600.
|
|
3052
|
+
*
|
|
3053
|
+
* Returns the mnemonic (for one-time display/backup) alongside the encrypted
|
|
3054
|
+
* envelope. The caller is responsible for displaying the mnemonic securely and
|
|
3055
|
+
* NOT persisting it in plaintext.
|
|
3056
|
+
*/
|
|
3057
|
+
declare function generateKeystore(path: string, password: string): {
|
|
3058
|
+
mnemonic: string;
|
|
3059
|
+
keystore: EncryptedKeystore;
|
|
3060
|
+
};
|
|
3061
|
+
/**
|
|
3062
|
+
* Import an existing BIP-39 mnemonic (12 or 24 words), encrypt it under
|
|
3063
|
+
* `password`, and write the encrypted keystore to `path` with mode 0o600.
|
|
3064
|
+
*
|
|
3065
|
+
* Throws if the mnemonic is not a valid BIP-39 phrase (wrong checksum/word
|
|
3066
|
+
* count) before any file is written.
|
|
3067
|
+
*/
|
|
3068
|
+
declare function importKeystore(path: string, mnemonic: string, password: string): EncryptedKeystore;
|
|
3069
|
+
/**
|
|
3070
|
+
* Load and decrypt a keystore file at `path` with `password`, returning the
|
|
3071
|
+
* plaintext mnemonic. Throws on a wrong password or corruption.
|
|
3072
|
+
*/
|
|
3073
|
+
declare function loadKeystore(path: string, password: string): string;
|
|
3074
|
+
/**
|
|
3075
|
+
* Serialize and write an encrypted keystore to disk with mode 0o600
|
|
3076
|
+
* (owner read/write only), mirroring the Townhouse wallet file permissions.
|
|
3077
|
+
*/
|
|
3078
|
+
declare function writeKeystoreFile(path: string, keystore: EncryptedKeystore): void;
|
|
3079
|
+
|
|
3080
|
+
export { ANON_ASSETS, ANON_VERSION, type AnonAsset, type BackupPayload, type BalanceProofParams, BtpRuntimeClient, type BtpRuntimeClientConfig, type ChainMetadata, type ChainSigner, ChannelManager, type ClaimMessage, type ClientTransportConfig, ConnectorError, type DiscoveredIlpPeer, type EVMClaimMessage, type EncryptedKeystore, EvmSigner, HS_HOSTNAME_MAX_LENGTH, HS_HOSTNAME_REGEX, HttpConnectorAdmin, type HttpConnectorAdminConfig, HttpIlpClient, type HttpIlpClientConfig, HttpRuntimeClient, type HttpRuntimeClientConfig, ILP_CLAIM_HEADER, ILP_CLAIM_WRAPPED_HEADER, ILP_PEER_ID_HEADER, type IlpTransportChoice, type InteractionResultContent, KeyManager, type KeyManagerConfig, type ManagedAnonProxy, type MinaClaimMessage, type MinaDepositReader, MinaSigner, type MinaSignerOptions, NetworkError, OnChainChannelClient, type OnChainChannelClientConfig, type PasskeyInfo, type PetDvmProvider, type PetInteractionEventData, type PetInteractionRequestParams, type PetInteractionResultData, type PetListing, type PetListingFilterOptions, type PetListingParams, type PetPurchaseRequestParams, type ProofStatus, type PublishEventResult, type RequestBlobStorageParams, type RequestBlobStorageResult, type RetryOptions, type SelectIlpTransportOptions, type SignedBalanceProof, type SolanaChannelClientOptions, type SolanaClaimMessage, SolanaSigner, type StartManagedAnonProxyOptions, type StatValues, ToonClient, type ToonClientConfig, ToonClientError, type ToonIdentity, type ToonSigners, type ToonStartResult, type UnsignedNostrEvent, ValidationError, type VaultData, applyDefaults, applyNetworkPresets, assertRoutableHsHostname, buildBackupEvent, buildBackupFilter, buildPetInteractionRequest, buildPetListingEvent, buildPetPurchaseRequest, buildSettlementInfo, decryptMnemonic, deriveFromNsec, deriveFullIdentity, deriveNostrKeyFromMnemonic, encryptMnemonic, filterPetDvmProviders, filterPetListings, generateKeystore, generateMnemonic, generateRandomIdentity, getNetworkStatus, httpEndpointToBtpUrl, importKeystore, isPrfSupported, isRoutableHsHostname, loadKeystore, parseBackupPayload, parsePetInteractionEvent, parsePetInteractionResult, parsePetListing, readDiscoveredIlpPeer, readMinaDepositTotal, requestBlobStorage, selectAnonAsset, selectIlpTransport, startManagedAnonProxy, validateConfig, validateMnemonic, withRetry, writeKeystoreFile };
|