@1sat/wallet-toolbox 0.0.75 → 0.0.76

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.
@@ -65,8 +65,9 @@ export const broadcast = {
65
65
  return { txid };
66
66
  }
67
67
  catch (error) {
68
+ console.error("[broadcast]", error);
68
69
  return {
69
- error: error instanceof Error ? error.message : "Unknown error",
70
+ error: error instanceof Error ? error.message : "unknown-error",
70
71
  };
71
72
  }
72
73
  },
@@ -101,6 +101,7 @@ export const inscribe = {
101
101
  };
102
102
  }
103
103
  catch (error) {
104
+ console.error("[inscribe]", error);
104
105
  return {
105
106
  error: error instanceof Error ? error.message : "unknown-error",
106
107
  };
@@ -143,6 +143,7 @@ export const lockBsv = {
143
143
  };
144
144
  }
145
145
  catch (error) {
146
+ console.error("[lockBsv]", error);
146
147
  return {
147
148
  error: error instanceof Error ? error.message : "unknown-error",
148
149
  };
@@ -280,6 +281,7 @@ export const unlockBsv = {
280
281
  };
281
282
  }
282
283
  catch (error) {
284
+ console.error("[unlockBsv]", error);
283
285
  return {
284
286
  error: error instanceof Error ? error.message : "unknown-error",
285
287
  };
@@ -454,6 +454,7 @@ export const transferOrdinals = {
454
454
  };
455
455
  }
456
456
  catch (error) {
457
+ console.error("[transferOrdinals]", error);
457
458
  return {
458
459
  error: error instanceof Error ? error.message : "unknown-error",
459
460
  };
@@ -523,6 +524,7 @@ export const listOrdinal = {
523
524
  };
524
525
  }
525
526
  catch (error) {
527
+ console.error("[listOrdinal]", error);
526
528
  return {
527
529
  error: error instanceof Error ? error.message : "unknown-error",
528
530
  };
@@ -661,6 +663,7 @@ export const cancelListing = {
661
663
  };
662
664
  }
663
665
  catch (error) {
666
+ console.error("[cancelListing]", error);
664
667
  return {
665
668
  error: error instanceof Error ? error.message : "unknown-error",
666
669
  };
@@ -827,6 +830,7 @@ export const purchaseOrdinal = {
827
830
  };
828
831
  }
829
832
  catch (error) {
833
+ console.error("[purchaseOrdinal]", error);
830
834
  return {
831
835
  error: error instanceof Error ? error.message : "unknown-error",
832
836
  };
@@ -126,6 +126,7 @@ export const sendBsv = {
126
126
  };
127
127
  }
128
128
  catch (error) {
129
+ console.error("[sendBsv]", error);
129
130
  return {
130
131
  error: error instanceof Error ? error.message : "unknown-error",
131
132
  };
@@ -178,6 +179,7 @@ export const sendAllBsv = {
178
179
  };
179
180
  }
180
181
  catch (error) {
182
+ console.error("[sendAllBsv]", error);
181
183
  return {
182
184
  error: error instanceof Error ? error.message : "unknown-error",
183
185
  };
@@ -67,6 +67,7 @@ export const signMessage = {
67
67
  };
68
68
  }
69
69
  catch (error) {
70
+ console.error("[signMessage]", error);
70
71
  return {
71
72
  error: error instanceof Error ? error.message : "unknown-error",
72
73
  };
@@ -216,10 +216,11 @@ export const sweepBsv = {
216
216
  };
217
217
  }
218
218
  catch (error) {
219
+ console.error("[sweepBsv]", error);
219
220
  // Log detailed error info for WERR_REVIEW_ACTIONS
220
221
  if (error && typeof error === "object" && "sendWithResults" in error) {
221
222
  const werr = error;
222
- console.error("[sweep] WERR_REVIEW_ACTIONS details:", {
223
+ console.error("[sweepBsv] WERR_REVIEW_ACTIONS details:", {
223
224
  message: werr.message,
224
225
  txid: werr.txid,
225
226
  sendWithResults: JSON.stringify(werr.sendWithResults, null, 2),
@@ -509,6 +510,7 @@ export const sweepOrdinals = {
509
510
  };
510
511
  }
511
512
  catch (error) {
513
+ console.error("[sweepOrdinals]", error);
512
514
  return {
513
515
  error: error instanceof Error ? error.message : "unknown-error",
514
516
  };
@@ -588,6 +590,16 @@ export const sweepBsv21 = {
588
590
  return { error: "token-not-active" };
589
591
  }
590
592
  const { fee_address, fee_per_output } = tokenDetails.status;
593
+ // Validate all input outpoints exist in the overlay
594
+ const candidateOutpoints = inputs.map((i) => i.outpoint);
595
+ const validated = await ctx.services.bsv21.validateOutputs(tokenId, candidateOutpoints, { unspent: true });
596
+ const validSet = new Set(validated.map((v) => v.outpoint));
597
+ const invalidInputs = inputs.filter((i) => !validSet.has(i.outpoint));
598
+ if (invalidInputs.length > 0) {
599
+ return {
600
+ error: `unvalidated-inputs: ${invalidInputs.map((i) => i.outpoint).join(", ")}`,
601
+ };
602
+ }
591
603
  // Parse WIF
592
604
  const privateKey = PrivateKey.fromWif(wif);
593
605
  // Sum all input amounts
@@ -635,7 +647,15 @@ export const sweepBsv21 = {
635
647
  satoshis: 1,
636
648
  outputDescription: `Sweep ${totalAmount} tokens`,
637
649
  basket: BSV21_BASKET,
638
- tags: [`id:${tokenId}`, `amt:${totalAmount}`],
650
+ tags: [
651
+ `id:${tokenId}`,
652
+ `amt:${totalAmount}`,
653
+ `dec:${tokenDetails.token.dec}`,
654
+ ...(tokenDetails.token.sym ? [`sym:${tokenDetails.token.sym}`] : []),
655
+ ...(tokenDetails.token.icon
656
+ ? [`icon:${tokenDetails.token.icon}`]
657
+ : []),
658
+ ],
639
659
  customInstructions: JSON.stringify({
640
660
  protocolID: BSV21_PROTOCOL,
641
661
  keyID,
@@ -716,6 +736,7 @@ export const sweepBsv21 = {
716
736
  };
717
737
  }
718
738
  catch (error) {
739
+ console.error("[sweepBsv21]", error);
719
740
  return {
720
741
  error: error instanceof Error ? error.message : "unknown-error",
721
742
  };
@@ -5,8 +5,7 @@
5
5
  */
6
6
  import { BSV21, OrdLock } from "@bopen-io/templates";
7
7
  import { BigNumber, LockingScript, OP, P2PKH, PublicKey, Transaction, TransactionSignature, UnlockingScript, Utils, } from "@bsv/sdk";
8
- import { deriveFundAddress } from "../../indexers";
9
- import { BSV21_BASKET, BSV21_FEE_SATS, BSV21_PROTOCOL } from "../constants";
8
+ import { BSV21_BASKET, BSV21_PROTOCOL } from "../constants";
10
9
  // ============================================================================
11
10
  // Internal helpers
12
11
  // ============================================================================
@@ -105,31 +104,19 @@ export const getBsv21Balances = {
105
104
  const amtTag = o.tags?.find((t) => t.startsWith("amt:"))?.slice(4);
106
105
  if (!idTag || !amtTag)
107
106
  continue;
108
- const idContent = idTag.slice(3);
109
- const lastColonIdx = idContent.lastIndexOf(":");
110
- if (lastColonIdx === -1)
111
- continue;
112
- const tokenId = idContent.slice(0, lastColonIdx);
113
- const status = idContent.slice(lastColonIdx + 1);
114
- if (status === "invalid")
115
- continue;
116
- const isConfirmed = status === "valid";
107
+ const tokenId = idTag.slice(3);
117
108
  const amt = BigInt(amtTag);
118
109
  const dec = Number.parseInt(o.tags?.find((t) => t.startsWith("dec:"))?.slice(4) || "0", 10);
119
110
  const symTag = o.tags?.find((t) => t.startsWith("sym:"))?.slice(4);
120
111
  const iconTag = o.tags?.find((t) => t.startsWith("icon:"))?.slice(5);
121
112
  const existing = balanceMap.get(tokenId);
122
113
  if (existing) {
123
- if (isConfirmed)
124
- existing.confirmed += amt;
125
- else
126
- existing.pending += amt;
114
+ existing.amt += amt;
127
115
  }
128
116
  else {
129
117
  balanceMap.set(tokenId, {
130
118
  id: tokenId,
131
- confirmed: isConfirmed ? amt : 0n,
132
- pending: isConfirmed ? 0n : amt,
119
+ amt,
133
120
  sym: symTag,
134
121
  icon: iconTag,
135
122
  dec,
@@ -140,11 +127,11 @@ export const getBsv21Balances = {
140
127
  p: "bsv-20",
141
128
  op: "transfer",
142
129
  dec: b.dec,
143
- amt: (b.confirmed + b.pending).toString(),
130
+ amt: b.amt.toString(),
144
131
  id: b.id,
145
132
  sym: b.sym,
146
133
  icon: b.icon,
147
- all: { confirmed: b.confirmed, pending: b.pending },
134
+ all: { confirmed: b.amt, pending: 0n },
148
135
  listed: { confirmed: 0n, pending: 0n },
149
136
  }));
150
137
  },
@@ -191,6 +178,14 @@ export const sendBsv21 = {
191
178
  !/^\d+$/.test(parts[1])) {
192
179
  return { error: "invalid-token-id-format" };
193
180
  }
181
+ if (!ctx.services) {
182
+ return { error: "services-required" };
183
+ }
184
+ const tokenDetails = await ctx.services.bsv21.getTokenDetails(tokenId);
185
+ if (!tokenDetails.status.is_active) {
186
+ return { error: "token-not-active" };
187
+ }
188
+ const { fee_address, fee_per_output } = tokenDetails.status;
194
189
  const result = await ctx.wallet.listOutputs({
195
190
  basket: BSV21_BASKET,
196
191
  includeTags: true,
@@ -201,16 +196,24 @@ export const sendBsv21 = {
201
196
  const idTag = o.tags?.find((t) => t.startsWith("id:"));
202
197
  if (!idTag)
203
198
  return false;
204
- const idContent = idTag.slice(3);
205
- const lastColonIdx = idContent.lastIndexOf(":");
206
- if (lastColonIdx === -1)
207
- return false;
208
- const id = idContent.slice(0, lastColonIdx);
209
- const status = idContent.slice(lastColonIdx + 1);
210
- return id === tokenId && status !== "invalid";
199
+ return idTag.slice(3) === tokenId;
211
200
  });
212
- if (tokenUtxos.length === 0) {
213
- return { error: "no-token-utxos-found" };
201
+ // Batch-validate all candidate outpoints against the overlay
202
+ const validOutpoints = new Set();
203
+ let overlayValidated = false;
204
+ if (ctx.services?.bsv21) {
205
+ const candidateOutpoints = tokenUtxos.map((o) => o.outpoint);
206
+ try {
207
+ const validated = await ctx.services.bsv21.validateOutputs(tokenId, candidateOutpoints, { unspent: true });
208
+ overlayValidated = true;
209
+ for (const v of validated) {
210
+ validOutpoints.add(v.outpoint);
211
+ }
212
+ }
213
+ catch (e) {
214
+ console.error("[sendBsv21] overlay validation error:", e);
215
+ return { error: "overlay-validation-failed" };
216
+ }
214
217
  }
215
218
  const selected = [];
216
219
  let totalIn = 0n;
@@ -221,23 +224,15 @@ export const sendBsv21 = {
221
224
  if (!amtTag)
222
225
  continue;
223
226
  const utxoAmount = BigInt(amtTag.slice(4));
224
- if (ctx.services?.bsv21) {
225
- try {
226
- const [txid] = utxo.outpoint.split("_");
227
- const validation = await ctx.services.bsv21.getTokenByTxid(tokenId, txid);
228
- const outputData = validation.outputs.find((o) => `${validation.txid}_${o.vout}` === utxo.outpoint);
229
- if (!outputData)
230
- continue;
231
- }
232
- catch {
233
- continue;
234
- }
227
+ // Skip UTXOs not confirmed in the overlay
228
+ if (overlayValidated && !validOutpoints.has(utxo.outpoint)) {
229
+ continue;
235
230
  }
236
231
  selected.push(utxo);
237
232
  totalIn += utxoAmount;
238
233
  }
239
234
  if (totalIn < amount) {
240
- return { error: "insufficient-validated-tokens" };
235
+ return { error: "insufficient-tokens" };
241
236
  }
242
237
  let recipientAddress;
243
238
  if (counterparty) {
@@ -267,16 +262,10 @@ export const sendBsv21 = {
267
262
  satoshis: 1,
268
263
  outputDescription: `Send ${amount} tokens`,
269
264
  });
270
- // Fee output to overlay fund address
271
- const fundAddress = deriveFundAddress(tokenId);
272
- outputs.push({
273
- lockingScript: p2pkh.lock(fundAddress).toHex(),
274
- satoshis: BSV21_FEE_SATS,
275
- outputDescription: "Overlay processing fee",
276
- tags: [],
277
- });
278
265
  const change = totalIn - amount;
266
+ let tokenOutputCount = 1;
279
267
  if (change > 0n) {
268
+ tokenOutputCount = 2;
280
269
  const changeKeyID = `${tokenId}-${Date.now()}`;
281
270
  const { publicKey } = await ctx.wallet.getPublicKey({
282
271
  protocolID: BSV21_PROTOCOL,
@@ -292,15 +281,31 @@ export const sendBsv21 = {
292
281
  satoshis: 1,
293
282
  outputDescription: "Token change",
294
283
  basket: BSV21_BASKET,
295
- tags: [`id:${tokenId}`, `amt:${change}`],
284
+ tags: [
285
+ `id:${tokenId}`,
286
+ `amt:${change}`,
287
+ `dec:${tokenDetails.token.dec}`,
288
+ ...(tokenDetails.token.sym
289
+ ? [`sym:${tokenDetails.token.sym}`]
290
+ : []),
291
+ ...(tokenDetails.token.icon
292
+ ? [`icon:${tokenDetails.token.icon}`]
293
+ : []),
294
+ ],
296
295
  customInstructions: JSON.stringify({
297
296
  protocolID: BSV21_PROTOCOL,
298
297
  keyID: changeKeyID,
299
298
  }),
300
299
  });
301
300
  }
302
- const symTag = tokenUtxos[0]?.tags?.find((t) => t.startsWith("sym:"));
303
- const symbol = symTag ? symTag.slice(4) : tokenId.slice(0, 8);
301
+ // Fee output to overlay fund address (per token output)
302
+ outputs.push({
303
+ lockingScript: p2pkh.lock(fee_address).toHex(),
304
+ satoshis: fee_per_output * tokenOutputCount,
305
+ outputDescription: "Overlay processing fee",
306
+ tags: [],
307
+ });
308
+ const symbol = tokenDetails.token.sym || tokenId.slice(0, 8);
304
309
  const createResult = await ctx.wallet.createAction({
305
310
  description: `Send ${amount} ${symbol}`,
306
311
  inputs: selected.map((o) => ({
@@ -340,6 +345,7 @@ export const sendBsv21 = {
340
345
  };
341
346
  }
342
347
  catch (error) {
348
+ console.error("[sendBsv21]", error);
343
349
  return {
344
350
  error: error instanceof Error ? error.message : "unknown-error",
345
351
  };
@@ -393,11 +399,13 @@ export const purchaseBsv21 = {
393
399
  const [txid, voutStr] = parts;
394
400
  const vout = Number.parseInt(voutStr, 10);
395
401
  try {
396
- await ctx.services.bsv21.getTokenByTxid(tokenId, txid);
402
+ await ctx.services.bsv21.validateOutput(tokenId, outpoint);
397
403
  }
398
- catch {
404
+ catch (e) {
405
+ console.error("[purchaseBsv21] overlay validation error:", e);
399
406
  return { error: "listing-not-found-in-overlay" };
400
407
  }
408
+ const tokenDetails = await ctx.services.bsv21.getTokenDetails(tokenId);
401
409
  const beef = await ctx.services.getBeefForTxid(txid);
402
410
  const listingBeefTx = beef.findTxid(txid);
403
411
  if (!listingBeefTx?.tx) {
@@ -428,7 +436,15 @@ export const purchaseBsv21 = {
428
436
  satoshis: 1,
429
437
  outputDescription: "Purchased tokens",
430
438
  basket: BSV21_BASKET,
431
- tags: [`id:${tokenId}`, `amt:${tokenAmount}`],
439
+ tags: [
440
+ `id:${tokenId}`,
441
+ `amt:${tokenAmount}`,
442
+ `dec:${tokenDetails.token.dec}`,
443
+ ...(tokenDetails.token.sym ? [`sym:${tokenDetails.token.sym}`] : []),
444
+ ...(tokenDetails.token.icon
445
+ ? [`icon:${tokenDetails.token.icon}`]
446
+ : []),
447
+ ],
432
448
  customInstructions: JSON.stringify({
433
449
  protocolID: BSV21_PROTOCOL,
434
450
  keyID: bsv21KeyID,
@@ -456,6 +472,15 @@ export const purchaseBsv21 = {
456
472
  });
457
473
  }
458
474
  }
475
+ // Fee output to overlay fund address
476
+ if (tokenDetails.status.is_active) {
477
+ outputs.push({
478
+ lockingScript: p2pkh.lock(tokenDetails.status.fee_address).toHex(),
479
+ satoshis: tokenDetails.status.fee_per_output,
480
+ outputDescription: "Overlay processing fee",
481
+ tags: [],
482
+ });
483
+ }
459
484
  const createResult = await ctx.wallet.createAction({
460
485
  description: `Purchase ${tokenAmount} tokens for ${payoutSatoshis} sats`,
461
486
  inputBEEF: beef.toBinary(),
@@ -503,6 +528,7 @@ export const purchaseBsv21 = {
503
528
  };
504
529
  }
505
530
  catch (error) {
531
+ console.error("[purchaseBsv21]", error);
506
532
  return {
507
533
  error: error instanceof Error ? error.message : "unknown-error",
508
534
  };
@@ -77,8 +77,7 @@ export class Bsv21Indexer extends Indexer {
77
77
  return;
78
78
  const tags = [];
79
79
  if (txo.owner && this.owners.has(txo.owner)) {
80
- // Use id:tokenId:status format for querying by token and status
81
- tags.push(`id:${bsv21.id}:${bsv21.status}`);
80
+ tags.push(`id:${bsv21.id}`);
82
81
  tags.push(`amt:${bsv21.amt.toString()}`);
83
82
  // Add metadata tags for efficient querying
84
83
  if (bsv21.sym)
@@ -1,5 +1,23 @@
1
1
  import type { Bsv21TransactionData, ClientOptions, IndexedOutput, TokenDetailResponse } from "../types";
2
2
  import { BaseClient } from "./BaseClient";
3
+ /**
4
+ * Query options for /outputs validation endpoints.
5
+ * All flags default to false on the server.
6
+ */
7
+ export interface OutputQueryOptions {
8
+ /** Filter for unspent outputs only */
9
+ unspent?: boolean;
10
+ /** Include spend txid */
11
+ spend?: boolean;
12
+ /** Include satoshis */
13
+ sats?: boolean;
14
+ /** Include events array */
15
+ events?: boolean;
16
+ /** Include block info */
17
+ block?: boolean;
18
+ /** Comma-separated data tags to include (e.g. 'bsv21') */
19
+ tags?: string;
20
+ }
3
21
  /**
4
22
  * Client for /1sat/bsv21/* routes.
5
23
  * Provides BSV21 token queries.
@@ -66,6 +84,24 @@ export declare class Bsv21Client extends BaseClient {
66
84
  * @param addresses - Array of addresses (max 100)
67
85
  */
68
86
  getHistoryMulti(tokenId: string, lockType: string, addresses: string[]): Promise<IndexedOutput[]>;
87
+ /**
88
+ * Validate specific outpoints against the token's overlay topic.
89
+ * Returns only those found in the overlay. By default returns minimal data
90
+ * (outpoint + score). Use opts to include additional fields.
91
+ * @param tokenId - Token ID (txid_vout format)
92
+ * @param outpoints - Array of outpoints to validate (max 1000)
93
+ * @param opts - Optional query flags for additional data
94
+ */
95
+ validateOutputs(tokenId: string, outpoints: string[], opts?: OutputQueryOptions): Promise<IndexedOutput[]>;
96
+ /**
97
+ * Validate a single outpoint against the token's overlay topic.
98
+ * Returns 404 if not found. By default returns minimal data (outpoint + score).
99
+ * @param tokenId - Token ID (txid_vout format)
100
+ * @param outpoint - Outpoint to validate (txid_vout or txid:vout)
101
+ * @param opts - Optional query flags for additional data
102
+ */
103
+ validateOutput(tokenId: string, outpoint: string, opts?: OutputQueryOptions): Promise<IndexedOutput>;
104
+ private buildOutputQuery;
69
105
  /**
70
106
  * Clear the token details cache
71
107
  */
@@ -100,6 +100,51 @@ export class Bsv21Client extends BaseClient {
100
100
  body: JSON.stringify(addresses),
101
101
  });
102
102
  }
103
+ /**
104
+ * Validate specific outpoints against the token's overlay topic.
105
+ * Returns only those found in the overlay. By default returns minimal data
106
+ * (outpoint + score). Use opts to include additional fields.
107
+ * @param tokenId - Token ID (txid_vout format)
108
+ * @param outpoints - Array of outpoints to validate (max 1000)
109
+ * @param opts - Optional query flags for additional data
110
+ */
111
+ async validateOutputs(tokenId, outpoints, opts) {
112
+ const params = this.buildOutputQuery(opts);
113
+ return this.request(`/${tokenId}/outputs${params}`, {
114
+ method: "POST",
115
+ headers: { "Content-Type": "application/json" },
116
+ body: JSON.stringify(outpoints),
117
+ });
118
+ }
119
+ /**
120
+ * Validate a single outpoint against the token's overlay topic.
121
+ * Returns 404 if not found. By default returns minimal data (outpoint + score).
122
+ * @param tokenId - Token ID (txid_vout format)
123
+ * @param outpoint - Outpoint to validate (txid_vout or txid:vout)
124
+ * @param opts - Optional query flags for additional data
125
+ */
126
+ async validateOutput(tokenId, outpoint, opts) {
127
+ const params = this.buildOutputQuery(opts);
128
+ return this.request(`/${tokenId}/outputs/${outpoint}${params}`);
129
+ }
130
+ buildOutputQuery(opts) {
131
+ if (!opts)
132
+ return "";
133
+ const parts = [];
134
+ if (opts.unspent)
135
+ parts.push("unspent=true");
136
+ if (opts.spend)
137
+ parts.push("spend=true");
138
+ if (opts.sats)
139
+ parts.push("sats=true");
140
+ if (opts.events)
141
+ parts.push("events=true");
142
+ if (opts.block)
143
+ parts.push("block=true");
144
+ if (opts.tags)
145
+ parts.push(`tags=${encodeURIComponent(opts.tags)}`);
146
+ return parts.length > 0 ? `?${parts.join("&")}` : "";
147
+ }
103
148
  /**
104
149
  * Clear the token details cache
105
150
  */
@@ -5,5 +5,5 @@ export { ArcadeClient } from "./ArcadeClient";
5
5
  export { TxoClient } from "./TxoClient";
6
6
  export { OwnerClient } from "./OwnerClient";
7
7
  export { OrdfsClient } from "./OrdfsClient";
8
- export { Bsv21Client } from "./Bsv21Client";
8
+ export { Bsv21Client, type OutputQueryOptions } from "./Bsv21Client";
9
9
  export { OverlayClient } from "./OverlayClient";
@@ -5,7 +5,7 @@
5
5
  * (browser extension) and 1sat-website (React app).
6
6
  */
7
7
  import { PrivateKey } from "@bsv/sdk";
8
- import { Monitor, type PermissionsManagerConfig, StorageClient, Wallet, WalletPermissionsManager, WalletStorageManager } from "@bsv/wallet-toolbox-mobile/out/src/index.client.js";
8
+ import { Monitor, StorageClient, Wallet, WalletStorageManager } from "@bsv/wallet-toolbox-mobile/out/src/index.client.js";
9
9
  import { OneSatServices } from "../services/OneSatServices";
10
10
  import { type FullSyncResult, type FullSyncStage } from "./fullSync";
11
11
  type Chain = "main" | "test";
@@ -17,10 +17,6 @@ export interface WebWalletConfig {
17
17
  privateKey: PrivateKey | string;
18
18
  /** Network: 'main' or 'test' */
19
19
  chain: Chain;
20
- /** Admin originator that bypasses permission checks (e.g., chrome-extension://id or https://wallet.example.com) */
21
- adminOriginator: string;
22
- /** Permission configuration for WalletPermissionsManager */
23
- permissionsConfig: PermissionsManagerConfig;
24
20
  /** Fee model. Default: { model: 'sat/kb', value: 100 } */
25
21
  feeModel?: {
26
22
  model: "sat/kb";
@@ -39,10 +35,8 @@ export interface WebWalletConfig {
39
35
  * Result of wallet creation.
40
36
  */
41
37
  export interface WebWalletResult {
42
- /** Wallet instance with permission management */
43
- wallet: WalletPermissionsManager;
44
- /** Underlying wallet without permission checks (for trusted contexts like sweep-ui) */
45
- rawWallet: Wallet;
38
+ /** Wallet instance */
39
+ wallet: Wallet;
46
40
  /** 1Sat services for API access */
47
41
  services: OneSatServices;
48
42
  /** Monitor for transaction lifecycle (not started - call monitor.startTasks() when ready) */
@@ -57,15 +51,14 @@ export interface WebWalletResult {
57
51
  remoteStorage?: StorageClient;
58
52
  }
59
53
  /**
60
- * Create a web wallet with storage, services, permissions, and monitor.
54
+ * Create a web wallet with storage, services, and monitor.
61
55
  *
62
56
  * @example
63
57
  * ```typescript
64
58
  * const { wallet, services, monitor, destroy } = await createWebWallet({
65
59
  * privateKey: identityWif,
66
60
  * chain: 'main',
67
- * adminOriginator: 'https://wallet.example.com',
68
- * permissionsConfig: DEFAULT_PERMISSIONS_CONFIG,
61
+ * storageIdentityKey: 'device-unique-id',
69
62
  * });
70
63
  *
71
64
  * // Wire up monitor callbacks
@@ -5,7 +5,7 @@
5
5
  * (browser extension) and 1sat-website (React app).
6
6
  */
7
7
  import { KeyDeriver, PrivateKey } from "@bsv/sdk";
8
- import { Monitor, Services, StorageClient, StorageIdb, StorageProvider, Wallet, WalletPermissionsManager, WalletStorageManager, } from "@bsv/wallet-toolbox-mobile/out/src/index.client.js";
8
+ import { Monitor, Services, StorageClient, StorageIdb, StorageProvider, Wallet, WalletStorageManager, } from "@bsv/wallet-toolbox-mobile/out/src/index.client.js";
9
9
  import { OneSatServices } from "../services/OneSatServices";
10
10
  import { fullSync } from "./fullSync";
11
11
  // Default database name for IndexedDB storage
@@ -39,15 +39,14 @@ function parsePrivateKey(input) {
39
39
  }
40
40
  }
41
41
  /**
42
- * Create a web wallet with storage, services, permissions, and monitor.
42
+ * Create a web wallet with storage, services, and monitor.
43
43
  *
44
44
  * @example
45
45
  * ```typescript
46
46
  * const { wallet, services, monitor, destroy } = await createWebWallet({
47
47
  * privateKey: identityWif,
48
48
  * chain: 'main',
49
- * adminOriginator: 'https://wallet.example.com',
50
- * permissionsConfig: DEFAULT_PERMISSIONS_CONFIG,
49
+ * storageIdentityKey: 'device-unique-id',
51
50
  * });
52
51
  *
53
52
  * // Wire up monitor callbacks
@@ -58,7 +57,7 @@ function parsePrivateKey(input) {
58
57
  * ```
59
58
  */
60
59
  export async function createWebWallet(config) {
61
- const { chain, adminOriginator, permissionsConfig } = config;
60
+ const { chain } = config;
62
61
  const feeModel = config.feeModel ?? DEFAULT_FEE_MODEL;
63
62
  // 1. Parse private key and create KeyDeriver
64
63
  const privateKey = parsePrivateKey(config.privateKey);
@@ -75,8 +74,8 @@ export async function createWebWallet(config) {
75
74
  // 4. Create storage manager with local-only storage initially (empty backups)
76
75
  const storage = new WalletStorageManager(identityPubKey, localStorage, []);
77
76
  await storage.makeAvailable();
78
- // 5. Create the underlying Wallet FIRST (needed for StorageClient signing)
79
- const underlyingWallet = new Wallet({
77
+ // 5. Create wallet (needed before StorageClient for signing)
78
+ const wallet = new Wallet({
80
79
  chain,
81
80
  keyDeriver,
82
81
  storage,
@@ -89,7 +88,7 @@ export async function createWebWallet(config) {
89
88
  if (config.remoteStorageUrl) {
90
89
  console.log(`[createWebWallet] Attempting remote storage connection to ${config.remoteStorageUrl}`);
91
90
  try {
92
- remoteClient = new StorageClient(underlyingWallet, config.remoteStorageUrl);
91
+ remoteClient = new StorageClient(wallet, config.remoteStorageUrl);
93
92
  const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error("Remote storage connection timeout")), DEFAULT_REMOTE_STORAGE_TIMEOUT));
94
93
  await Promise.race([remoteClient.makeAvailable(), timeoutPromise]);
95
94
  // Add remote to storage manager - it will partition as conflicting if another device is active
@@ -137,8 +136,8 @@ export async function createWebWallet(config) {
137
136
  // bypass the monitor's onTransactionBroadcasted callback. We detect broadcasts
138
137
  // by checking for txid in the result and sync to backup immediately.
139
138
  if (remoteClient) {
140
- const originalCreateAction = underlyingWallet.createAction.bind(underlyingWallet);
141
- underlyingWallet.createAction = async (args) => {
139
+ const originalCreateAction = wallet.createAction.bind(wallet);
140
+ wallet.createAction = async (args) => {
142
141
  const result = await originalCreateAction(args);
143
142
  if (result.txid) {
144
143
  console.log("[createWebWallet] Broadcast detected in createAction:", result.txid);
@@ -148,8 +147,8 @@ export async function createWebWallet(config) {
148
147
  }
149
148
  return result;
150
149
  };
151
- const originalSignAction = underlyingWallet.signAction.bind(underlyingWallet);
152
- underlyingWallet.signAction = async (args) => {
150
+ const originalSignAction = wallet.signAction.bind(wallet);
151
+ wallet.signAction = async (args) => {
153
152
  const result = await originalSignAction(args);
154
153
  if (result.txid) {
155
154
  console.log("[createWebWallet] Broadcast detected in signAction:", result.txid);
@@ -160,9 +159,7 @@ export async function createWebWallet(config) {
160
159
  return result;
161
160
  };
162
161
  }
163
- // 9. Wrap with permissions manager
164
- const wallet = new WalletPermissionsManager(underlyingWallet, adminOriginator, permissionsConfig);
165
- // 10. Create monitor (not started - consumer calls startTasks() when ready)
162
+ // 9. Create monitor (not started - consumer calls startTasks() when ready)
166
163
  const monitor = new Monitor({
167
164
  chain,
168
165
  services: oneSatServices,
@@ -228,7 +225,7 @@ export async function createWebWallet(config) {
228
225
  const destroy = async () => {
229
226
  monitor.stopTasks();
230
227
  await monitor.destroy();
231
- await underlyingWallet.destroy();
228
+ await wallet.destroy();
232
229
  };
233
230
  // 13. Create fullSync function if remote storage is connected
234
231
  const fullSyncFn = remoteClient
@@ -243,7 +240,6 @@ export async function createWebWallet(config) {
243
240
  : undefined;
244
241
  return {
245
242
  wallet,
246
- rawWallet: underlyingWallet,
247
243
  services: oneSatServices,
248
244
  monitor,
249
245
  destroy,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1sat/wallet-toolbox",
3
- "version": "0.0.75",
3
+ "version": "0.0.76",
4
4
  "description": "BSV wallet library extending @bsv/wallet-toolbox with 1Sat Ordinals protocol support",
5
5
  "author": "1Sat Team",
6
6
  "license": "MIT",