@1sat/wallet-toolbox 0.0.9 → 0.0.11

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 (39) hide show
  1. package/dist/api/balance/index.d.ts +20 -8
  2. package/dist/api/balance/index.js +104 -51
  3. package/dist/api/broadcast/index.d.ts +5 -3
  4. package/dist/api/broadcast/index.js +65 -37
  5. package/dist/api/index.d.ts +16 -15
  6. package/dist/api/index.js +42 -17
  7. package/dist/api/inscriptions/index.d.ts +9 -9
  8. package/dist/api/inscriptions/index.js +79 -31
  9. package/dist/api/locks/index.d.ts +15 -12
  10. package/dist/api/locks/index.js +252 -194
  11. package/dist/api/ordinals/index.d.ts +50 -35
  12. package/dist/api/ordinals/index.js +469 -349
  13. package/dist/api/payments/index.d.ts +15 -4
  14. package/dist/api/payments/index.js +147 -92
  15. package/dist/api/signing/index.d.ts +8 -5
  16. package/dist/api/signing/index.js +70 -33
  17. package/dist/api/skills/registry.d.ts +61 -0
  18. package/dist/api/skills/registry.js +74 -0
  19. package/dist/api/skills/types.d.ts +71 -0
  20. package/dist/api/skills/types.js +14 -0
  21. package/dist/api/sweep/index.d.ts +23 -0
  22. package/dist/api/sweep/index.js +221 -0
  23. package/dist/api/sweep/types.d.ts +30 -0
  24. package/dist/api/sweep/types.js +4 -0
  25. package/dist/api/tokens/index.d.ts +37 -38
  26. package/dist/api/tokens/index.js +398 -341
  27. package/dist/index.d.ts +2 -1
  28. package/dist/index.js +2 -0
  29. package/dist/services/client/OwnerClient.js +4 -0
  30. package/dist/wallet/factory.d.ts +64 -0
  31. package/dist/wallet/factory.js +163 -0
  32. package/dist/wallet/index.d.ts +1 -0
  33. package/dist/wallet/index.js +1 -0
  34. package/package.json +13 -4
  35. package/dist/OneSatWallet.d.ts +0 -316
  36. package/dist/OneSatWallet.js +0 -956
  37. package/dist/api/OneSatApi.d.ts +0 -100
  38. package/dist/api/OneSatApi.js +0 -156
  39. package/dist/indexers/TransactionParser.d.ts +0 -53
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Sweep Module
3
+ *
4
+ * Functions for sweeping assets from external wallets into a BRC-100 wallet.
5
+ */
6
+ import type { OneSatContext, Skill } from "../skills/types";
7
+ import type { IndexedOutput } from "../../services/types";
8
+ import type { SweepBsvRequest, SweepBsvResponse, SweepInput } from "./types";
9
+ export * from "./types";
10
+ /**
11
+ * Prepare sweep inputs from IndexedOutput objects by fetching locking scripts.
12
+ * This extracts locking scripts from the raw transactions in BEEF format.
13
+ */
14
+ export declare function prepareSweepInputs(ctx: OneSatContext, utxos: IndexedOutput[]): Promise<SweepInput[]>;
15
+ /**
16
+ * Sweep BSV from external inputs into the destination wallet.
17
+ *
18
+ * If amount is specified, only that amount is swept and the remainder
19
+ * is returned to the source address. If amount is omitted, all input
20
+ * value is swept (minus fees).
21
+ */
22
+ export declare const sweepBsv: Skill<SweepBsvRequest, SweepBsvResponse>;
23
+ export declare const sweepSkills: Skill<SweepBsvRequest, SweepBsvResponse>[];
@@ -0,0 +1,221 @@
1
+ /**
2
+ * Sweep Module
3
+ *
4
+ * Functions for sweeping assets from external wallets into a BRC-100 wallet.
5
+ */
6
+ import { P2PKH, PrivateKey, Transaction, } from "@bsv/sdk";
7
+ export * from "./types";
8
+ /**
9
+ * Prepare sweep inputs from IndexedOutput objects by fetching locking scripts.
10
+ * This extracts locking scripts from the raw transactions in BEEF format.
11
+ */
12
+ export async function prepareSweepInputs(ctx, utxos) {
13
+ if (!ctx.services) {
14
+ throw new Error("Services required for prepareSweepInputs");
15
+ }
16
+ // Group UTXOs by txid to minimize BEEF fetches
17
+ const byTxid = new Map();
18
+ for (const utxo of utxos) {
19
+ const [txid, voutStr] = utxo.outpoint.split("_");
20
+ const vout = Number.parseInt(voutStr, 10);
21
+ const existing = byTxid.get(txid) ?? [];
22
+ existing.push({ vout, utxo });
23
+ byTxid.set(txid, existing);
24
+ }
25
+ const results = [];
26
+ // Fetch BEEF for each txid and extract locking scripts
27
+ for (const [txid, outputs] of byTxid) {
28
+ const beef = await ctx.services.getBeefForTxid(txid);
29
+ const beefTx = beef.findTxid(txid);
30
+ if (!beefTx?.tx) {
31
+ throw new Error(`Transaction ${txid} not found in BEEF`);
32
+ }
33
+ for (const { vout, utxo } of outputs) {
34
+ const output = beefTx.tx.outputs[vout];
35
+ if (!output) {
36
+ throw new Error(`Output ${vout} not found in transaction ${txid}`);
37
+ }
38
+ results.push({
39
+ outpoint: utxo.outpoint,
40
+ satoshis: utxo.satoshis ?? output.satoshis ?? 0,
41
+ lockingScript: output.lockingScript?.toHex() ?? "",
42
+ });
43
+ }
44
+ }
45
+ return results;
46
+ }
47
+ /**
48
+ * Sweep BSV from external inputs into the destination wallet.
49
+ *
50
+ * If amount is specified, only that amount is swept and the remainder
51
+ * is returned to the source address. If amount is omitted, all input
52
+ * value is swept (minus fees).
53
+ */
54
+ export const sweepBsv = {
55
+ meta: {
56
+ name: "sweepBsv",
57
+ description: "Sweep BSV from external wallet (via WIF) into the connected wallet",
58
+ category: "sweep",
59
+ requiresServices: true,
60
+ inputSchema: {
61
+ type: "object",
62
+ properties: {
63
+ inputs: {
64
+ type: "array",
65
+ description: "UTXOs to sweep (use prepareSweepInputs to build these)",
66
+ items: {
67
+ type: "object",
68
+ properties: {
69
+ outpoint: { type: "string", description: "Outpoint (txid_vout)" },
70
+ satoshis: { type: "integer", description: "Satoshis in output" },
71
+ lockingScript: {
72
+ type: "string",
73
+ description: "Locking script hex",
74
+ },
75
+ },
76
+ required: ["outpoint", "satoshis", "lockingScript"],
77
+ },
78
+ },
79
+ wif: {
80
+ type: "string",
81
+ description: "WIF private key controlling the inputs",
82
+ },
83
+ amount: {
84
+ type: "integer",
85
+ description: "Amount to sweep (satoshis). If omitted, sweeps all input value.",
86
+ },
87
+ },
88
+ required: ["inputs", "wif"],
89
+ },
90
+ },
91
+ async execute(ctx, request) {
92
+ if (!ctx.services) {
93
+ return { error: "services-required" };
94
+ }
95
+ try {
96
+ const { inputs, wif, amount } = request;
97
+ if (!inputs || inputs.length === 0) {
98
+ return { error: "no-inputs" };
99
+ }
100
+ // Parse WIF and derive source address
101
+ const privateKey = PrivateKey.fromWif(wif);
102
+ const sourceAddress = privateKey.toPublicKey().toAddress();
103
+ // Calculate totals
104
+ const inputTotal = inputs.reduce((sum, i) => sum + i.satoshis, 0);
105
+ // Validate amount if specified
106
+ if (amount !== undefined) {
107
+ if (amount <= 0) {
108
+ return { error: "invalid-amount" };
109
+ }
110
+ if (amount > inputTotal) {
111
+ return { error: "insufficient-funds" };
112
+ }
113
+ }
114
+ // Fetch BEEF for all input transactions and merge them
115
+ const txids = [
116
+ ...new Set(inputs.map((i) => i.outpoint.split("_")[0])),
117
+ ];
118
+ console.log(`[sweep] Fetching BEEF for ${txids.length} transactions`);
119
+ // Get first BEEF, then merge others into it
120
+ const firstBeef = await ctx.services.getBeefForTxid(txids[0]);
121
+ for (let i = 1; i < txids.length; i++) {
122
+ const additionalBeef = await ctx.services.getBeefForTxid(txids[i]);
123
+ firstBeef.mergeBeef(additionalBeef);
124
+ }
125
+ console.log(`[sweep] Merged BEEF valid=${firstBeef.isValid()}, txs=${firstBeef.txs.length}`);
126
+ // Build input descriptors (we'll sign after getting the final transaction)
127
+ const inputDescriptors = inputs.map((input) => {
128
+ const [txid, voutStr] = input.outpoint.split("_");
129
+ // Convert outpoint format: our format uses "_" but SDK expects "."
130
+ return {
131
+ outpoint: `${txid}.${voutStr}`,
132
+ inputDescription: "Sweep input",
133
+ unlockingScriptLength: 108, // P2PKH unlocking script length
134
+ sequenceNumber: 0xffffffff,
135
+ };
136
+ });
137
+ const beefData = firstBeef.toBinary();
138
+ // Build outputs array
139
+ const outputs = [];
140
+ // If amount specified, create return output for the difference
141
+ if (amount !== undefined) {
142
+ const returnAmount = inputTotal - amount;
143
+ if (returnAmount > 0) {
144
+ outputs.push({
145
+ lockingScript: new P2PKH().lock(sourceAddress).toHex(),
146
+ satoshis: returnAmount,
147
+ outputDescription: "Return to source",
148
+ });
149
+ }
150
+ }
151
+ // If no amount specified, no outputs - wallet creates change for everything
152
+ // Step 1: Create action to get the signable transaction
153
+ const createResult = await ctx.wallet.createAction({
154
+ description: amount
155
+ ? `Sweep ${amount} sats`
156
+ : `Sweep ${inputTotal} sats`,
157
+ inputBEEF: beefData,
158
+ inputs: inputDescriptors,
159
+ outputs,
160
+ options: { signAndProcess: false },
161
+ });
162
+ if ("error" in createResult && createResult.error) {
163
+ return { error: String(createResult.error) };
164
+ }
165
+ if (!createResult.signableTransaction) {
166
+ return { error: "no-signable-transaction" };
167
+ }
168
+ // Step 2: Sign each input with our external key
169
+ const tx = Transaction.fromBEEF(createResult.signableTransaction.tx);
170
+ console.log(`[sweep] Transaction has ${tx.inputs.length} inputs, ${tx.outputs.length} outputs`);
171
+ // Build a set of outpoints we control (using SDK format with ".")
172
+ const ourOutpoints = new Set(inputs.map((input) => {
173
+ const [txid, vout] = input.outpoint.split("_");
174
+ return `${txid}.${vout}`;
175
+ }));
176
+ // Find and set up P2PKH unlocker on each input we control
177
+ for (let i = 0; i < tx.inputs.length; i++) {
178
+ const txInput = tx.inputs[i];
179
+ const inputOutpoint = `${txInput.sourceTXID}.${txInput.sourceOutputIndex}`;
180
+ const hasSourceTx = !!txInput.sourceTransaction;
181
+ const sourceSatoshis = txInput.sourceTransaction?.outputs[txInput.sourceOutputIndex]?.satoshis;
182
+ console.log(`[sweep] Input ${i}: ${inputOutpoint}, hasSourceTx=${hasSourceTx}, satoshis=${sourceSatoshis}, isOurs=${ourOutpoints.has(inputOutpoint)}`);
183
+ if (ourOutpoints.has(inputOutpoint)) {
184
+ const p2pkh = new P2PKH();
185
+ txInput.unlockingScriptTemplate = p2pkh.unlock(privateKey, "all", // SIGHASH_ALL - commit to outputs (we know them now)
186
+ true);
187
+ }
188
+ }
189
+ // Sign all inputs
190
+ await tx.sign();
191
+ // Extract unlocking scripts for signAction (only for our inputs)
192
+ const spends = {};
193
+ for (let i = 0; i < tx.inputs.length; i++) {
194
+ const txInput = tx.inputs[i];
195
+ const inputOutpoint = `${txInput.sourceTXID}.${txInput.sourceOutputIndex}`;
196
+ if (ourOutpoints.has(inputOutpoint)) {
197
+ spends[i] = { unlockingScript: txInput.unlockingScript?.toHex() ?? "" };
198
+ }
199
+ }
200
+ // Step 3: Complete the action with our signatures
201
+ const signResult = await ctx.wallet.signAction({
202
+ reference: createResult.signableTransaction.reference,
203
+ spends,
204
+ });
205
+ if ("error" in signResult) {
206
+ return { error: String(signResult.error) };
207
+ }
208
+ return {
209
+ txid: signResult.txid,
210
+ beef: signResult.tx ? Array.from(signResult.tx) : undefined,
211
+ };
212
+ }
213
+ catch (error) {
214
+ return {
215
+ error: error instanceof Error ? error.message : "unknown-error",
216
+ };
217
+ }
218
+ },
219
+ };
220
+ // Export skills array for registry
221
+ export const sweepSkills = [sweepBsv];
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Sweep Module Types
3
+ */
4
+ /** Input for sweep operations - a UTXO to be swept */
5
+ export interface SweepInput {
6
+ /** Outpoint in format "txid_vout" */
7
+ outpoint: string;
8
+ /** Satoshis in this output */
9
+ satoshis: number;
10
+ /** Locking script hex */
11
+ lockingScript: string;
12
+ }
13
+ /** Request to sweep BSV funds */
14
+ export interface SweepBsvRequest {
15
+ /** UTXOs to spend from source wallet */
16
+ inputs: SweepInput[];
17
+ /** WIF private key controlling the inputs */
18
+ wif: string;
19
+ /** Amount to sweep (in satoshis). If omitted, sweeps all input value. */
20
+ amount?: number;
21
+ }
22
+ /** Response from sweep operation */
23
+ export interface SweepBsvResponse {
24
+ /** Transaction ID if successful */
25
+ txid?: string;
26
+ /** BEEF (transaction with validity proof) */
27
+ beef?: number[];
28
+ /** Error message if failed */
29
+ error?: string;
30
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Sweep Module Types
3
+ */
4
+ export {};
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * Tokens Module
3
3
  *
4
- * Functions for managing BSV21 tokens.
4
+ * Skills for managing BSV21 tokens.
5
5
  */
6
- import { type WalletInterface, type WalletOutput } from "@bsv/sdk";
7
- import type { OneSatServices } from "../../services/OneSatServices";
6
+ import { type WalletOutput } from "@bsv/sdk";
7
+ import type { Skill } from "../skills/types";
8
+ type PubKeyHex = string;
8
9
  export interface Bsv21Balance {
9
10
  /** Token protocol (bsv-20) */
10
11
  p: string;
@@ -32,57 +33,55 @@ export interface Bsv21Balance {
32
33
  export interface SendBsv21Request {
33
34
  /** Token ID (txid_vout format) */
34
35
  tokenId: string;
35
- /** Destination address */
36
- address: string;
37
36
  /** Amount to send (as bigint or string) */
38
37
  amount: bigint | string;
38
+ /** Recipient's identity public key (preferred) */
39
+ counterparty?: PubKeyHex;
40
+ /** Legacy: raw P2PKH address */
41
+ address?: string;
42
+ /** Paymail address */
43
+ paymail?: string;
44
+ }
45
+ export interface PurchaseBsv21Request {
46
+ /** Token ID (txid_vout format of the deploy transaction) */
47
+ tokenId: string;
48
+ /** Outpoint of listed token UTXO (OrdLock containing BSV21) */
49
+ outpoint: string;
50
+ /** Amount of tokens in the listing */
51
+ amount: bigint | string;
52
+ /** Optional marketplace fee address */
53
+ marketplaceAddress?: string;
54
+ /** Optional marketplace fee rate (0-1) */
55
+ marketplaceRate?: number;
39
56
  }
40
57
  export interface TokenOperationResponse {
41
58
  txid?: string;
42
59
  rawtx?: string;
43
60
  error?: string;
44
61
  }
62
+ /** Input for listTokens skill */
63
+ export interface ListTokensInput {
64
+ /** Max number of tokens to return */
65
+ limit?: number;
66
+ }
45
67
  /**
46
- * List BSV21 token outputs from the bsv21 basket.
47
- * Returns WalletOutput[] directly - use tags for metadata.
68
+ * List BSV21 token outputs from the wallet.
48
69
  */
49
- export declare function listTokens(cwi: WalletInterface, limit?: number): Promise<WalletOutput[]>;
70
+ export declare const listTokens: Skill<ListTokensInput, WalletOutput[]>;
71
+ /** Input for getBsv21Balances skill (no required params) */
72
+ export type GetBsv21BalancesInput = Record<string, never>;
50
73
  /**
51
74
  * Get aggregated BSV21 token balances.
52
- * Groups outputs by token ID and sums amounts.
53
75
  */
54
- export declare function getBsv21Balances(cwi: WalletInterface): Promise<Bsv21Balance[]>;
76
+ export declare const getBsv21Balances: Skill<GetBsv21BalancesInput, Bsv21Balance[]>;
55
77
  /**
56
78
  * Send BSV21 tokens to an address.
57
- *
58
- * Flow:
59
- * 1. Get token UTXOs from basket
60
- * 2. Validate each with BSV21 service
61
- * 3. Select UTXOs until we have enough tokens
62
- * 4. Build transfer inscription outputs
63
- * 5. Create and sign transaction
64
79
  */
65
- export declare function sendBsv21(cwi: WalletInterface, request: SendBsv21Request, services?: OneSatServices): Promise<TokenOperationResponse>;
66
- export interface PurchaseBsv21Request {
67
- /** Token ID (txid_vout format of the deploy transaction) */
68
- tokenId: string;
69
- /** Outpoint of listed token UTXO (OrdLock containing BSV21) */
70
- outpoint: string;
71
- /** Amount of tokens in the listing */
72
- amount: bigint | string;
73
- /** Optional marketplace fee address */
74
- marketplaceAddress?: string;
75
- /** Optional marketplace fee rate (0-1) */
76
- marketplaceRate?: number;
77
- }
80
+ export declare const sendBsv21: Skill<SendBsv21Request, TokenOperationResponse>;
78
81
  /**
79
82
  * Purchase BSV21 tokens from marketplace.
80
- *
81
- * Flow:
82
- * 1. Fetch listing BEEF to get the locking script
83
- * 2. Decode OrdLock to get price and payout
84
- * 3. Build BSV21 transfer output for buyer
85
- * 4. Build payment output for seller
86
- * 5. Build custom OrdLock purchase unlock (preimage only, no signature)
87
83
  */
88
- export declare function purchaseBsv21(cwi: WalletInterface, request: PurchaseBsv21Request, services?: OneSatServices): Promise<TokenOperationResponse>;
84
+ export declare const purchaseBsv21: Skill<PurchaseBsv21Request, TokenOperationResponse>;
85
+ /** All token skills for registry */
86
+ export declare const tokensSkills: (Skill<ListTokensInput, WalletOutput[]> | Skill<GetBsv21BalancesInput, Bsv21Balance[]> | Skill<SendBsv21Request, TokenOperationResponse> | Skill<PurchaseBsv21Request, TokenOperationResponse>)[];
87
+ export {};