@1sat/wallet-toolbox 0.0.9 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/balance/index.d.ts +20 -8
- package/dist/api/balance/index.js +104 -51
- package/dist/api/broadcast/index.d.ts +5 -3
- package/dist/api/broadcast/index.js +65 -37
- package/dist/api/index.d.ts +15 -15
- package/dist/api/index.js +38 -17
- package/dist/api/inscriptions/index.d.ts +9 -9
- package/dist/api/inscriptions/index.js +79 -31
- package/dist/api/locks/index.d.ts +15 -12
- package/dist/api/locks/index.js +252 -194
- package/dist/api/ordinals/index.d.ts +50 -35
- package/dist/api/ordinals/index.js +469 -349
- package/dist/api/payments/index.d.ts +15 -4
- package/dist/api/payments/index.js +147 -92
- package/dist/api/signing/index.d.ts +8 -5
- package/dist/api/signing/index.js +70 -33
- package/dist/api/skills/registry.d.ts +61 -0
- package/dist/api/skills/registry.js +74 -0
- package/dist/api/skills/types.d.ts +71 -0
- package/dist/api/skills/types.js +14 -0
- package/dist/api/tokens/index.d.ts +37 -38
- package/dist/api/tokens/index.js +398 -341
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/wallet/factory.d.ts +64 -0
- package/dist/wallet/factory.js +129 -0
- package/dist/wallet/index.d.ts +1 -0
- package/dist/wallet/index.js +1 -0
- package/package.json +10 -1
- package/dist/OneSatWallet.d.ts +0 -316
- package/dist/OneSatWallet.js +0 -956
- package/dist/api/OneSatApi.d.ts +0 -100
- package/dist/api/OneSatApi.js +0 -156
- package/dist/indexers/TransactionParser.d.ts +0 -53
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Locks Module
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Skills for time-locking BSV.
|
|
5
5
|
*/
|
|
6
|
-
import
|
|
6
|
+
import type { Skill } from "../skills/types";
|
|
7
7
|
export interface LockBsvRequest {
|
|
8
8
|
/** Amount in satoshis to lock */
|
|
9
9
|
satoshis: number;
|
|
@@ -23,22 +23,25 @@ export interface LockOperationResponse {
|
|
|
23
23
|
rawtx?: string;
|
|
24
24
|
error?: string;
|
|
25
25
|
}
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
* Returns WalletOutput[] directly - use tags for metadata (lock:until:).
|
|
29
|
-
*/
|
|
30
|
-
export declare function listLocks(cwi: WalletInterface, limit?: number): Promise<WalletOutput[]>;
|
|
26
|
+
/** Input for getLockData skill (no required params) */
|
|
27
|
+
export type GetLockDataInput = Record<string, never>;
|
|
31
28
|
/**
|
|
32
29
|
* Get lock data summary.
|
|
33
30
|
*/
|
|
34
|
-
export declare
|
|
31
|
+
export declare const getLockData: Skill<GetLockDataInput, LockData>;
|
|
32
|
+
/** Input for lockBsv skill */
|
|
33
|
+
export interface LockBsvInput {
|
|
34
|
+
requests: LockBsvRequest[];
|
|
35
|
+
}
|
|
35
36
|
/**
|
|
36
37
|
* Lock BSV until a block height.
|
|
37
|
-
* Derives lock address using hardcoded keyID.
|
|
38
38
|
*/
|
|
39
|
-
export declare
|
|
39
|
+
export declare const lockBsv: Skill<LockBsvInput, LockOperationResponse>;
|
|
40
|
+
/** Input for unlockBsv skill (no required params) */
|
|
41
|
+
export type UnlockBsvInput = Record<string, never>;
|
|
40
42
|
/**
|
|
41
43
|
* Unlock matured BSV locks.
|
|
42
|
-
* Uses createSignature with stored keyID to sign unlock transactions.
|
|
43
44
|
*/
|
|
44
|
-
export declare
|
|
45
|
+
export declare const unlockBsv: Skill<UnlockBsvInput, LockOperationResponse>;
|
|
46
|
+
/** All lock skills for registry */
|
|
47
|
+
export declare const locksSkills: (Skill<GetLockDataInput, LockData> | Skill<LockBsvInput, LockOperationResponse> | Skill<UnlockBsvInput, LockOperationResponse>)[];
|
package/dist/api/locks/index.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Locks Module
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Skills for time-locking BSV.
|
|
5
5
|
*/
|
|
6
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
|
-
|
|
9
|
-
//
|
|
7
|
+
import { LOCK_BASKET, LOCK_PREFIX, LOCK_SUFFIX, MIN_UNLOCK_SATS, WOC_MAINNET_URL, WOC_TESTNET_URL } from "../constants";
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Constants
|
|
10
|
+
// ============================================================================
|
|
11
|
+
const LOCK_PROTOCOL = [1, "lock"];
|
|
10
12
|
const LOCK_KEY_ID = "lock";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Internal helpers
|
|
15
|
+
// ============================================================================
|
|
14
16
|
function buildLockScript(address, until) {
|
|
15
17
|
const pkh = Utils.fromBase58Check(address).data;
|
|
16
18
|
return new Script()
|
|
@@ -19,215 +21,271 @@ function buildLockScript(address, until) {
|
|
|
19
21
|
.writeNumber(until)
|
|
20
22
|
.writeScript(Script.fromHex(LOCK_SUFFIX));
|
|
21
23
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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) {
|
|
24
|
+
async function getChainInfoInternal(chain, wocApiKey) {
|
|
25
|
+
const baseUrl = chain === "main" ? WOC_MAINNET_URL : WOC_TESTNET_URL;
|
|
26
|
+
const headers = {};
|
|
27
|
+
if (wocApiKey)
|
|
28
|
+
headers["woc-api-key"] = wocApiKey;
|
|
65
29
|
try {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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 };
|
|
30
|
+
const response = await fetch(`${baseUrl}/chain/info`, { headers });
|
|
31
|
+
if (!response.ok)
|
|
32
|
+
return null;
|
|
33
|
+
return await response.json();
|
|
100
34
|
}
|
|
101
|
-
catch
|
|
102
|
-
return
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
103
37
|
}
|
|
104
38
|
}
|
|
105
39
|
/**
|
|
106
|
-
*
|
|
107
|
-
* Uses createSignature with stored keyID to sign unlock transactions.
|
|
40
|
+
* Get lock data summary.
|
|
108
41
|
*/
|
|
109
|
-
export
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
42
|
+
export const getLockData = {
|
|
43
|
+
meta: {
|
|
44
|
+
name: "getLockData",
|
|
45
|
+
description: "Get summary of time-locked BSV (total, unlockable, next unlock height)",
|
|
46
|
+
category: "locks",
|
|
47
|
+
inputSchema: {
|
|
48
|
+
type: "object",
|
|
49
|
+
properties: {},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
async execute(ctx) {
|
|
53
|
+
const lockData = { totalLocked: 0, unlockable: 0, nextUnlock: 0 };
|
|
54
|
+
const chainInfo = await getChainInfoInternal(ctx.chain, ctx.wocApiKey);
|
|
113
55
|
const currentHeight = chainInfo?.blocks || 0;
|
|
114
|
-
|
|
115
|
-
return { error: "could-not-get-block-height" };
|
|
116
|
-
}
|
|
117
|
-
// Get lock outputs from basket
|
|
118
|
-
const result = await cwi.listOutputs({
|
|
56
|
+
const result = await ctx.wallet.listOutputs({
|
|
119
57
|
basket: LOCK_BASKET,
|
|
120
58
|
includeTags: true,
|
|
121
|
-
include: "locking scripts",
|
|
122
59
|
limit: 10000,
|
|
123
60
|
});
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
const untilTag = o.tags?.find((t) => t.startsWith("lock:until:"));
|
|
61
|
+
const outputs = result.outputs;
|
|
62
|
+
for (const o of outputs) {
|
|
63
|
+
const untilTag = o.tags?.find((t) => t.startsWith("until:"));
|
|
128
64
|
if (!untilTag)
|
|
129
65
|
continue;
|
|
130
|
-
const until = parseInt(untilTag.slice(
|
|
66
|
+
const until = Number.parseInt(untilTag.slice(6), 10);
|
|
67
|
+
lockData.totalLocked += o.satoshis;
|
|
131
68
|
if (until <= currentHeight) {
|
|
132
|
-
|
|
69
|
+
lockData.unlockable += o.satoshis;
|
|
70
|
+
}
|
|
71
|
+
else if (!lockData.nextUnlock || until < lockData.nextUnlock) {
|
|
72
|
+
lockData.nextUnlock = until;
|
|
133
73
|
}
|
|
134
74
|
}
|
|
135
|
-
if (
|
|
136
|
-
|
|
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" };
|
|
75
|
+
if (lockData.unlockable < MIN_UNLOCK_SATS * outputs.length) {
|
|
76
|
+
lockData.unlockable = 0;
|
|
142
77
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
78
|
+
return lockData;
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Lock BSV until a block height.
|
|
83
|
+
*/
|
|
84
|
+
export const lockBsv = {
|
|
85
|
+
meta: {
|
|
86
|
+
name: "lockBsv",
|
|
87
|
+
description: "Lock BSV until a specific block height",
|
|
88
|
+
category: "locks",
|
|
89
|
+
inputSchema: {
|
|
90
|
+
type: "object",
|
|
91
|
+
properties: {
|
|
92
|
+
requests: {
|
|
93
|
+
type: "array",
|
|
94
|
+
description: "Array of lock requests",
|
|
95
|
+
items: {
|
|
96
|
+
type: "object",
|
|
97
|
+
properties: {
|
|
98
|
+
satoshis: { type: "integer", description: "Amount in satoshis to lock" },
|
|
99
|
+
until: { type: "integer", description: "Block height until which to lock" },
|
|
100
|
+
},
|
|
101
|
+
required: ["satoshis", "until"],
|
|
102
|
+
},
|
|
159
103
|
},
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
104
|
+
},
|
|
105
|
+
required: ["requests"],
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
async execute(ctx, input) {
|
|
109
|
+
try {
|
|
110
|
+
const { requests } = input;
|
|
111
|
+
if (!requests || requests.length === 0) {
|
|
112
|
+
return { error: "no-lock-requests" };
|
|
113
|
+
}
|
|
114
|
+
const { publicKey } = await ctx.wallet.getPublicKey({
|
|
115
|
+
protocolID: LOCK_PROTOCOL,
|
|
116
|
+
keyID: LOCK_KEY_ID,
|
|
117
|
+
counterparty: "self",
|
|
118
|
+
forSelf: true,
|
|
119
|
+
});
|
|
120
|
+
const lockAddress = PublicKey.fromString(publicKey).toAddress();
|
|
121
|
+
const outputs = [];
|
|
122
|
+
for (const req of requests) {
|
|
123
|
+
if (req.satoshis <= 0)
|
|
124
|
+
return { error: "invalid-satoshis" };
|
|
125
|
+
if (req.until <= 0)
|
|
126
|
+
return { error: "invalid-block-height" };
|
|
127
|
+
const lockingScript = buildLockScript(lockAddress, req.until);
|
|
128
|
+
outputs.push({
|
|
129
|
+
lockingScript: lockingScript.toHex(),
|
|
130
|
+
satoshis: req.satoshis,
|
|
131
|
+
outputDescription: `Lock ${req.satoshis} sats until block ${req.until}`,
|
|
132
|
+
basket: LOCK_BASKET,
|
|
133
|
+
tags: [`until:${req.until}`],
|
|
134
|
+
customInstructions: JSON.stringify({
|
|
135
|
+
protocolID: LOCK_PROTOCOL,
|
|
136
|
+
keyID: LOCK_KEY_ID,
|
|
137
|
+
}),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
const result = await ctx.wallet.createAction({
|
|
141
|
+
description: `Lock BSV in ${requests.length} output(s)`,
|
|
142
|
+
outputs,
|
|
143
|
+
});
|
|
144
|
+
if (!result.txid) {
|
|
145
|
+
return { error: "no-txid-returned" };
|
|
146
|
+
}
|
|
147
|
+
return { txid: result.txid, rawtx: result.tx ? Utils.toHex(result.tx) : undefined };
|
|
166
148
|
}
|
|
167
|
-
|
|
168
|
-
return { error: "
|
|
149
|
+
catch (error) {
|
|
150
|
+
return { error: error instanceof Error ? error.message : "unknown-error" };
|
|
169
151
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Unlock matured BSV locks.
|
|
156
|
+
*/
|
|
157
|
+
export const unlockBsv = {
|
|
158
|
+
meta: {
|
|
159
|
+
name: "unlockBsv",
|
|
160
|
+
description: "Unlock all matured time-locked BSV",
|
|
161
|
+
category: "locks",
|
|
162
|
+
inputSchema: {
|
|
163
|
+
type: "object",
|
|
164
|
+
properties: {},
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
async execute(ctx) {
|
|
168
|
+
try {
|
|
169
|
+
const chainInfo = await getChainInfoInternal(ctx.chain, ctx.wocApiKey);
|
|
170
|
+
const currentHeight = chainInfo?.blocks || 0;
|
|
171
|
+
if (currentHeight === 0) {
|
|
172
|
+
return { error: "could-not-get-block-height" };
|
|
173
|
+
}
|
|
174
|
+
const result = await ctx.wallet.listOutputs({
|
|
175
|
+
basket: LOCK_BASKET,
|
|
176
|
+
includeTags: true,
|
|
177
|
+
includeCustomInstructions: true,
|
|
178
|
+
include: "locking scripts",
|
|
179
|
+
limit: 10000,
|
|
193
180
|
});
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
181
|
+
const maturedLocks = [];
|
|
182
|
+
for (const o of result.outputs) {
|
|
183
|
+
const untilTag = o.tags?.find((t) => t.startsWith("until:"));
|
|
184
|
+
if (!untilTag)
|
|
185
|
+
continue;
|
|
186
|
+
const until = Number.parseInt(untilTag.slice(6), 10);
|
|
187
|
+
let protocolID = LOCK_PROTOCOL;
|
|
188
|
+
let keyID = LOCK_KEY_ID;
|
|
189
|
+
if (o.customInstructions) {
|
|
190
|
+
const instructions = JSON.parse(o.customInstructions);
|
|
191
|
+
protocolID = instructions.protocolID ?? LOCK_PROTOCOL;
|
|
192
|
+
keyID = instructions.keyID ?? LOCK_KEY_ID;
|
|
193
|
+
}
|
|
194
|
+
if (until <= currentHeight) {
|
|
195
|
+
maturedLocks.push({ output: o, until, protocolID, keyID });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (maturedLocks.length === 0) {
|
|
199
|
+
return { error: "no-matured-locks" };
|
|
200
|
+
}
|
|
201
|
+
const totalSats = maturedLocks.reduce((sum, l) => sum + l.output.satoshis, 0);
|
|
202
|
+
if (totalSats < MIN_UNLOCK_SATS * maturedLocks.length) {
|
|
203
|
+
return { error: "insufficient-unlock-amount" };
|
|
204
|
+
}
|
|
205
|
+
const maxUntil = Math.max(...maturedLocks.map((l) => l.until));
|
|
206
|
+
const createResult = await ctx.wallet.createAction({
|
|
207
|
+
description: `Unlock ${maturedLocks.length} lock(s)`,
|
|
208
|
+
inputs: maturedLocks.map((l) => ({
|
|
209
|
+
outpoint: l.output.outpoint,
|
|
210
|
+
inputDescription: "Locked BSV",
|
|
211
|
+
unlockingScriptLength: 180,
|
|
212
|
+
sequenceNumber: 0,
|
|
213
|
+
})),
|
|
214
|
+
outputs: [
|
|
215
|
+
{
|
|
216
|
+
lockingScript: "",
|
|
217
|
+
satoshis: 0,
|
|
218
|
+
outputDescription: "Unlocked BSV",
|
|
219
|
+
},
|
|
220
|
+
],
|
|
221
|
+
lockTime: maxUntil,
|
|
222
|
+
options: { signAndProcess: false },
|
|
202
223
|
});
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
224
|
+
if ("error" in createResult && createResult.error) {
|
|
225
|
+
return { error: String(createResult.error) };
|
|
226
|
+
}
|
|
227
|
+
if (!createResult.signableTransaction) {
|
|
228
|
+
return { error: "no-signable-transaction" };
|
|
229
|
+
}
|
|
230
|
+
const tx = Transaction.fromBEEF(createResult.signableTransaction.tx);
|
|
231
|
+
const spends = {};
|
|
232
|
+
for (let i = 0; i < maturedLocks.length; i++) {
|
|
233
|
+
const lock = maturedLocks[i];
|
|
234
|
+
const input = tx.inputs[i];
|
|
235
|
+
const lockingScript = Script.fromHex(lock.output.lockingScript);
|
|
236
|
+
const preimage = TransactionSignature.format({
|
|
237
|
+
sourceTXID: input.sourceTXID,
|
|
238
|
+
sourceOutputIndex: input.sourceOutputIndex,
|
|
239
|
+
sourceSatoshis: lock.output.satoshis,
|
|
240
|
+
transactionVersion: tx.version,
|
|
241
|
+
otherInputs: tx.inputs.filter((_, idx) => idx !== i),
|
|
242
|
+
outputs: tx.outputs,
|
|
243
|
+
inputIndex: i,
|
|
244
|
+
subscript: lockingScript,
|
|
245
|
+
inputSequence: 0,
|
|
246
|
+
lockTime: tx.lockTime,
|
|
247
|
+
scope: TransactionSignature.SIGHASH_ALL |
|
|
248
|
+
TransactionSignature.SIGHASH_ANYONECANPAY |
|
|
249
|
+
TransactionSignature.SIGHASH_FORKID,
|
|
250
|
+
});
|
|
251
|
+
const sighash = Hash.sha256(Hash.sha256(preimage));
|
|
252
|
+
const { signature } = await ctx.wallet.createSignature({
|
|
253
|
+
protocolID: lock.protocolID,
|
|
254
|
+
keyID: lock.keyID,
|
|
255
|
+
counterparty: "self",
|
|
256
|
+
hashToDirectlySign: Array.from(sighash),
|
|
257
|
+
});
|
|
258
|
+
const { publicKey } = await ctx.wallet.getPublicKey({
|
|
259
|
+
protocolID: lock.protocolID,
|
|
260
|
+
keyID: lock.keyID,
|
|
261
|
+
counterparty: "self",
|
|
262
|
+
forSelf: true,
|
|
263
|
+
});
|
|
264
|
+
const unlockingScript = new Script()
|
|
265
|
+
.writeBin(signature)
|
|
266
|
+
.writeBin(Utils.toArray(publicKey, "hex"))
|
|
267
|
+
.writeBin(Array.from(preimage));
|
|
268
|
+
spends[i] = { unlockingScript: unlockingScript.toHex() };
|
|
269
|
+
}
|
|
270
|
+
const signResult = await ctx.wallet.signAction({
|
|
271
|
+
reference: createResult.signableTransaction.reference,
|
|
272
|
+
spends,
|
|
209
273
|
});
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
.
|
|
215
|
-
|
|
274
|
+
if ("error" in signResult) {
|
|
275
|
+
return { error: String(signResult.error) };
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
txid: signResult.txid,
|
|
279
|
+
rawtx: signResult.tx ? Utils.toHex(signResult.tx) : undefined,
|
|
280
|
+
};
|
|
216
281
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
reference: createResult.signableTransaction.reference,
|
|
220
|
-
spends,
|
|
221
|
-
});
|
|
222
|
-
if ("error" in signResult) {
|
|
223
|
-
return { error: String(signResult.error) };
|
|
282
|
+
catch (error) {
|
|
283
|
+
return { error: error instanceof Error ? error.message : "unknown-error" };
|
|
224
284
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
233
|
-
}
|
|
285
|
+
},
|
|
286
|
+
};
|
|
287
|
+
// ============================================================================
|
|
288
|
+
// Module exports
|
|
289
|
+
// ============================================================================
|
|
290
|
+
/** All lock skills for registry */
|
|
291
|
+
export const locksSkills = [getLockData, lockBsv, unlockBsv];
|