@arkade-os/sdk 0.4.19 → 0.4.20

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.
Files changed (59) hide show
  1. package/dist/cjs/contracts/contractWatcher.js +7 -1
  2. package/dist/cjs/contracts/handlers/default.js +10 -3
  3. package/dist/cjs/contracts/handlers/helpers.js +47 -5
  4. package/dist/cjs/contracts/handlers/vhtlc.js +4 -2
  5. package/dist/cjs/identity/descriptor.js +98 -0
  6. package/dist/cjs/identity/descriptorProvider.js +2 -0
  7. package/dist/cjs/identity/index.js +15 -1
  8. package/dist/cjs/identity/seedIdentity.js +91 -6
  9. package/dist/cjs/identity/serialize.js +166 -0
  10. package/dist/cjs/identity/staticDescriptorProvider.js +65 -0
  11. package/dist/cjs/index.js +6 -3
  12. package/dist/cjs/providers/ark.js +11 -3
  13. package/dist/cjs/providers/electrum.js +663 -0
  14. package/dist/cjs/providers/indexer.js +5 -1
  15. package/dist/cjs/providers/utils.js +4 -0
  16. package/dist/cjs/wallet/ramps.js +1 -1
  17. package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +10 -0
  18. package/dist/cjs/wallet/serviceWorker/wallet.js +137 -91
  19. package/dist/cjs/wallet/vtxo-manager.js +56 -8
  20. package/dist/cjs/wallet/wallet.js +3 -3
  21. package/dist/cjs/worker/messageBus.js +200 -56
  22. package/dist/esm/contracts/contractWatcher.js +7 -1
  23. package/dist/esm/contracts/handlers/default.js +10 -3
  24. package/dist/esm/contracts/handlers/helpers.js +47 -5
  25. package/dist/esm/contracts/handlers/vhtlc.js +4 -2
  26. package/dist/esm/identity/descriptor.js +92 -0
  27. package/dist/esm/identity/descriptorProvider.js +1 -0
  28. package/dist/esm/identity/index.js +6 -1
  29. package/dist/esm/identity/seedIdentity.js +89 -6
  30. package/dist/esm/identity/serialize.js +159 -0
  31. package/dist/esm/identity/staticDescriptorProvider.js +61 -0
  32. package/dist/esm/index.js +2 -1
  33. package/dist/esm/providers/ark.js +12 -4
  34. package/dist/esm/providers/electrum.js +658 -0
  35. package/dist/esm/providers/indexer.js +6 -2
  36. package/dist/esm/providers/utils.js +3 -0
  37. package/dist/esm/wallet/ramps.js +1 -1
  38. package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +10 -0
  39. package/dist/esm/wallet/serviceWorker/wallet.js +137 -91
  40. package/dist/esm/wallet/vtxo-manager.js +56 -8
  41. package/dist/esm/wallet/wallet.js +3 -3
  42. package/dist/esm/worker/messageBus.js +201 -57
  43. package/dist/types/contracts/handlers/default.d.ts +1 -1
  44. package/dist/types/contracts/handlers/helpers.d.ts +1 -1
  45. package/dist/types/contracts/types.d.ts +11 -3
  46. package/dist/types/identity/descriptor.d.ts +35 -0
  47. package/dist/types/identity/descriptorProvider.d.ts +28 -0
  48. package/dist/types/identity/index.d.ts +7 -1
  49. package/dist/types/identity/seedIdentity.d.ts +41 -4
  50. package/dist/types/identity/serialize.d.ts +84 -0
  51. package/dist/types/identity/staticDescriptorProvider.d.ts +18 -0
  52. package/dist/types/index.d.ts +4 -2
  53. package/dist/types/providers/electrum.d.ts +212 -0
  54. package/dist/types/providers/utils.d.ts +1 -0
  55. package/dist/types/wallet/serviceWorker/wallet-message-handler.d.ts +11 -2
  56. package/dist/types/wallet/serviceWorker/wallet.d.ts +27 -10
  57. package/dist/types/wallet/vtxo-manager.d.ts +2 -0
  58. package/dist/types/worker/messageBus.d.ts +68 -8
  59. package/package.json +3 -2
@@ -0,0 +1,18 @@
1
+ import { Identity } from ".";
2
+ import { DescriptorProvider, DescriptorSigningRequest } from "./descriptorProvider";
3
+ import { Transaction } from "../utils/transaction";
4
+ /**
5
+ * Wraps a legacy Identity (single-key) as a DescriptorProvider.
6
+ * The descriptor is always a simple tr(pubkey) format.
7
+ */
8
+ export declare class StaticDescriptorProvider implements DescriptorProvider {
9
+ private readonly identity;
10
+ private readonly descriptor;
11
+ private readonly pubKeyHex;
12
+ constructor(identity: Identity, pubKeyHex: string);
13
+ static create(identity: Identity): Promise<StaticDescriptorProvider>;
14
+ getSigningDescriptor(): string;
15
+ isOurs(descriptor: string): boolean;
16
+ signWithDescriptor(requests: DescriptorSigningRequest[]): Promise<Transaction[]>;
17
+ signMessageWithDescriptor(descriptor: string, message: Uint8Array, type?: "schnorr" | "ecdsa"): Promise<Uint8Array>;
18
+ }
@@ -22,6 +22,8 @@ import type { MessageTimeouts } from "./wallet/serviceWorker/wallet";
22
22
  import { OnchainWallet } from "./wallet/onchain";
23
23
  import { setupServiceWorker } from "./worker/browser/utils";
24
24
  import { ESPLORA_URL, EsploraProvider, OnchainProvider, ExplorerTransaction } from "./providers/onchain";
25
+ import { ElectrumOnchainProvider, WsElectrumChainSource } from "./providers/electrum";
26
+ import type { TransactionHistory as ElectrumTransactionHistory, BlockHeader as ElectrumBlockHeader, Unspent as ElectrumUnspent } from "./providers/electrum";
25
27
  import { RestArkProvider, ArkProvider, SettlementEvent, SettlementEventType, ArkInfo, SignedIntent, Output, TxNotification, BatchFinalizationEvent, BatchFinalizedEvent, BatchFailedEvent, TreeSigningStartedEvent, TreeNoncesEvent, BatchStartedEvent, TreeTxEvent, TreeSignatureEvent, ScheduledSession, FeeInfo } from "./providers/ark";
26
28
  import { DelegatorProvider, DelegateInfo, DelegateOptions, RestDelegatorProvider } from "./providers/delegator";
27
29
  import { CLTVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CSVMultisigTapscript, decodeTapscript, MultisigTapscript, TapscriptType, ArkTapscript, RelativeTimelock } from "./script/tapscript";
@@ -50,5 +52,5 @@ import { IContractManager } from "./contracts/contractManager";
50
52
  import { closeDatabase, openDatabase } from "./repositories/indexedDB/manager";
51
53
  import { WalletMessageHandler, WalletNotInitializedError, ReadonlyWalletError, DelegatorNotConfiguredError } from "./wallet/serviceWorker/wallet-message-handler";
52
54
  import { MESSAGE_BUS_NOT_INITIALIZED, MessageBusNotInitializedError, ServiceWorkerTimeoutError } from "./worker/errors";
53
- export { Wallet, ReadonlyWallet, SingleKey, ReadonlySingleKey, SeedIdentity, MnemonicIdentity, ReadonlyDescriptorIdentity, isBatchSignable, OnchainWallet, Ramps, VtxoManager, DelegatorManagerImpl, RestDelegatorProvider, ESPLORA_URL, EsploraProvider, RestArkProvider, RestIndexerProvider, ArkAddress, DefaultVtxo, DelegateVtxo, VtxoScript, VHTLC, TxType, IndexerTxType, ChainTxType, SettlementEventType, setupServiceWorker, MessageBus, WalletMessageHandler, WalletNotInitializedError, ReadonlyWalletError, DelegatorNotConfiguredError, MESSAGE_BUS_NOT_INITIALIZED, MessageBusNotInitializedError, ServiceWorkerTimeoutError, ServiceWorkerWallet, ServiceWorkerReadonlyWallet, DEFAULT_MESSAGE_TIMEOUTS, decodeTapscript, MultisigTapscript, CSVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CLTVMultisigTapscript, TapTreeCoder, ArkPsbtFieldKey, ArkPsbtFieldKeyType, setArkPsbtField, getArkPsbtFields, CosignerPublicKey, VtxoTreeExpiry, VtxoTaprootTree, ConditionWitness, buildOffchainTx, verifyTapscriptSignatures, waitForIncomingFunds, hasBoardingTxExpired, combineTapscriptSigs, isVtxoExpiringSoon, isValidArkAddress, ArkNote, networks, closeDatabase, openDatabase, IndexedDBWalletRepository, IndexedDBContractRepository, InMemoryWalletRepository, InMemoryContractRepository, MIGRATION_KEY, migrateWalletRepository, requiresMigration, getMigrationStatus, rollbackMigration, WalletRepositoryImpl, ContractRepositoryImpl, Intent, BIP322, TxTree, P2A, Unroll, Transaction, ArkError, maybeArkError, Batch, validateVtxoTxGraph, validateConnectorsTxGraph, buildForfeitTx, isRecoverable, isSpendable, isSubdust, isExpired, getSequence, ContractManager, ContractWatcher, contractHandlers, DefaultContractHandler, DelegateContractHandler, VHTLCContractHandler, encodeArkContract, decodeArkContract, contractFromArkContract, contractFromArkContractWithAddress, isArkContract, };
54
- export type { Identity, ReadonlyIdentity, BatchSignableIdentity, SignRequest, IWallet, IReadonlyWallet, BaseWalletConfig, WalletConfig, ReadonlyWalletConfig, ProviderClass, ArkTransaction, Coin, ExtendedCoin, ExtendedVirtualCoin, WalletBalance, SendBitcoinParams, SettleParams, Status, VirtualStatus, Outpoint, VirtualCoin, TxKey, TapscriptType, ArkTxInput, OffchainTx, TapLeaves, IncomingFunds, SeedIdentityOptions, MnemonicOptions, NetworkOptions, DescriptorOptions, IndexerProvider, PageResponse, BatchInfo, ChainTx, CommitmentTx, TxHistoryRecord, Vtxo, VtxoChain, Tx, OnchainProvider, ArkProvider, SettlementEvent, FeeInfo, ArkInfo, SignedIntent, Output, TxNotification, ExplorerTransaction, BatchFinalizationEvent, BatchFinalizedEvent, BatchFailedEvent, TreeSigningStartedEvent, TreeNoncesEvent, BatchStartedEvent, TreeTxEvent, TreeSignatureEvent, ScheduledSession, PaginationOptions, SubscriptionResponse, SubscriptionHeartbeat, SubscriptionEvent, Network, NetworkName, ArkTapscript, RelativeTimelock, EncodedVtxoScript, TapLeafScript, SignerSession, TreeNonces, TreePartialSigs, GetVtxosFilter, SettlementConfig, IVtxoManager, Asset, Recipient, IssuanceParams, IssuanceResult, ReissuanceParams, BurnParams, AssetDetails, AssetMetadata, KnownMetadata, Nonces, PartialSig, ArkPsbtFieldCoder, TxTreeNode, AnchorBumper, StorageConfig, Contract, ContractVtxo, ContractState, ContractEvent, ContractEventCallback, ContractBalance, ContractWithVtxos, ContractHandler, IContractManager, PathSelection, PathContext, ContractManagerConfig, CreateContractParams, ContractWatcherConfig, ParsedArkContract, DefaultContractParams, DelegateContractParams, VHTLCContractParams, MessageHandler, RequestEnvelope, ResponseEnvelope, MessageTimeouts, IDelegatorManager, DelegatorProvider, DelegateInfo, DelegateOptions, WalletRepository, ContractRepository, MigrationStatus, };
55
+ export { Wallet, ReadonlyWallet, SingleKey, ReadonlySingleKey, SeedIdentity, MnemonicIdentity, ReadonlyDescriptorIdentity, isBatchSignable, OnchainWallet, Ramps, VtxoManager, DelegatorManagerImpl, RestDelegatorProvider, ESPLORA_URL, EsploraProvider, ElectrumOnchainProvider, WsElectrumChainSource, RestArkProvider, RestIndexerProvider, ArkAddress, DefaultVtxo, DelegateVtxo, VtxoScript, VHTLC, TxType, IndexerTxType, ChainTxType, SettlementEventType, setupServiceWorker, MessageBus, WalletMessageHandler, WalletNotInitializedError, ReadonlyWalletError, DelegatorNotConfiguredError, MESSAGE_BUS_NOT_INITIALIZED, MessageBusNotInitializedError, ServiceWorkerTimeoutError, ServiceWorkerWallet, ServiceWorkerReadonlyWallet, DEFAULT_MESSAGE_TIMEOUTS, decodeTapscript, MultisigTapscript, CSVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CLTVMultisigTapscript, TapTreeCoder, ArkPsbtFieldKey, ArkPsbtFieldKeyType, setArkPsbtField, getArkPsbtFields, CosignerPublicKey, VtxoTreeExpiry, VtxoTaprootTree, ConditionWitness, buildOffchainTx, verifyTapscriptSignatures, waitForIncomingFunds, hasBoardingTxExpired, combineTapscriptSigs, isVtxoExpiringSoon, isValidArkAddress, ArkNote, networks, closeDatabase, openDatabase, IndexedDBWalletRepository, IndexedDBContractRepository, InMemoryWalletRepository, InMemoryContractRepository, MIGRATION_KEY, migrateWalletRepository, requiresMigration, getMigrationStatus, rollbackMigration, WalletRepositoryImpl, ContractRepositoryImpl, Intent, BIP322, TxTree, P2A, Unroll, Transaction, ArkError, maybeArkError, Batch, validateVtxoTxGraph, validateConnectorsTxGraph, buildForfeitTx, isRecoverable, isSpendable, isSubdust, isExpired, getSequence, ContractManager, ContractWatcher, contractHandlers, DefaultContractHandler, DelegateContractHandler, VHTLCContractHandler, encodeArkContract, decodeArkContract, contractFromArkContract, contractFromArkContractWithAddress, isArkContract, };
56
+ export type { Identity, ReadonlyIdentity, BatchSignableIdentity, SignRequest, IWallet, IReadonlyWallet, BaseWalletConfig, WalletConfig, ReadonlyWalletConfig, ProviderClass, ArkTransaction, Coin, ExtendedCoin, ExtendedVirtualCoin, WalletBalance, SendBitcoinParams, SettleParams, Status, VirtualStatus, Outpoint, VirtualCoin, TxKey, TapscriptType, ArkTxInput, OffchainTx, TapLeaves, IncomingFunds, SeedIdentityOptions, MnemonicOptions, NetworkOptions, DescriptorOptions, IndexerProvider, PageResponse, BatchInfo, ChainTx, CommitmentTx, TxHistoryRecord, Vtxo, VtxoChain, Tx, OnchainProvider, ArkProvider, SettlementEvent, FeeInfo, ArkInfo, SignedIntent, Output, TxNotification, ExplorerTransaction, ElectrumTransactionHistory, ElectrumBlockHeader, ElectrumUnspent, BatchFinalizationEvent, BatchFinalizedEvent, BatchFailedEvent, TreeSigningStartedEvent, TreeNoncesEvent, BatchStartedEvent, TreeTxEvent, TreeSignatureEvent, ScheduledSession, PaginationOptions, SubscriptionResponse, SubscriptionHeartbeat, SubscriptionEvent, Network, NetworkName, ArkTapscript, RelativeTimelock, EncodedVtxoScript, TapLeafScript, SignerSession, TreeNonces, TreePartialSigs, GetVtxosFilter, SettlementConfig, IVtxoManager, Asset, Recipient, IssuanceParams, IssuanceResult, ReissuanceParams, BurnParams, AssetDetails, AssetMetadata, KnownMetadata, Nonces, PartialSig, ArkPsbtFieldCoder, TxTreeNode, AnchorBumper, StorageConfig, Contract, ContractVtxo, ContractState, ContractEvent, ContractEventCallback, ContractBalance, ContractWithVtxos, ContractHandler, IContractManager, PathSelection, PathContext, ContractManagerConfig, CreateContractParams, ContractWatcherConfig, ParsedArkContract, DefaultContractParams, DelegateContractParams, VHTLCContractParams, MessageHandler, RequestEnvelope, ResponseEnvelope, MessageTimeouts, IDelegatorManager, DelegatorProvider, DelegateInfo, DelegateOptions, WalletRepository, ContractRepository, MigrationStatus, };
@@ -0,0 +1,212 @@
1
+ import type { ElectrumWS } from "ws-electrumx-client";
2
+ import type { Network } from "../networks";
3
+ import type { Coin } from "../wallet";
4
+ import type { ExplorerTransaction, OnchainProvider } from "./onchain";
5
+ export type TransactionHistory = {
6
+ tx_hash: string;
7
+ height: number;
8
+ fee?: number;
9
+ };
10
+ export type BlockHeader = {
11
+ height: number;
12
+ hex: string;
13
+ };
14
+ export type Unspent = {
15
+ txid: string;
16
+ vout: number;
17
+ witnessUtxo: {
18
+ script: Uint8Array;
19
+ value: bigint;
20
+ };
21
+ };
22
+ type VerboseTransaction = {
23
+ txid: string;
24
+ confirmations: number;
25
+ blockhash?: string;
26
+ blocktime?: number;
27
+ time?: number;
28
+ /** Raw transaction hex. Bitcoin Core's getrawtransaction <tx> 1 always
29
+ * includes this; we use it to derive exact satoshi amounts instead of
30
+ * multiplying the floating-point `value` field by 1e8. */
31
+ hex?: string;
32
+ vout: {
33
+ n: number;
34
+ value: number;
35
+ scriptPubKey: {
36
+ addresses?: string[];
37
+ address?: string;
38
+ hex: string;
39
+ };
40
+ }[];
41
+ vin: {
42
+ txid: string;
43
+ vout: number;
44
+ }[];
45
+ };
46
+ type HeaderSubscribeResult = {
47
+ height: number;
48
+ hex: string;
49
+ };
50
+ /**
51
+ * WebSocket-based Electrum chain source using ws-electrumx-client.
52
+ * Provides low-level methods for the Electrum protocol.
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * import { ElectrumWS } from "ws-electrumx-client";
57
+ * import { WsElectrumChainSource } from "./providers/electrum";
58
+ * import { networks } from "./networks";
59
+ *
60
+ * const ws = new ElectrumWS("wss://electrum.blockstream.info:50004");
61
+ * const chain = new WsElectrumChainSource(ws, networks.bitcoin);
62
+ *
63
+ * const history = await chain.fetchHistories([script]);
64
+ * await chain.close();
65
+ * ```
66
+ */
67
+ export declare class WsElectrumChainSource {
68
+ private ws;
69
+ private network;
70
+ private cachedTip;
71
+ private headersSubscribePromise;
72
+ constructor(ws: ElectrumWS, network: Network);
73
+ fetchTransactions(txids: string[]): Promise<{
74
+ txID: string;
75
+ hex: string;
76
+ }[]>;
77
+ fetchVerboseTransaction(txid: string): Promise<VerboseTransaction>;
78
+ fetchVerboseTransactions(txids: string[]): Promise<VerboseTransaction[]>;
79
+ unsubscribeScriptStatus(script: Uint8Array): Promise<void>;
80
+ subscribeScriptStatus(script: Uint8Array, callback: (scripthash: string, status: string | null) => void): Promise<void>;
81
+ fetchHistories(scripts: Uint8Array[]): Promise<TransactionHistory[][]>;
82
+ fetchHistory(script: Uint8Array): Promise<TransactionHistory[]>;
83
+ fetchBlockHeaders(heights: number[]): Promise<BlockHeader[]>;
84
+ fetchBlockHeader(height: number): Promise<BlockHeader>;
85
+ /**
86
+ * Returns the current chain tip and keeps it fresh via a single
87
+ * server-side subscription. Subsequent calls return the cached tip
88
+ * (updated by background notifications) without round-tripping to the
89
+ * server. Previously each call issued `blockchain.headers.subscribe` as
90
+ * a regular request, leaving a stale subscription on the server every
91
+ * time — under polling that adds up. ws-electrumx-client deduplicates
92
+ * `subscribe()` by method+params, so registering once is enough.
93
+ */
94
+ subscribeHeaders(): Promise<HeaderSubscribeResult>;
95
+ estimateFees(targetNumberBlocks: number): Promise<number>;
96
+ broadcastTransaction(txHex: string): Promise<string>;
97
+ /**
98
+ * Submit a package of raw transactions atomically via Fulcrum's
99
+ * `blockchain.transaction.broadcast_package` method, the on-the-wire
100
+ * equivalent of bitcoind's `submitpackage` RPC.
101
+ *
102
+ * Required for TRUC (BIP 431) 1P1C relay where the parent has zero
103
+ * (or below-minfee) fee and depends on the child to pay for both via
104
+ * CPFP — sequential broadcast cannot work in that case because the
105
+ * parent would be rejected from the mempool on its own.
106
+ *
107
+ * @param txHexes - Topologically sorted raw transactions; child must
108
+ * be the last element. Currently must be a 1P1C pair
109
+ * (length 2). Parents may not depend on each other.
110
+ * @returns The child transaction id (the last entry in the array),
111
+ * computed locally — `broadcast_package` itself returns
112
+ * `{success, errors}` rather than a txid.
113
+ * @throws If the server does not implement `broadcast_package` (e.g.
114
+ * ElectrumX, or older Fulcrum, or Fulcrum backed by bitcoind
115
+ * < v28.0.0). Callers must surface this clearly to users —
116
+ * this method does NOT silently fall back to sequential
117
+ * broadcasts because doing so would let TRUC packages fail
118
+ * in subtle ways.
119
+ * @throws If the server returns `success=false`, surfacing the
120
+ * underlying mempool rejection in the error message.
121
+ */
122
+ broadcastPackage(txHexes: string[]): Promise<string>;
123
+ getRelayFee(): Promise<number>;
124
+ close(): Promise<void>;
125
+ waitForAddressReceivesTx(addr: string): Promise<void>;
126
+ listUnspents(addr: string): Promise<Unspent[]>;
127
+ /**
128
+ * Get the address string for a script output, if decodable.
129
+ */
130
+ addressForScript(scriptHex: string): string | undefined;
131
+ }
132
+ /**
133
+ * Electrum-based implementation of the OnchainProvider interface.
134
+ * Replaces esplora polling with electrum subscriptions where possible.
135
+ *
136
+ * @example
137
+ * ```typescript
138
+ * import { ElectrumWS } from "ws-electrumx-client";
139
+ * import { ElectrumOnchainProvider } from "./providers/electrum";
140
+ * import { networks } from "./networks";
141
+ *
142
+ * const ws = new ElectrumWS("wss://electrum.blockstream.info:50004");
143
+ * const provider = new ElectrumOnchainProvider(ws, networks.bitcoin);
144
+ *
145
+ * const coins = await provider.getCoins("bc1q...");
146
+ * ```
147
+ */
148
+ export declare class ElectrumOnchainProvider implements OnchainProvider {
149
+ private ws;
150
+ private network;
151
+ private chain;
152
+ constructor(ws: ElectrumWS, network: Network);
153
+ getCoins(address: string): Promise<Coin[]>;
154
+ getFeeRate(): Promise<number | undefined>;
155
+ /**
156
+ * Broadcast a single transaction or a TRUC (BIP 431) 1P1C package
157
+ * atomically.
158
+ *
159
+ * **Server requirements for 1P1C packages:** the backing Electrum
160
+ * server must implement `blockchain.transaction.broadcast_package`
161
+ * (Fulcrum ≥ 1.10) and be backed by bitcoind ≥ v28.0.0. ElectrumX
162
+ * does not implement this method. There is **no fallback** to
163
+ * sequential parent-then-child broadcast: TRUC packages typically
164
+ * have a zero-fee parent and would be rejected from the mempool on
165
+ * their own, so a fallback would silently fail in subtle ways.
166
+ * Callers receiving a "method not found" error here should route
167
+ * through a different provider for that submission.
168
+ *
169
+ * @param txs - One transaction (single broadcast) or two
170
+ * topologically-sorted transactions (parent first,
171
+ * child last) for 1P1C package relay.
172
+ * @returns The broadcast txid (or the child txid for 1P1C packages).
173
+ */
174
+ broadcastTransaction(...txs: string[]): Promise<string>;
175
+ getTxOutspends(txid: string): Promise<{
176
+ spent: boolean;
177
+ txid: string;
178
+ }[]>;
179
+ getTransactions(address: string): Promise<ExplorerTransaction[]>;
180
+ /**
181
+ * Map an electrum verbose transaction to the ExplorerTransaction shape.
182
+ *
183
+ * Output values are derived from the raw transaction hex when available,
184
+ * never from the floating-point `value` field returned by the daemon.
185
+ * That field has 8 decimal places and `Math.round(value * 1e8)` is safe
186
+ * in the common case but a footgun for protocol-level money handling —
187
+ * the raw bytes are exact.
188
+ */
189
+ private verboseToExplorer;
190
+ /**
191
+ * Decode `address` into its scriptPubKey, throwing a clear error if the
192
+ * input is malformed. @scure/btc-signer raises a generic decode error
193
+ * which is hard to map back to user input — this wraps it.
194
+ */
195
+ private encodeAddress;
196
+ getTxStatus(txid: string): Promise<{
197
+ confirmed: false;
198
+ } | {
199
+ confirmed: true;
200
+ blockTime: number;
201
+ blockHeight: number;
202
+ }>;
203
+ getChainTip(): Promise<{
204
+ height: number;
205
+ time: number;
206
+ hash: string;
207
+ }>;
208
+ watchAddresses(addresses: string[], eventCallback: (txs: ExplorerTransaction[]) => void): Promise<() => void>;
209
+ /** Close the underlying WebSocket connection. */
210
+ close(): Promise<void>;
211
+ }
212
+ export {};
@@ -5,3 +5,4 @@
5
5
  * where events arrive before iteration begins.
6
6
  */
7
7
  export declare function eventSourceIterator(eventSource: EventSource): AsyncGenerator<MessageEvent, void, unknown>;
8
+ export declare function isEventSourceError(error: unknown): error is Error;
@@ -18,11 +18,19 @@ export declare const DEFAULT_MESSAGE_TAG = "WALLET_UPDATER";
18
18
  export type RequestInitWallet = RequestEnvelope & {
19
19
  type: "INIT_WALLET";
20
20
  payload: {
21
- key: {
21
+ /**
22
+ * Legacy per-request key material. Ignored by the current handler —
23
+ * identity hydration happens during INITIALIZE_MESSAGE_BUS. Retained
24
+ * for wire compatibility with older workers that may still read it.
25
+ * Slated for removal in the next major.
26
+ *
27
+ * @deprecated Identity is now carried by INITIALIZE_MESSAGE_BUS.
28
+ */
29
+ key?: {
22
30
  privateKey: string;
23
31
  } | {
24
32
  publicKey: string;
25
- };
33
+ } | {};
26
34
  arkServerUrl: string;
27
35
  arkServerPublicKey?: string;
28
36
  };
@@ -481,6 +489,7 @@ export declare class WalletMessageHandler implements MessageHandler<WalletUpdate
481
489
  private scheduleForNextTick;
482
490
  private requireWallet;
483
491
  private tagged;
492
+ isLongRunning(message: WalletUpdaterRequest): boolean;
484
493
  handleMessage(message: WalletUpdaterRequest): Promise<WalletUpdaterResponse>;
485
494
  private handleInitWallet;
486
495
  private handleGetBalance;
@@ -1,6 +1,6 @@
1
1
  import { IWallet, WalletBalance, SendBitcoinParams, SettleParams, ArkTransaction, ExtendedCoin, ExtendedVirtualCoin, GetVtxosFilter, StorageConfig, IReadonlyWallet, IReadonlyAssetManager, IAssetManager, Recipient } from "..";
2
2
  import { SettlementEvent } from "../../providers/ark";
3
- import { Identity, ReadonlyIdentity } from "../../identity";
3
+ import { Identity, ReadonlyIdentity, type SerializedIdentity, type LegacySerializedIdentity } from "../../identity";
4
4
  import { WalletRepository } from "../../repositories/walletRepository";
5
5
  import { ContractRepository } from "../../repositories/contractRepository";
6
6
  import { RequestInitWallet, ResponseGetStatus, WalletUpdaterRequest, WalletUpdaterResponse } from "./wallet-message-handler";
@@ -11,9 +11,6 @@ import type { ContractWatcherConfig } from "../../contracts/contractWatcher";
11
11
  type RequestType = WalletUpdaterRequest["type"];
12
12
  export type MessageTimeouts = Partial<Record<RequestType, number>>;
13
13
  export declare const DEFAULT_MESSAGE_TIMEOUTS: Readonly<Record<RequestType, number>>;
14
- type PrivateKeyIdentity = Identity & {
15
- toHex(): string;
16
- };
17
14
  /**
18
15
  * Service Worker-based wallet implementation for browser environments.
19
16
  *
@@ -102,11 +99,7 @@ export type ServiceWorkerWalletSetupOptions = ServiceWorkerWalletOptions & {
102
99
  serviceWorkerActivationTimeoutMs?: number;
103
100
  };
104
101
  type MessageBusInitConfig = {
105
- wallet: {
106
- privateKey: string;
107
- } | {
108
- publicKey: string;
109
- };
102
+ wallet: SerializedIdentity | LegacySerializedIdentity;
110
103
  arkServer: {
111
104
  url: string;
112
105
  publicKey?: string;
@@ -117,6 +110,7 @@ type MessageBusInitConfig = {
117
110
  timeoutMs?: number;
118
111
  settlementConfig?: SettlementConfig | false;
119
112
  watcherConfig?: Partial<Omit<ContractWatcherConfig, "indexerProvider">>;
113
+ messageTimeouts?: Record<string, number>;
120
114
  };
121
115
  export declare class ServiceWorkerReadonlyWallet implements IReadonlyWallet {
122
116
  readonly serviceWorker: ServiceWorker;
@@ -129,6 +123,13 @@ export declare class ServiceWorkerReadonlyWallet implements IReadonlyWallet {
129
123
  protected initWalletPayload: RequestInitWallet["payload"] | null;
130
124
  protected messageBusTimeoutMs?: number;
131
125
  protected messageTimeouts: Record<RequestType, number>;
126
+ protected arkServerUrl?: string;
127
+ protected arkServerPublicKey?: string;
128
+ protected delegatorUrl?: string;
129
+ protected indexerUrl?: string;
130
+ protected esploraUrl?: string;
131
+ protected watcherConfig?: Partial<Omit<ContractWatcherConfig, "indexerProvider">>;
132
+ protected settlementConfig?: SettlementConfig | false;
132
133
  private reinitPromise;
133
134
  private pingPromise;
134
135
  private inflightRequests;
@@ -165,6 +166,21 @@ export declare class ServiceWorkerReadonlyWallet implements IReadonlyWallet {
165
166
  private pingServiceWorker;
166
167
  private sendMessageWithRetry;
167
168
  protected sendMessageWithEvents(request: WalletUpdaterRequest, onEvent: (response: WalletUpdaterResponse) => void, isComplete: (response: WalletUpdaterResponse) => boolean): Promise<WalletUpdaterResponse>;
169
+ /**
170
+ * Produce a serialized envelope for the wallet's identity. The base
171
+ * class always emits a readonly envelope; `ServiceWorkerWallet`
172
+ * overrides to emit a signing envelope.
173
+ */
174
+ protected serializeIdentity(): Promise<SerializedIdentity>;
175
+ /**
176
+ * Return the cached init config, or rebuild one from live instance
177
+ * state when the cache was never populated. Recovery path for
178
+ * SDK-factory-created wallets; manual constructor bypasses do not
179
+ * retain enough state here and will hit the "never initialized" throw.
180
+ */
181
+ protected buildInitConfig(): Promise<MessageBusInitConfig>;
182
+ /** Minimal INIT_WALLET payload used on reinitialize when the cache is gone. */
183
+ protected buildInitWalletPayload(): RequestInitWallet["payload"];
168
184
  private reinitialize;
169
185
  /** Clear cached wallet state from both the page and service worker storage. */
170
186
  clear(): Promise<void>;
@@ -195,8 +211,9 @@ export declare class ServiceWorkerWallet extends ServiceWorkerReadonlyWallet imp
195
211
  readonly identity: Identity;
196
212
  private readonly _assetManager;
197
213
  private readonly hasDelegator;
198
- protected constructor(serviceWorker: ServiceWorker, identity: PrivateKeyIdentity, walletRepository: WalletRepository, contractRepository: ContractRepository, messageTag: string, hasDelegator: boolean);
214
+ protected constructor(serviceWorker: ServiceWorker, identity: Identity, walletRepository: WalletRepository, contractRepository: ContractRepository, messageTag: string, hasDelegator: boolean);
199
215
  get assetManager(): IAssetManager;
216
+ protected serializeIdentity(): Promise<SerializedIdentity>;
200
217
  static create(options: ServiceWorkerWalletCreateOptions): Promise<ServiceWorkerWallet>;
201
218
  /**
202
219
  * Simplified setup method that handles service worker registration
@@ -400,6 +400,8 @@ export declare class VtxoManager implements AsyncDisposable, IVtxoManager {
400
400
  private getBoardingOutputScript;
401
401
  /** Returns the onchain provider for fee estimation and broadcasting. */
402
402
  private getOnchainProvider;
403
+ /** Returns the Ark provider for intent fee and server info lookups. */
404
+ private getArkProvider;
403
405
  /** Returns the Bitcoin network configuration from the wallet. */
404
406
  private getNetwork;
405
407
  /** Returns the wallet's identity for transaction signing. */
@@ -1,4 +1,5 @@
1
1
  import { ArkProvider } from "../providers/ark";
2
+ import { type SerializedIdentity, type LegacySerializedIdentity } from "../identity";
2
3
  import { ReadonlyWallet, Wallet } from "../wallet/wallet";
3
4
  import type { SettlementConfig } from "../wallet/vtxo-manager";
4
5
  import type { ContractWatcherConfig } from "../contracts/contractWatcher";
@@ -45,11 +46,29 @@ export interface MessageHandler<REQ extends RequestEnvelope = RequestEnvelope, R
45
46
  * Handle routed messages from the clients
46
47
  **/
47
48
  handleMessage(message: REQ): Promise<RES | null>;
49
+ /**
50
+ * Optional opt-out from the bus-level message timeout.
51
+ *
52
+ * Long-running flows (e.g. settlement) surrender control to remote peers
53
+ * and can legitimately sit idle for longer than `messageTimeoutMs`. When
54
+ * this returns true, the bus awaits `handleMessage` without a deadline.
55
+ * Defaults to false.
56
+ */
57
+ isLongRunning?(message: REQ): boolean;
48
58
  }
49
59
  type Options = {
50
60
  messageHandlers: MessageHandler[];
51
61
  tickIntervalMs?: number;
52
62
  messageTimeoutMs?: number;
63
+ /**
64
+ * Per-operation timeout overrides. Keys are either message types
65
+ * (e.g. "SETTLE") or handler tags (e.g. "WALLET_UPDATER"). Message-type
66
+ * matches take precedence over tag matches. Unspecified operations use
67
+ * `messageTimeoutMs`. These are treated as defaults: any map supplied
68
+ * via `INITIALIZE_MESSAGE_BUS` overrides per-key and is re-applied on
69
+ * every (re-)init.
70
+ */
71
+ messageTimeoutOverrides?: Record<string, number>;
53
72
  debug?: boolean;
54
73
  buildServices?: (config: Initialize["config"]) => Promise<{
55
74
  arkProvider: ArkProvider;
@@ -61,11 +80,7 @@ type Initialize = {
61
80
  type: "INITIALIZE_MESSAGE_BUS";
62
81
  id: string;
63
82
  config: {
64
- wallet: {
65
- privateKey: string;
66
- } | {
67
- publicKey: string;
68
- };
83
+ wallet: SerializedIdentity | LegacySerializedIdentity;
69
84
  arkServer: {
70
85
  url: string;
71
86
  publicKey?: string;
@@ -75,6 +90,12 @@ type Initialize = {
75
90
  esploraUrl?: string;
76
91
  settlementConfig?: SettlementConfig | false;
77
92
  watcherConfig?: Partial<Omit<ContractWatcherConfig, "indexerProvider">>;
93
+ /**
94
+ * Page-supplied per-operation timeout map. Keys are message types
95
+ * (e.g. "SETTLE"). Overrides constructor-supplied
96
+ * `messageTimeoutOverrides` per-key; re-applied on every init.
97
+ */
98
+ messageTimeouts?: Record<string, number>;
78
99
  };
79
100
  };
80
101
  export declare class MessageBus {
@@ -83,6 +104,9 @@ export declare class MessageBus {
83
104
  private handlers;
84
105
  private tickIntervalMs;
85
106
  private messageTimeoutMs;
107
+ private readonly constructorTimeoutOverrides;
108
+ private messageTimeoutOverrides;
109
+ private lateDeliveries;
86
110
  private running;
87
111
  private tickTimeout;
88
112
  private tickInProgress;
@@ -91,7 +115,7 @@ export declare class MessageBus {
91
115
  private readonly buildServicesFn;
92
116
  private readonly boundOnMessage;
93
117
  /** Create the service-worker message bus with repositories and handler configuration. */
94
- constructor(walletRepository: WalletRepository, contractRepository: ContractRepository, { messageHandlers, tickIntervalMs, messageTimeoutMs, debug, buildServices, }: Options);
118
+ constructor(walletRepository: WalletRepository, contractRepository: ContractRepository, { messageHandlers, tickIntervalMs, messageTimeoutMs, messageTimeoutOverrides, debug, buildServices, }: Options);
95
119
  /** Start the message bus and attach service-worker event listeners. */
96
120
  start(): Promise<void>;
97
121
  /** Stop the message bus, cancel ticks, and stop all registered handlers. */
@@ -104,10 +128,46 @@ export declare class MessageBus {
104
128
  private processMessage;
105
129
  /**
106
130
  * Race `promise` against a timeout. Note: this does NOT cancel the
107
- * underlying work — the original promise keeps running. This is safe
108
- * here because only the caller (not the handler) posts the response.
131
+ * underlying work — the original promise keeps running. Call
132
+ * `attachLateDelivery` after catching the timeout to surface the
133
+ * eventual result so the message id does not go silent.
109
134
  */
110
135
  private withTimeout;
136
+ /**
137
+ * Extract the declared `type` from a request envelope (e.g. "SETTLE").
138
+ * Not every envelope carries a type (PING/INIT are special cased
139
+ * earlier), so this returns undefined for envelopes that lack one.
140
+ */
141
+ private extractMessageType;
142
+ /**
143
+ * Resolve the timeout for an operation. Message-type overrides take
144
+ * precedence over handler-tag overrides, with the bus-wide default
145
+ * (`messageTimeoutMs`) as the final fallback.
146
+ */
147
+ private resolveTimeoutMs;
148
+ /**
149
+ * Build a human-readable label for timeout errors. Format:
150
+ * `"<MESSAGE_TYPE> via <HANDLER_TAG>"` when both are known, else the
151
+ * handler tag alone. Used so timeout errors name the operation the
152
+ * client actually triggered (e.g. SETTLE) rather than just the
153
+ * handler that received it (e.g. WALLET_UPDATER).
154
+ */
155
+ private labelFor;
156
+ /**
157
+ * Post a response to the originating client. When `source` is null
158
+ * (client tab closed, detached frame, etc.) the response cannot be
159
+ * delivered; we log the drop in debug mode so it is not invisible.
160
+ */
161
+ private deliverResponse;
162
+ /**
163
+ * After a handler times out the client has already received a timeout
164
+ * error, but the handler keeps running. Attach a follow-up so the
165
+ * handler's eventual result (or error) is delivered under the same
166
+ * message id, or — if the handler never completes within
167
+ * {@link LATE_DELIVERY_GRACE_MS} — an "Operation abandoned" error is
168
+ * sent so the client's listener (if still attached) does not hang.
169
+ */
170
+ private attachLateDelivery;
111
171
  /**
112
172
  * Returns the registered SW for the path.
113
173
  * It uses the functions in `service-worker-manager.ts` module.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkade-os/sdk",
3
- "version": "0.4.19",
3
+ "version": "0.4.20",
4
4
  "description": "TypeScript SDK for building Bitcoin wallets using the Arkade protocol",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
@@ -87,7 +87,8 @@
87
87
  "@scure/base": "2.0.0",
88
88
  "@scure/bip39": "2.0.1",
89
89
  "@scure/btc-signer": "2.0.1",
90
- "bip68": "1.0.4"
90
+ "bip68": "1.0.4",
91
+ "ws-electrumx-client": "1.0.5"
91
92
  },
92
93
  "devDependencies": {
93
94
  "@types/better-sqlite3": "7.6.13",