@1sat/wallet-toolbox 0.0.7 → 0.0.9

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 (57) hide show
  1. package/dist/api/OneSatApi.d.ts +100 -0
  2. package/dist/api/OneSatApi.js +156 -0
  3. package/dist/api/balance/index.d.ts +38 -0
  4. package/dist/api/balance/index.js +82 -0
  5. package/dist/api/broadcast/index.d.ts +22 -0
  6. package/dist/api/broadcast/index.js +45 -0
  7. package/dist/api/constants.d.ts +21 -0
  8. package/dist/api/constants.js +29 -0
  9. package/dist/api/index.d.ts +36 -0
  10. package/dist/api/index.js +38 -0
  11. package/dist/api/inscriptions/index.d.ts +25 -0
  12. package/dist/api/inscriptions/index.js +50 -0
  13. package/dist/api/locks/index.d.ts +44 -0
  14. package/dist/api/locks/index.js +233 -0
  15. package/dist/api/ordinals/index.d.ts +87 -0
  16. package/dist/api/ordinals/index.js +446 -0
  17. package/dist/api/payments/index.d.ts +37 -0
  18. package/dist/api/payments/index.js +130 -0
  19. package/dist/api/signing/index.d.ts +32 -0
  20. package/dist/api/signing/index.js +41 -0
  21. package/dist/api/tokens/index.d.ts +88 -0
  22. package/dist/api/tokens/index.js +400 -0
  23. package/dist/cwi/chrome.d.ts +11 -0
  24. package/dist/cwi/chrome.js +39 -0
  25. package/dist/cwi/event.d.ts +11 -0
  26. package/dist/cwi/event.js +38 -0
  27. package/dist/cwi/factory.d.ts +14 -0
  28. package/dist/cwi/factory.js +44 -0
  29. package/dist/cwi/index.d.ts +11 -0
  30. package/dist/cwi/index.js +11 -0
  31. package/dist/cwi/types.d.ts +39 -0
  32. package/dist/cwi/types.js +39 -0
  33. package/dist/index.d.ts +2 -1
  34. package/dist/index.js +5 -1
  35. package/dist/indexers/Bsv21Indexer.js +1 -1
  36. package/dist/indexers/CosignIndexer.js +2 -1
  37. package/dist/indexers/InscriptionIndexer.js +4 -5
  38. package/dist/indexers/LockIndexer.js +2 -1
  39. package/dist/indexers/MapIndexer.js +1 -1
  40. package/dist/indexers/OrdLockIndexer.js +2 -1
  41. package/dist/indexers/OriginIndexer.js +1 -1
  42. package/dist/indexers/index.d.ts +1 -1
  43. package/dist/indexers/types.d.ts +18 -0
  44. package/dist/services/OneSatServices.d.ts +19 -10
  45. package/dist/services/OneSatServices.js +201 -39
  46. package/dist/services/client/ChaintracksClient.d.ts +55 -13
  47. package/dist/services/client/ChaintracksClient.js +123 -28
  48. package/dist/services/client/OrdfsClient.d.ts +2 -2
  49. package/dist/services/client/OrdfsClient.js +4 -3
  50. package/dist/services/client/TxoClient.js +9 -0
  51. package/dist/sync/AddressManager.d.ts +85 -0
  52. package/dist/sync/AddressManager.js +107 -0
  53. package/dist/sync/SyncManager.d.ts +207 -0
  54. package/dist/sync/SyncManager.js +507 -0
  55. package/dist/sync/index.d.ts +4 -0
  56. package/dist/sync/index.js +2 -0
  57. package/package.json +5 -4
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Locks Module
3
+ *
4
+ * Functions for time-locking BSV.
5
+ */
6
+ import { type WalletInterface, type WalletOutput } from "@bsv/sdk";
7
+ export interface LockBsvRequest {
8
+ /** Amount in satoshis to lock */
9
+ satoshis: number;
10
+ /** Block height until which to lock */
11
+ until: number;
12
+ }
13
+ export interface LockData {
14
+ /** Total locked satoshis */
15
+ totalLocked: number;
16
+ /** Unlockable satoshis (matured locks) */
17
+ unlockable: number;
18
+ /** Next unlock block height */
19
+ nextUnlock: number;
20
+ }
21
+ export interface LockOperationResponse {
22
+ txid?: string;
23
+ rawtx?: string;
24
+ error?: string;
25
+ }
26
+ /**
27
+ * List locked outputs from the lock basket.
28
+ * Returns WalletOutput[] directly - use tags for metadata (lock:until:).
29
+ */
30
+ export declare function listLocks(cwi: WalletInterface, limit?: number): Promise<WalletOutput[]>;
31
+ /**
32
+ * Get lock data summary.
33
+ */
34
+ export declare function getLockData(cwi: WalletInterface, chain?: "main" | "test", wocApiKey?: string): Promise<LockData>;
35
+ /**
36
+ * Lock BSV until a block height.
37
+ * Derives lock address using hardcoded keyID.
38
+ */
39
+ export declare function lockBsv(cwi: WalletInterface, requests: LockBsvRequest[]): Promise<LockOperationResponse>;
40
+ /**
41
+ * Unlock matured BSV locks.
42
+ * Uses createSignature with stored keyID to sign unlock transactions.
43
+ */
44
+ export declare function unlockBsv(cwi: WalletInterface, chain?: "main" | "test", wocApiKey?: string): Promise<LockOperationResponse>;
@@ -0,0 +1,233 @@
1
+ /**
2
+ * Locks Module
3
+ *
4
+ * Functions for time-locking BSV.
5
+ */
6
+ import { Hash, PublicKey, Script, Transaction, TransactionSignature, Utils, } from "@bsv/sdk";
7
+ import { LOCK_BASKET, LOCK_PREFIX, LOCK_SUFFIX, MIN_UNLOCK_SATS } from "../constants";
8
+ import { getChainInfo } from "../balance";
9
+ // Hardcoded keyID for all locks - deterministic derivation
10
+ const LOCK_KEY_ID = "lock";
11
+ /**
12
+ * Build lock script for time-locked BSV.
13
+ */
14
+ function buildLockScript(address, until) {
15
+ const pkh = Utils.fromBase58Check(address).data;
16
+ return new Script()
17
+ .writeScript(Script.fromHex(LOCK_PREFIX))
18
+ .writeBin(pkh)
19
+ .writeNumber(until)
20
+ .writeScript(Script.fromHex(LOCK_SUFFIX));
21
+ }
22
+ /**
23
+ * List locked outputs from the lock basket.
24
+ * Returns WalletOutput[] directly - use tags for metadata (lock:until:).
25
+ */
26
+ export async function listLocks(cwi, limit = 10000) {
27
+ const result = await cwi.listOutputs({
28
+ basket: LOCK_BASKET,
29
+ includeTags: true,
30
+ limit,
31
+ });
32
+ return result.outputs;
33
+ }
34
+ /**
35
+ * Get lock data summary.
36
+ */
37
+ export async function getLockData(cwi, chain = "main", wocApiKey) {
38
+ const lockData = { totalLocked: 0, unlockable: 0, nextUnlock: 0 };
39
+ const chainInfo = await getChainInfo(chain, wocApiKey);
40
+ const currentHeight = chainInfo?.blocks || 0;
41
+ const outputs = await listLocks(cwi);
42
+ for (const o of outputs) {
43
+ const lockTag = o.tags?.find((t) => t.startsWith("lock:until:"));
44
+ if (!lockTag)
45
+ continue;
46
+ const until = parseInt(lockTag.slice(11), 10);
47
+ lockData.totalLocked += o.satoshis;
48
+ if (until <= currentHeight) {
49
+ lockData.unlockable += o.satoshis;
50
+ }
51
+ else if (!lockData.nextUnlock || until < lockData.nextUnlock) {
52
+ lockData.nextUnlock = until;
53
+ }
54
+ }
55
+ if (lockData.unlockable < MIN_UNLOCK_SATS * outputs.length) {
56
+ lockData.unlockable = 0;
57
+ }
58
+ return lockData;
59
+ }
60
+ /**
61
+ * Lock BSV until a block height.
62
+ * Derives lock address using hardcoded keyID.
63
+ */
64
+ export async function lockBsv(cwi, requests) {
65
+ try {
66
+ if (!requests || requests.length === 0) {
67
+ return { error: "no-lock-requests" };
68
+ }
69
+ // Derive lock address once (same for all locks)
70
+ const { publicKey } = await cwi.getPublicKey({
71
+ protocolID: [1, "lock"],
72
+ keyID: LOCK_KEY_ID,
73
+ counterparty: "self",
74
+ forSelf: true,
75
+ });
76
+ const lockAddress = PublicKey.fromString(publicKey).toAddress();
77
+ const outputs = [];
78
+ for (const req of requests) {
79
+ if (req.satoshis <= 0)
80
+ return { error: "invalid-satoshis" };
81
+ if (req.until <= 0)
82
+ return { error: "invalid-block-height" };
83
+ const lockingScript = buildLockScript(lockAddress, req.until);
84
+ outputs.push({
85
+ lockingScript: lockingScript.toHex(),
86
+ satoshis: req.satoshis,
87
+ outputDescription: `Lock ${req.satoshis} sats until block ${req.until}`,
88
+ basket: LOCK_BASKET,
89
+ tags: [`lock:until:${req.until}`],
90
+ });
91
+ }
92
+ const result = await cwi.createAction({
93
+ description: `Lock BSV in ${requests.length} output(s)`,
94
+ outputs,
95
+ });
96
+ if (!result.txid) {
97
+ return { error: "no-txid-returned" };
98
+ }
99
+ return { txid: result.txid, rawtx: result.tx ? Utils.toHex(result.tx) : undefined };
100
+ }
101
+ catch (error) {
102
+ return { error: error instanceof Error ? error.message : "unknown-error" };
103
+ }
104
+ }
105
+ /**
106
+ * Unlock matured BSV locks.
107
+ * Uses createSignature with stored keyID to sign unlock transactions.
108
+ */
109
+ export async function unlockBsv(cwi, chain = "main", wocApiKey) {
110
+ try {
111
+ // Get current block height
112
+ const chainInfo = await getChainInfo(chain, wocApiKey);
113
+ const currentHeight = chainInfo?.blocks || 0;
114
+ if (currentHeight === 0) {
115
+ return { error: "could-not-get-block-height" };
116
+ }
117
+ // Get lock outputs from basket
118
+ const result = await cwi.listOutputs({
119
+ basket: LOCK_BASKET,
120
+ includeTags: true,
121
+ include: "locking scripts",
122
+ limit: 10000,
123
+ });
124
+ // Filter for matured locks
125
+ const maturedLocks = [];
126
+ for (const o of result.outputs) {
127
+ const untilTag = o.tags?.find((t) => t.startsWith("lock:until:"));
128
+ if (!untilTag)
129
+ continue;
130
+ const until = parseInt(untilTag.slice(11), 10);
131
+ if (until <= currentHeight) {
132
+ maturedLocks.push({ output: o, until });
133
+ }
134
+ }
135
+ if (maturedLocks.length === 0) {
136
+ return { error: "no-matured-locks" };
137
+ }
138
+ // Check minimum unlock amount
139
+ const totalSats = maturedLocks.reduce((sum, l) => sum + l.output.satoshis, 0);
140
+ if (totalSats < MIN_UNLOCK_SATS * maturedLocks.length) {
141
+ return { error: "insufficient-unlock-amount" };
142
+ }
143
+ // Find max until value for lockTime
144
+ const maxUntil = Math.max(...maturedLocks.map((l) => l.until));
145
+ // Build createAction args
146
+ const createResult = await cwi.createAction({
147
+ description: `Unlock ${maturedLocks.length} lock(s)`,
148
+ inputs: maturedLocks.map((l) => ({
149
+ outpoint: l.output.outpoint,
150
+ inputDescription: "Locked BSV",
151
+ unlockingScriptLength: 180, // sig + pubkey + preimage estimate
152
+ sequenceNumber: 0, // Must be < 0xffffffff for nLockTime
153
+ })),
154
+ outputs: [
155
+ {
156
+ lockingScript: "", // Will be filled by wallet as change
157
+ satoshis: 0, // Will be calculated by wallet
158
+ outputDescription: "Unlocked BSV",
159
+ },
160
+ ],
161
+ lockTime: maxUntil,
162
+ options: { signAndProcess: false },
163
+ });
164
+ if ("error" in createResult && createResult.error) {
165
+ return { error: String(createResult.error) };
166
+ }
167
+ if (!createResult.signableTransaction) {
168
+ return { error: "no-signable-transaction" };
169
+ }
170
+ // Parse transaction from BEEF
171
+ const tx = Transaction.fromBEEF(createResult.signableTransaction.tx);
172
+ // Build unlocking scripts for each input
173
+ const spends = {};
174
+ for (let i = 0; i < maturedLocks.length; i++) {
175
+ const lock = maturedLocks[i];
176
+ const input = tx.inputs[i];
177
+ const lockingScript = Script.fromHex(lock.output.lockingScript);
178
+ // Build preimage for signature
179
+ const preimage = TransactionSignature.format({
180
+ sourceTXID: input.sourceTXID,
181
+ sourceOutputIndex: input.sourceOutputIndex,
182
+ sourceSatoshis: lock.output.satoshis,
183
+ transactionVersion: tx.version,
184
+ otherInputs: tx.inputs.filter((_, idx) => idx !== i),
185
+ outputs: tx.outputs,
186
+ inputIndex: i,
187
+ subscript: lockingScript,
188
+ inputSequence: 0,
189
+ lockTime: tx.lockTime,
190
+ scope: TransactionSignature.SIGHASH_ALL |
191
+ TransactionSignature.SIGHASH_ANYONECANPAY |
192
+ TransactionSignature.SIGHASH_FORKID,
193
+ });
194
+ // Hash preimage for signing
195
+ const sighash = Hash.sha256(Hash.sha256(preimage));
196
+ // Get signature via createSignature using hardcoded keyID
197
+ const { signature } = await cwi.createSignature({
198
+ protocolID: [1, "lock"],
199
+ keyID: LOCK_KEY_ID,
200
+ counterparty: "self",
201
+ hashToDirectlySign: Array.from(sighash),
202
+ });
203
+ // Get public key
204
+ const { publicKey } = await cwi.getPublicKey({
205
+ protocolID: [1, "lock"],
206
+ keyID: LOCK_KEY_ID,
207
+ counterparty: "self",
208
+ forSelf: true,
209
+ });
210
+ // Build unlocking script: <sig> <pubkey> <preimage>
211
+ const unlockingScript = new Script()
212
+ .writeBin(signature)
213
+ .writeBin(Utils.toArray(publicKey, "hex"))
214
+ .writeBin(Array.from(preimage));
215
+ spends[i] = { unlockingScript: unlockingScript.toHex() };
216
+ }
217
+ // Sign and broadcast
218
+ const signResult = await cwi.signAction({
219
+ reference: createResult.signableTransaction.reference,
220
+ spends,
221
+ });
222
+ if ("error" in signResult) {
223
+ return { error: String(signResult.error) };
224
+ }
225
+ return {
226
+ txid: signResult.txid,
227
+ rawtx: signResult.tx ? Utils.toHex(signResult.tx) : undefined,
228
+ };
229
+ }
230
+ catch (error) {
231
+ return { error: error instanceof Error ? error.message : "unknown-error" };
232
+ }
233
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Ordinals Module
3
+ *
4
+ * Functions for managing ordinals/inscriptions.
5
+ * Returns WalletOutput[] directly from the SDK - no custom mapping needed.
6
+ */
7
+ import { type WalletInterface, type WalletOutput, type CreateActionArgs, type ListOutputsArgs } from "@bsv/sdk";
8
+ import type { OneSatServices } from "../../services/OneSatServices";
9
+ export interface TransferOrdinalRequest {
10
+ /** Outpoint of the ordinal to transfer (txid_vout or txid.vout format) */
11
+ outpoint: string;
12
+ /** Destination address or paymail */
13
+ destination: string;
14
+ }
15
+ export interface ListOrdinalRequest {
16
+ /** Outpoint of ordinal to list */
17
+ outpoint: string;
18
+ /** Price in satoshis */
19
+ price: number;
20
+ /** Address that receives payment on purchase (BRC-29 receive address) */
21
+ payAddress: string;
22
+ /** Address that can cancel the listing (optional - derived from CWI if not provided) */
23
+ cancelAddress?: string;
24
+ }
25
+ export interface PurchaseOrdinalRequest {
26
+ /** Outpoint of listing to purchase */
27
+ outpoint: string;
28
+ /** Marketplace address for fees */
29
+ marketplaceAddress?: string;
30
+ /** Marketplace fee rate (0-1) */
31
+ marketplaceRate?: number;
32
+ }
33
+ export interface OrdinalOperationResponse {
34
+ txid?: string;
35
+ rawtx?: string;
36
+ error?: string;
37
+ }
38
+ /**
39
+ * Derive a cancel address for an ordinal listing.
40
+ * Uses the outpoint as keyID with security level 1 (self-only).
41
+ */
42
+ export declare function deriveCancelAddress(cwi: WalletInterface, outpoint: string): Promise<string>;
43
+ /**
44
+ * List ordinals from the 1sat basket.
45
+ * Returns WalletOutput[] directly - use tags for metadata (origin:, type:, name:, own:, list:).
46
+ */
47
+ export declare function listOrdinals(cwi: WalletInterface, options?: Partial<ListOutputsArgs>): Promise<WalletOutput[]>;
48
+ /**
49
+ * Build CreateActionArgs for transferring an ordinal.
50
+ * Does NOT execute - returns params for createAction.
51
+ */
52
+ export declare function buildTransferOrdinal(cwi: WalletInterface, request: TransferOrdinalRequest): Promise<CreateActionArgs | {
53
+ error: string;
54
+ }>;
55
+ /**
56
+ * Build CreateActionArgs for listing an ordinal for sale.
57
+ * Does NOT execute - returns params for createAction.
58
+ * If cancelAddress is not provided, it will be derived from the CWI.
59
+ */
60
+ export declare function buildListOrdinal(cwi: WalletInterface, request: ListOrdinalRequest): Promise<CreateActionArgs | {
61
+ error: string;
62
+ }>;
63
+ /**
64
+ * Transfer an ordinal to a new address.
65
+ */
66
+ export declare function transferOrdinal(cwi: WalletInterface, request: TransferOrdinalRequest): Promise<OrdinalOperationResponse>;
67
+ /**
68
+ * List an ordinal for sale on the global orderbook.
69
+ */
70
+ export declare function listOrdinal(cwi: WalletInterface, request: ListOrdinalRequest): Promise<OrdinalOperationResponse>;
71
+ /**
72
+ * Cancel an ordinal listing.
73
+ * Uses the origin tag to recover the keyID for signing.
74
+ * Cancel unlock script: <sig> <pubkey> OP_1
75
+ */
76
+ export declare function cancelListing(cwi: WalletInterface, outpoint: string): Promise<OrdinalOperationResponse>;
77
+ /**
78
+ * Purchase an ordinal from the global orderbook.
79
+ *
80
+ * Flow:
81
+ * 1. Fetch listing BEEF to get the locking script
82
+ * 2. Decode OrdLock to get price and payout
83
+ * 3. Build P2PKH output for buyer
84
+ * 4. Build payment output for seller
85
+ * 5. Build custom OrdLock purchase unlock (preimage only, no signature)
86
+ */
87
+ export declare function purchaseOrdinal(cwi: WalletInterface, request: PurchaseOrdinalRequest, services?: OneSatServices): Promise<OrdinalOperationResponse>;