openclaw-overlay-plugin 0.7.22
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/README.md +406 -0
- package/SKILL.md +78 -0
- package/clawdbot.plugin.json +106 -0
- package/dist/cli-main.d.ts +7 -0
- package/dist/cli-main.js +192 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +14 -0
- package/dist/core/config.d.ts +11 -0
- package/dist/core/config.js +13 -0
- package/dist/core/index.d.ts +25 -0
- package/dist/core/index.js +26 -0
- package/dist/core/payment.d.ts +16 -0
- package/dist/core/payment.js +94 -0
- package/dist/core/types.d.ts +94 -0
- package/dist/core/types.js +4 -0
- package/dist/core/verify.d.ts +28 -0
- package/dist/core/verify.js +104 -0
- package/dist/core/wallet.d.ts +99 -0
- package/dist/core/wallet.js +219 -0
- package/dist/scripts/baemail/commands.d.ts +64 -0
- package/dist/scripts/baemail/commands.js +258 -0
- package/dist/scripts/baemail/handler.d.ts +36 -0
- package/dist/scripts/baemail/handler.js +284 -0
- package/dist/scripts/baemail/index.d.ts +5 -0
- package/dist/scripts/baemail/index.js +5 -0
- package/dist/scripts/config.d.ts +48 -0
- package/dist/scripts/config.js +68 -0
- package/dist/scripts/index.d.ts +7 -0
- package/dist/scripts/index.js +7 -0
- package/dist/scripts/messaging/connect.d.ts +8 -0
- package/dist/scripts/messaging/connect.js +114 -0
- package/dist/scripts/messaging/handlers.d.ts +21 -0
- package/dist/scripts/messaging/handlers.js +334 -0
- package/dist/scripts/messaging/inbox.d.ts +11 -0
- package/dist/scripts/messaging/inbox.js +51 -0
- package/dist/scripts/messaging/index.d.ts +8 -0
- package/dist/scripts/messaging/index.js +8 -0
- package/dist/scripts/messaging/poll.d.ts +7 -0
- package/dist/scripts/messaging/poll.js +52 -0
- package/dist/scripts/messaging/send.d.ts +7 -0
- package/dist/scripts/messaging/send.js +43 -0
- package/dist/scripts/output.d.ts +12 -0
- package/dist/scripts/output.js +19 -0
- package/dist/scripts/overlay/discover.d.ts +7 -0
- package/dist/scripts/overlay/discover.js +72 -0
- package/dist/scripts/overlay/index.d.ts +7 -0
- package/dist/scripts/overlay/index.js +7 -0
- package/dist/scripts/overlay/registration.d.ts +19 -0
- package/dist/scripts/overlay/registration.js +176 -0
- package/dist/scripts/overlay/services.d.ts +29 -0
- package/dist/scripts/overlay/services.js +167 -0
- package/dist/scripts/overlay/transaction.d.ts +42 -0
- package/dist/scripts/overlay/transaction.js +103 -0
- package/dist/scripts/payment/build.d.ts +24 -0
- package/dist/scripts/payment/build.js +54 -0
- package/dist/scripts/payment/commands.d.ts +15 -0
- package/dist/scripts/payment/commands.js +73 -0
- package/dist/scripts/payment/index.d.ts +6 -0
- package/dist/scripts/payment/index.js +6 -0
- package/dist/scripts/payment/types.d.ts +56 -0
- package/dist/scripts/payment/types.js +4 -0
- package/dist/scripts/services/index.d.ts +6 -0
- package/dist/scripts/services/index.js +6 -0
- package/dist/scripts/services/queue.d.ts +11 -0
- package/dist/scripts/services/queue.js +28 -0
- package/dist/scripts/services/request.d.ts +7 -0
- package/dist/scripts/services/request.js +82 -0
- package/dist/scripts/services/respond.d.ts +11 -0
- package/dist/scripts/services/respond.js +132 -0
- package/dist/scripts/types.d.ts +107 -0
- package/dist/scripts/types.js +4 -0
- package/dist/scripts/utils/index.d.ts +6 -0
- package/dist/scripts/utils/index.js +6 -0
- package/dist/scripts/utils/merkle.d.ts +12 -0
- package/dist/scripts/utils/merkle.js +47 -0
- package/dist/scripts/utils/storage.d.ts +66 -0
- package/dist/scripts/utils/storage.js +211 -0
- package/dist/scripts/utils/woc.d.ts +26 -0
- package/dist/scripts/utils/woc.js +91 -0
- package/dist/scripts/wallet/balance.d.ts +22 -0
- package/dist/scripts/wallet/balance.js +240 -0
- package/dist/scripts/wallet/identity.d.ts +70 -0
- package/dist/scripts/wallet/identity.js +151 -0
- package/dist/scripts/wallet/index.d.ts +6 -0
- package/dist/scripts/wallet/index.js +6 -0
- package/dist/scripts/wallet/setup.d.ts +15 -0
- package/dist/scripts/wallet/setup.js +105 -0
- package/dist/scripts/x-verification/commands.d.ts +27 -0
- package/dist/scripts/x-verification/commands.js +222 -0
- package/dist/scripts/x-verification/index.d.ts +4 -0
- package/dist/scripts/x-verification/index.js +4 -0
- package/dist/services/built-in/api-proxy/index.d.ts +6 -0
- package/dist/services/built-in/api-proxy/index.js +23 -0
- package/dist/services/built-in/code-develop/index.d.ts +6 -0
- package/dist/services/built-in/code-develop/index.js +23 -0
- package/dist/services/built-in/code-review/index.d.ts +10 -0
- package/dist/services/built-in/code-review/index.js +51 -0
- package/dist/services/built-in/image-analysis/index.d.ts +6 -0
- package/dist/services/built-in/image-analysis/index.js +33 -0
- package/dist/services/built-in/memory-store/index.d.ts +6 -0
- package/dist/services/built-in/memory-store/index.js +22 -0
- package/dist/services/built-in/roulette/index.d.ts +6 -0
- package/dist/services/built-in/roulette/index.js +27 -0
- package/dist/services/built-in/summarize/index.d.ts +6 -0
- package/dist/services/built-in/summarize/index.js +21 -0
- package/dist/services/built-in/tell-joke/handler.d.ts +7 -0
- package/dist/services/built-in/tell-joke/handler.js +122 -0
- package/dist/services/built-in/tell-joke/index.d.ts +9 -0
- package/dist/services/built-in/tell-joke/index.js +31 -0
- package/dist/services/built-in/translate/index.d.ts +6 -0
- package/dist/services/built-in/translate/index.js +21 -0
- package/dist/services/built-in/web-research/index.d.ts +9 -0
- package/dist/services/built-in/web-research/index.js +51 -0
- package/dist/services/index.d.ts +13 -0
- package/dist/services/index.js +14 -0
- package/dist/services/loader.d.ts +77 -0
- package/dist/services/loader.js +292 -0
- package/dist/services/manager.d.ts +86 -0
- package/dist/services/manager.js +255 -0
- package/dist/services/registry.d.ts +98 -0
- package/dist/services/registry.js +204 -0
- package/dist/services/types.d.ts +230 -0
- package/dist/services/types.js +30 -0
- package/dist/test/cli.test.d.ts +7 -0
- package/dist/test/cli.test.js +329 -0
- package/dist/test/comprehensive-overlay.test.d.ts +13 -0
- package/dist/test/comprehensive-overlay.test.js +593 -0
- package/dist/test/key-derivation.test.d.ts +12 -0
- package/dist/test/key-derivation.test.js +86 -0
- package/dist/test/overlay-submit.test.d.ts +10 -0
- package/dist/test/overlay-submit.test.js +460 -0
- package/dist/test/request-response-flow.test.d.ts +5 -0
- package/dist/test/request-response-flow.test.js +209 -0
- package/dist/test/service-system.test.d.ts +5 -0
- package/dist/test/service-system.test.js +190 -0
- package/dist/test/utils/server-logic.d.ts +98 -0
- package/dist/test/utils/server-logic.js +286 -0
- package/dist/test/wallet.test.d.ts +7 -0
- package/dist/test/wallet.test.js +146 -0
- package/index.ts +1965 -0
- package/openclaw.plugin.json +106 -0
- package/package.json +73 -0
- package/src/cli-main.ts +230 -0
- package/src/cli.ts +16 -0
- package/src/core/README.md +246 -0
- package/src/core/config.ts +21 -0
- package/src/core/index.ts +42 -0
- package/src/core/payment.ts +111 -0
- package/src/core/types.ts +102 -0
- package/src/core/verify.ts +119 -0
- package/src/core/wallet.ts +282 -0
- package/src/scripts/baemail/commands.ts +326 -0
- package/src/scripts/baemail/handler.ts +338 -0
- package/src/scripts/baemail/index.ts +6 -0
- package/src/scripts/config.ts +81 -0
- package/src/scripts/index.ts +8 -0
- package/src/scripts/messaging/connect.ts +121 -0
- package/src/scripts/messaging/handlers.ts +394 -0
- package/src/scripts/messaging/inbox.ts +64 -0
- package/src/scripts/messaging/index.ts +9 -0
- package/src/scripts/messaging/poll.ts +59 -0
- package/src/scripts/messaging/send.ts +54 -0
- package/src/scripts/output.ts +21 -0
- package/src/scripts/overlay/discover.ts +81 -0
- package/src/scripts/overlay/index.ts +8 -0
- package/src/scripts/overlay/registration.ts +199 -0
- package/src/scripts/overlay/services.ts +199 -0
- package/src/scripts/overlay/transaction.ts +124 -0
- package/src/scripts/payment/build.ts +65 -0
- package/src/scripts/payment/commands.ts +92 -0
- package/src/scripts/payment/index.ts +7 -0
- package/src/scripts/payment/types.ts +62 -0
- package/src/scripts/services/index.ts +7 -0
- package/src/scripts/services/queue.ts +35 -0
- package/src/scripts/services/request.ts +98 -0
- package/src/scripts/services/respond.ts +149 -0
- package/src/scripts/types.ts +121 -0
- package/src/scripts/utils/index.ts +7 -0
- package/src/scripts/utils/merkle.ts +57 -0
- package/src/scripts/utils/storage.ts +231 -0
- package/src/scripts/utils/woc.ts +106 -0
- package/src/scripts/wallet/balance.ts +277 -0
- package/src/scripts/wallet/identity.ts +203 -0
- package/src/scripts/wallet/index.ts +7 -0
- package/src/scripts/wallet/setup.ts +121 -0
- package/src/scripts/x-verification/commands.ts +256 -0
- package/src/scripts/x-verification/index.ts +5 -0
- package/src/services/built-in/api-proxy/index.ts +26 -0
- package/src/services/built-in/api-proxy/prompt.md +26 -0
- package/src/services/built-in/code-develop/index.ts +26 -0
- package/src/services/built-in/code-develop/prompt.md +35 -0
- package/src/services/built-in/code-review/index.ts +54 -0
- package/src/services/built-in/code-review/prompt.md +105 -0
- package/src/services/built-in/image-analysis/index.ts +36 -0
- package/src/services/built-in/image-analysis/prompt.md +42 -0
- package/src/services/built-in/memory-store/index.ts +25 -0
- package/src/services/built-in/memory-store/prompt.md +45 -0
- package/src/services/built-in/roulette/index.ts +30 -0
- package/src/services/built-in/roulette/prompt.md +35 -0
- package/src/services/built-in/summarize/index.ts +24 -0
- package/src/services/built-in/summarize/prompt.md +27 -0
- package/src/services/built-in/tell-joke/handler.ts +134 -0
- package/src/services/built-in/tell-joke/index.ts +34 -0
- package/src/services/built-in/tell-joke/prompt.md +59 -0
- package/src/services/built-in/translate/index.ts +24 -0
- package/src/services/built-in/translate/prompt.md +23 -0
- package/src/services/built-in/web-research/index.ts +54 -0
- package/src/services/built-in/web-research/prompt.md +110 -0
- package/src/services/index.ts +16 -0
- package/src/services/loader.ts +344 -0
- package/src/services/manager.ts +304 -0
- package/src/services/registry.ts +246 -0
- package/src/services/types.ts +259 -0
- package/src/test/cli.test.ts +352 -0
- package/src/test/comprehensive-overlay.test.ts +729 -0
- package/src/test/key-derivation.test.ts +102 -0
- package/src/test/overlay-submit.test.ts +570 -0
- package/src/test/request-response-flow.test.ts +252 -0
- package/src/test/service-system.test.ts +241 -0
- package/src/test/utils/server-logic.ts +368 -0
- package/src/test/wallet.test.ts +166 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-based storage helpers for registration, services, and queues.
|
|
3
|
+
*/
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import { OVERLAY_STATE_DIR, PATHS } from '../config.js';
|
|
6
|
+
/**
|
|
7
|
+
* Ensure the overlay state directory exists.
|
|
8
|
+
*/
|
|
9
|
+
export function ensureStateDir() {
|
|
10
|
+
fs.mkdirSync(OVERLAY_STATE_DIR, { recursive: true });
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Load registration data from disk.
|
|
14
|
+
*/
|
|
15
|
+
export function loadRegistration() {
|
|
16
|
+
try {
|
|
17
|
+
if (fs.existsSync(PATHS.registration)) {
|
|
18
|
+
return JSON.parse(fs.readFileSync(PATHS.registration, 'utf-8'));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// Ignore parse errors
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Save registration data to disk.
|
|
28
|
+
*/
|
|
29
|
+
export function saveRegistration(data) {
|
|
30
|
+
ensureStateDir();
|
|
31
|
+
fs.writeFileSync(PATHS.registration, JSON.stringify(data, null, 2), 'utf-8');
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Delete registration file.
|
|
35
|
+
*/
|
|
36
|
+
export function deleteRegistration() {
|
|
37
|
+
try {
|
|
38
|
+
fs.unlinkSync(PATHS.registration);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// Ignore if file doesn't exist
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Load services list from disk.
|
|
46
|
+
*/
|
|
47
|
+
export function loadServices() {
|
|
48
|
+
try {
|
|
49
|
+
if (fs.existsSync(PATHS.services)) {
|
|
50
|
+
return JSON.parse(fs.readFileSync(PATHS.services, 'utf-8'));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Ignore parse errors
|
|
55
|
+
}
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Save services list to disk.
|
|
60
|
+
*/
|
|
61
|
+
export function saveServices(services) {
|
|
62
|
+
ensureStateDir();
|
|
63
|
+
fs.writeFileSync(PATHS.services, JSON.stringify(services, null, 2), 'utf-8');
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Load X verifications from disk.
|
|
67
|
+
*/
|
|
68
|
+
export function loadXVerifications() {
|
|
69
|
+
try {
|
|
70
|
+
if (fs.existsSync(PATHS.xVerifications)) {
|
|
71
|
+
return JSON.parse(fs.readFileSync(PATHS.xVerifications, 'utf-8'));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// Ignore parse errors
|
|
76
|
+
}
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Save X verifications to disk.
|
|
81
|
+
*/
|
|
82
|
+
export function saveXVerifications(verifications) {
|
|
83
|
+
ensureStateDir();
|
|
84
|
+
fs.writeFileSync(PATHS.xVerifications, JSON.stringify(verifications, null, 2), 'utf-8');
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Append a line to a JSONL file.
|
|
88
|
+
*/
|
|
89
|
+
export function appendToJsonl(filePath, entry) {
|
|
90
|
+
ensureStateDir();
|
|
91
|
+
fs.appendFileSync(filePath, JSON.stringify(entry) + '\n');
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Read and parse a JSONL file.
|
|
95
|
+
*/
|
|
96
|
+
export function readJsonl(filePath) {
|
|
97
|
+
if (!fs.existsSync(filePath))
|
|
98
|
+
return [];
|
|
99
|
+
const lines = fs.readFileSync(filePath, 'utf-8').trim().split('\n').filter(Boolean);
|
|
100
|
+
return lines.map(line => {
|
|
101
|
+
try {
|
|
102
|
+
return JSON.parse(line);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}).filter(Boolean);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Load stored change BEEF data.
|
|
111
|
+
*/
|
|
112
|
+
export function loadStoredChange() {
|
|
113
|
+
try {
|
|
114
|
+
if (fs.existsSync(PATHS.latestChange)) {
|
|
115
|
+
return JSON.parse(fs.readFileSync(PATHS.latestChange, 'utf-8'));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// Ignore parse errors
|
|
120
|
+
}
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Save stored change BEEF data.
|
|
125
|
+
*/
|
|
126
|
+
export function saveStoredChange(data) {
|
|
127
|
+
ensureStateDir();
|
|
128
|
+
fs.writeFileSync(PATHS.latestChange, JSON.stringify(data));
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Delete stored change file.
|
|
132
|
+
*/
|
|
133
|
+
export function deleteStoredChange() {
|
|
134
|
+
try {
|
|
135
|
+
fs.unlinkSync(PATHS.latestChange);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// Ignore if file doesn't exist
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Clean up old entries from service queue.
|
|
143
|
+
* Removes entries older than maxAgeMs or entries with final statuses older than finalStatusMaxAgeMs.
|
|
144
|
+
*/
|
|
145
|
+
export function cleanupServiceQueue(maxAgeMs = 24 * 60 * 60 * 1000, finalStatusMaxAgeMs = 2 * 60 * 60 * 1000) {
|
|
146
|
+
if (!fs.existsSync(PATHS.serviceQueue))
|
|
147
|
+
return;
|
|
148
|
+
const now = Date.now();
|
|
149
|
+
const finalStatuses = ['fulfilled', 'rejected', 'delivery_failed', 'failed', 'error'];
|
|
150
|
+
const lines = fs.readFileSync(PATHS.serviceQueue, 'utf-8').trim().split('\n').filter(Boolean);
|
|
151
|
+
const keptLines = [];
|
|
152
|
+
let removedCount = 0;
|
|
153
|
+
for (const line of lines) {
|
|
154
|
+
try {
|
|
155
|
+
const entry = JSON.parse(line);
|
|
156
|
+
const entryAge = now - (entry._ts || 0);
|
|
157
|
+
// Always keep pending entries that aren't too old
|
|
158
|
+
if (entry.status === 'pending' && entryAge < maxAgeMs) {
|
|
159
|
+
keptLines.push(line);
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
// Keep final status entries only if they're recent
|
|
163
|
+
if (finalStatuses.includes(entry.status) && entryAge < finalStatusMaxAgeMs) {
|
|
164
|
+
keptLines.push(line);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
// Remove this entry
|
|
168
|
+
removedCount++;
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
// Keep malformed entries to avoid data loss
|
|
172
|
+
keptLines.push(line);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (removedCount > 0) {
|
|
176
|
+
fs.writeFileSync(PATHS.serviceQueue, keptLines.join('\n') + (keptLines.length ? '\n' : ''));
|
|
177
|
+
console.error(JSON.stringify({ event: 'queue-cleanup', removed: removedCount, kept: keptLines.length }));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Atomically update a service queue entry status.
|
|
182
|
+
* Returns true if the entry was found and updated, false otherwise.
|
|
183
|
+
*/
|
|
184
|
+
export function updateServiceQueueStatus(requestId, newStatus, additionalFields = {}) {
|
|
185
|
+
if (!fs.existsSync(PATHS.serviceQueue))
|
|
186
|
+
return false;
|
|
187
|
+
const lines = fs.readFileSync(PATHS.serviceQueue, 'utf-8').trim().split('\n').filter(Boolean);
|
|
188
|
+
let updated = false;
|
|
189
|
+
const updatedLines = lines.map(line => {
|
|
190
|
+
try {
|
|
191
|
+
const entry = JSON.parse(line);
|
|
192
|
+
if (entry.requestId === requestId) {
|
|
193
|
+
updated = true;
|
|
194
|
+
return JSON.stringify({
|
|
195
|
+
...entry,
|
|
196
|
+
status: newStatus,
|
|
197
|
+
...additionalFields,
|
|
198
|
+
updatedAt: Date.now()
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
return line;
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
return line;
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
if (updated) {
|
|
208
|
+
fs.writeFileSync(PATHS.serviceQueue, updatedLines.join('\n') + '\n');
|
|
209
|
+
}
|
|
210
|
+
return updated;
|
|
211
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WhatsOnChain API helpers with retry logic and rate limiting.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Fetch from WhatsonChain with optional API key auth and retry logic.
|
|
6
|
+
* Retries on 429 (rate limit) and 5xx errors with exponential backoff.
|
|
7
|
+
* Includes timeout to prevent hanging indefinitely.
|
|
8
|
+
*/
|
|
9
|
+
export declare function wocFetch(urlPath: string, options?: RequestInit, maxRetries?: number, timeoutMs?: number): Promise<Response>;
|
|
10
|
+
/**
|
|
11
|
+
* Fetch with timeout using AbortController.
|
|
12
|
+
*/
|
|
13
|
+
export declare function fetchWithTimeout(url: string, options?: RequestInit, timeoutMs?: number): Promise<Response>;
|
|
14
|
+
/**
|
|
15
|
+
* Fetch a pre-built BEEF from WhatsonChain for a given txid.
|
|
16
|
+
* WoC returns raw binary BEEF that includes the full source chain and merkle proofs.
|
|
17
|
+
*/
|
|
18
|
+
export declare function fetchBeefFromWoC(txid: string): Promise<Uint8Array | null>;
|
|
19
|
+
/**
|
|
20
|
+
* Get the WoC base URL for the current network.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getWocBaseUrl(): string;
|
|
23
|
+
/**
|
|
24
|
+
* Get the explorer base URL for the current network.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getExplorerBaseUrl(): string;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WhatsOnChain API helpers with retry logic and rate limiting.
|
|
3
|
+
*/
|
|
4
|
+
import { NETWORK, WOC_API_KEY } from '../config.js';
|
|
5
|
+
/**
|
|
6
|
+
* Fetch from WhatsonChain with optional API key auth and retry logic.
|
|
7
|
+
* Retries on 429 (rate limit) and 5xx errors with exponential backoff.
|
|
8
|
+
* Includes timeout to prevent hanging indefinitely.
|
|
9
|
+
*/
|
|
10
|
+
export async function wocFetch(urlPath, options = {}, maxRetries = 3, timeoutMs = 30000) {
|
|
11
|
+
const wocNet = NETWORK === 'mainnet' ? 'main' : 'test';
|
|
12
|
+
const base = `https://api.whatsonchain.com/v1/bsv/${wocNet}`;
|
|
13
|
+
const url = urlPath.startsWith('http') ? urlPath : `${base}${urlPath}`;
|
|
14
|
+
const headers = { ...(options.headers || {}) };
|
|
15
|
+
if (WOC_API_KEY) {
|
|
16
|
+
headers['Authorization'] = `Bearer ${WOC_API_KEY}`;
|
|
17
|
+
}
|
|
18
|
+
let lastError;
|
|
19
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
20
|
+
try {
|
|
21
|
+
const controller = new AbortController();
|
|
22
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
23
|
+
const resp = await fetch(url, { ...options, headers, signal: controller.signal });
|
|
24
|
+
clearTimeout(timeout);
|
|
25
|
+
// Retry on 429 (rate limit) or 5xx (server error)
|
|
26
|
+
if ((resp.status === 429 || resp.status >= 500) && attempt < maxRetries) {
|
|
27
|
+
const delayMs = Math.min(1000 * Math.pow(2, attempt), 8000);
|
|
28
|
+
await new Promise(r => setTimeout(r, delayMs));
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
return resp;
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
lastError = err;
|
|
35
|
+
if (attempt < maxRetries) {
|
|
36
|
+
const delayMs = Math.min(1000 * Math.pow(2, attempt), 8000);
|
|
37
|
+
await new Promise(r => setTimeout(r, delayMs));
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
throw lastError || new Error('WoC fetch failed after retries');
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Fetch with timeout using AbortController.
|
|
46
|
+
*/
|
|
47
|
+
export async function fetchWithTimeout(url, options = {}, timeoutMs = 15000) {
|
|
48
|
+
const controller = new AbortController();
|
|
49
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
50
|
+
try {
|
|
51
|
+
const resp = await fetch(url, { ...options, signal: controller.signal });
|
|
52
|
+
return resp;
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
clearTimeout(timeout);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Fetch a pre-built BEEF from WhatsonChain for a given txid.
|
|
60
|
+
* WoC returns raw binary BEEF that includes the full source chain and merkle proofs.
|
|
61
|
+
*/
|
|
62
|
+
export async function fetchBeefFromWoC(txid) {
|
|
63
|
+
try {
|
|
64
|
+
const resp = await wocFetch(`/tx/${txid}/beef`);
|
|
65
|
+
if (!resp.ok)
|
|
66
|
+
return null;
|
|
67
|
+
const hexStr = (await resp.text()).trim();
|
|
68
|
+
if (!hexStr || hexStr.length < 8)
|
|
69
|
+
return null;
|
|
70
|
+
const bytes = hexStr.match(/.{2}/g).map(h => parseInt(h, 16));
|
|
71
|
+
return new Uint8Array(bytes);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get the WoC base URL for the current network.
|
|
79
|
+
*/
|
|
80
|
+
export function getWocBaseUrl() {
|
|
81
|
+
const wocNet = NETWORK === 'mainnet' ? 'main' : 'test';
|
|
82
|
+
return `https://api.whatsonchain.com/v1/bsv/${wocNet}`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Get the explorer base URL for the current network.
|
|
86
|
+
*/
|
|
87
|
+
export function getExplorerBaseUrl() {
|
|
88
|
+
return NETWORK === 'mainnet'
|
|
89
|
+
? 'https://whatsonchain.com'
|
|
90
|
+
: 'https://test.whatsonchain.com';
|
|
91
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wallet balance commands: balance, import, refund.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Balance command: show wallet balance.
|
|
6
|
+
*/
|
|
7
|
+
export declare function cmdBalance(): Promise<never>;
|
|
8
|
+
/**
|
|
9
|
+
* Import command: import external UTXO with merkle proof.
|
|
10
|
+
*
|
|
11
|
+
* This function handles both confirmed and unconfirmed transactions.
|
|
12
|
+
* For unconfirmed transactions, it uses BEEF from WoC which includes
|
|
13
|
+
* the source chain back to confirmed ancestors (SPV-compliant).
|
|
14
|
+
*
|
|
15
|
+
* If the transaction isn't yet on WoC (just broadcast), it will poll
|
|
16
|
+
* with exponential backoff for up to 60 seconds.
|
|
17
|
+
*/
|
|
18
|
+
export declare function cmdImport(txidArg: string | undefined, voutStr?: string): Promise<never>;
|
|
19
|
+
/**
|
|
20
|
+
* Refund command: sweep wallet to an address.
|
|
21
|
+
*/
|
|
22
|
+
export declare function cmdRefund(targetAddress: string | undefined): Promise<void>;
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wallet balance commands: balance, import, refund.
|
|
3
|
+
*/
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import { NETWORK, WALLET_DIR, PATHS } from '../config.js';
|
|
6
|
+
import { ok, fail } from '../output.js';
|
|
7
|
+
import { wocFetch, fetchBeefFromWoC, getExplorerBaseUrl } from '../utils/woc.js';
|
|
8
|
+
import { buildMerklePathFromTSC } from '../utils/merkle.js';
|
|
9
|
+
import { BSVAgentWallet } from '../../core/index.js';
|
|
10
|
+
async function getBSVAgentWallet() {
|
|
11
|
+
return BSVAgentWallet;
|
|
12
|
+
}
|
|
13
|
+
// Dynamic import for @bsv/sdk
|
|
14
|
+
let _sdk = null;
|
|
15
|
+
async function getSdk() {
|
|
16
|
+
if (_sdk)
|
|
17
|
+
return _sdk;
|
|
18
|
+
try {
|
|
19
|
+
_sdk = await import('@bsv/sdk');
|
|
20
|
+
return _sdk;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
const { fileURLToPath } = await import('node:url');
|
|
24
|
+
const path = await import('node:path');
|
|
25
|
+
const os = await import('node:os');
|
|
26
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
27
|
+
const candidates = [
|
|
28
|
+
path.resolve(__dirname, '..', '..', '..', 'node_modules', '@bsv', 'sdk', 'dist', 'esm', 'mod.js'),
|
|
29
|
+
path.resolve(__dirname, '..', '..', '..', '..', '..', 'a2a-bsv', 'packages', 'core', 'node_modules', '@bsv', 'sdk', 'dist', 'esm', 'mod.js'),
|
|
30
|
+
path.resolve(os.homedir(), 'a2a-bsv', 'packages', 'core', 'node_modules', '@bsv', 'sdk', 'dist', 'esm', 'mod.js'),
|
|
31
|
+
];
|
|
32
|
+
for (const p of candidates) {
|
|
33
|
+
try {
|
|
34
|
+
_sdk = await import(p);
|
|
35
|
+
return _sdk;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Try next
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
throw new Error('Cannot find @bsv/sdk. Run setup.sh first.');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Sleep helper for polling
|
|
46
|
+
*/
|
|
47
|
+
function sleep(ms) {
|
|
48
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Balance command: show wallet balance.
|
|
52
|
+
*/
|
|
53
|
+
export async function cmdBalance() {
|
|
54
|
+
const BSVAgentWallet = await getBSVAgentWallet();
|
|
55
|
+
const sdk = await getSdk();
|
|
56
|
+
const wallet = await BSVAgentWallet.load({ network: NETWORK, storageDir: WALLET_DIR });
|
|
57
|
+
const total = await wallet.getBalance();
|
|
58
|
+
await wallet.destroy();
|
|
59
|
+
return ok({ walletBalance: total });
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Import command: import external UTXO with merkle proof.
|
|
63
|
+
*
|
|
64
|
+
* This function handles both confirmed and unconfirmed transactions.
|
|
65
|
+
* For unconfirmed transactions, it uses BEEF from WoC which includes
|
|
66
|
+
* the source chain back to confirmed ancestors (SPV-compliant).
|
|
67
|
+
*
|
|
68
|
+
* If the transaction isn't yet on WoC (just broadcast), it will poll
|
|
69
|
+
* with exponential backoff for up to 60 seconds.
|
|
70
|
+
*/
|
|
71
|
+
export async function cmdImport(txidArg, voutStr) {
|
|
72
|
+
if (!txidArg) {
|
|
73
|
+
return fail('Usage: import <txid> [vout]');
|
|
74
|
+
}
|
|
75
|
+
const vout = parseInt(voutStr || '0', 10);
|
|
76
|
+
const txid = txidArg.toLowerCase();
|
|
77
|
+
if (!/^[0-9a-f]{64}$/.test(txid)) {
|
|
78
|
+
return fail('Invalid txid — must be 64 hex characters');
|
|
79
|
+
}
|
|
80
|
+
const sdk = await getSdk();
|
|
81
|
+
const BSVAgentWallet = await getBSVAgentWallet();
|
|
82
|
+
// Poll for transaction on WoC with exponential backoff
|
|
83
|
+
// This handles the case where user just broadcast and WoC hasn't indexed yet
|
|
84
|
+
let txInfo = null;
|
|
85
|
+
const maxWaitMs = 60000; // 60 seconds max
|
|
86
|
+
const startTime = Date.now();
|
|
87
|
+
let attempt = 0;
|
|
88
|
+
while (Date.now() - startTime < maxWaitMs) {
|
|
89
|
+
const txInfoResp = await wocFetch(`/tx/${txid}`, {}, 1, 10000); // Single retry, 10s timeout
|
|
90
|
+
if (txInfoResp.ok) {
|
|
91
|
+
txInfo = await txInfoResp.json();
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
else if (txInfoResp.status === 404) {
|
|
95
|
+
// Transaction not found yet - wait and retry
|
|
96
|
+
attempt++;
|
|
97
|
+
const delayMs = Math.min(1000 * Math.pow(1.5, attempt), 10000); // 1s, 1.5s, 2.25s, ... max 10s
|
|
98
|
+
console.error(`[import] Transaction not on WoC yet, waiting ${Math.round(delayMs / 1000)}s... (attempt ${attempt})`);
|
|
99
|
+
await sleep(delayMs);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
return fail(`Failed to fetch tx info: ${txInfoResp.status}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (!txInfo) {
|
|
107
|
+
return fail(`Transaction ${txid} not found on WhatsOnChain after ${Math.round((Date.now() - startTime) / 1000)}s. The transaction may not have been broadcast yet, or the txid may be incorrect.`);
|
|
108
|
+
}
|
|
109
|
+
const isConfirmed = txInfo.confirmations && txInfo.confirmations >= 1;
|
|
110
|
+
const blockHeight = txInfo.blockheight;
|
|
111
|
+
// Validate output exists
|
|
112
|
+
if (!txInfo.vout || !txInfo.vout[vout]) {
|
|
113
|
+
return fail(`Output index ${vout} not found in transaction (has ${txInfo.vout?.length || 0} outputs)`);
|
|
114
|
+
}
|
|
115
|
+
let atomicBeefBytes;
|
|
116
|
+
// Try WoC BEEF first - works for both confirmed and unconfirmed transactions
|
|
117
|
+
// WoC provides BEEF with full source chain back to confirmed ancestors
|
|
118
|
+
const wocBeefBytes = await fetchBeefFromWoC(txid);
|
|
119
|
+
if (wocBeefBytes) {
|
|
120
|
+
try {
|
|
121
|
+
const wocBeef = sdk.Beef.fromBinary(Array.from(wocBeefBytes));
|
|
122
|
+
const foundTx = wocBeef.findTxid(txid);
|
|
123
|
+
if (foundTx) {
|
|
124
|
+
// Verify the output exists in the parsed tx
|
|
125
|
+
const txObj = foundTx.tx || foundTx._tx;
|
|
126
|
+
if (txObj) {
|
|
127
|
+
const output = txObj.outputs[vout];
|
|
128
|
+
if (!output) {
|
|
129
|
+
return fail(`Output index ${vout} not found in BEEF transaction (has ${txObj.outputs.length} outputs)`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
atomicBeefBytes = wocBeef.toBinaryAtomic(txid);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (beefErr) {
|
|
136
|
+
console.error(`[import] WoC BEEF parse failed: ${beefErr.message}`);
|
|
137
|
+
// Fall through to manual construction
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Fallback for confirmed txs: construct BEEF manually using TSC merkle proof
|
|
141
|
+
if (!atomicBeefBytes && isConfirmed) {
|
|
142
|
+
try {
|
|
143
|
+
const rawTxResp = await wocFetch(`/tx/${txid}/hex`);
|
|
144
|
+
if (!rawTxResp.ok) {
|
|
145
|
+
return fail(`Failed to fetch raw transaction: ${rawTxResp.status}`);
|
|
146
|
+
}
|
|
147
|
+
const rawTxHex = await rawTxResp.text();
|
|
148
|
+
const sourceTx = sdk.Transaction.fromHex(rawTxHex.trim());
|
|
149
|
+
const proofResp = await wocFetch(`/tx/${txid}/proof/tsc`);
|
|
150
|
+
if (!proofResp.ok) {
|
|
151
|
+
return fail(`Failed to fetch merkle proof: ${proofResp.status}`);
|
|
152
|
+
}
|
|
153
|
+
const proofData = await proofResp.json();
|
|
154
|
+
if (!Array.isArray(proofData) || proofData.length === 0) {
|
|
155
|
+
return fail('Merkle proof not available from WoC');
|
|
156
|
+
}
|
|
157
|
+
const proof = proofData[0];
|
|
158
|
+
const merklePath = await buildMerklePathFromTSC(txid, proof.index, proof.nodes, blockHeight);
|
|
159
|
+
sourceTx.merklePath = merklePath;
|
|
160
|
+
const beef = new sdk.Beef();
|
|
161
|
+
beef.mergeTransaction(sourceTx);
|
|
162
|
+
atomicBeefBytes = beef.toBinaryAtomic(txid);
|
|
163
|
+
}
|
|
164
|
+
catch (manualErr) {
|
|
165
|
+
return fail(`Failed to construct BEEF manually: ${manualErr.message}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// If still no BEEF, we can't import
|
|
169
|
+
if (!atomicBeefBytes) {
|
|
170
|
+
if (isConfirmed) {
|
|
171
|
+
return fail(`Transaction ${txid} is confirmed but BEEF construction failed. This is unexpected — please report this issue.`);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
// Unconfirmed and no BEEF available
|
|
175
|
+
// This can happen if the funding tx itself spends unconfirmed inputs
|
|
176
|
+
return fail(`Transaction ${txid} is unconfirmed (${txInfo.confirmations || 0} confirmations) and BEEF is not available.\n\n` +
|
|
177
|
+
`This usually means the funding transaction spends from other unconfirmed transactions, creating a chain.\n` +
|
|
178
|
+
`Wait for 1 block confirmation (~10 minutes) and try again, or use a fresh UTXO as the funding source.`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Get output satoshis for reporting
|
|
182
|
+
const outputSatoshis = txInfo.vout[vout].value != null
|
|
183
|
+
? Math.round(txInfo.vout[vout].value * 1e8)
|
|
184
|
+
: undefined;
|
|
185
|
+
// Import into wallet
|
|
186
|
+
const wallet = await BSVAgentWallet.load({ network: NETWORK, storageDir: WALLET_DIR });
|
|
187
|
+
const identityKey = await wallet.getIdentityKey();
|
|
188
|
+
try {
|
|
189
|
+
await wallet._setup.wallet.storage.internalizeAction({
|
|
190
|
+
tx: Array.from(atomicBeefBytes),
|
|
191
|
+
outputs: [{
|
|
192
|
+
outputIndex: vout,
|
|
193
|
+
protocol: 'wallet payment',
|
|
194
|
+
paymentRemittance: {
|
|
195
|
+
derivationPrefix: sdk.Utils.toBase64(sdk.Utils.toArray('import', 'utf8')),
|
|
196
|
+
derivationSuffix: sdk.Utils.toBase64(sdk.Utils.toArray('now', 'utf8')),
|
|
197
|
+
senderIdentityKey: identityKey,
|
|
198
|
+
},
|
|
199
|
+
}],
|
|
200
|
+
description: 'External funding import',
|
|
201
|
+
});
|
|
202
|
+
const balance = await wallet.getBalance();
|
|
203
|
+
await wallet.destroy();
|
|
204
|
+
const explorerBase = getExplorerBaseUrl();
|
|
205
|
+
return ok({
|
|
206
|
+
txid,
|
|
207
|
+
vout,
|
|
208
|
+
satoshis: outputSatoshis,
|
|
209
|
+
blockHeight: blockHeight || null,
|
|
210
|
+
confirmations: txInfo.confirmations || 0,
|
|
211
|
+
imported: true,
|
|
212
|
+
unconfirmed: !isConfirmed,
|
|
213
|
+
balance,
|
|
214
|
+
explorer: `${explorerBase}/tx/${txid}`,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
await wallet.destroy();
|
|
219
|
+
// Provide helpful error messages for common issues
|
|
220
|
+
if (err.message?.includes('already') || err.message?.includes('duplicate')) {
|
|
221
|
+
return fail(`UTXO ${txid}:${vout} appears to already be imported.`);
|
|
222
|
+
}
|
|
223
|
+
if (err.message?.includes('script') || err.message?.includes('locking')) {
|
|
224
|
+
return fail(`UTXO ${txid}:${vout} does not belong to this wallet's address. Make sure you sent to the correct address.`);
|
|
225
|
+
}
|
|
226
|
+
return fail(`Failed to import UTXO: ${err.message}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Refund command: sweep wallet to an address.
|
|
231
|
+
*/
|
|
232
|
+
export async function cmdRefund(targetAddress) {
|
|
233
|
+
if (!targetAddress) {
|
|
234
|
+
return fail('Usage: refund <address>');
|
|
235
|
+
}
|
|
236
|
+
if (!fs.existsSync(PATHS.walletIdentity)) {
|
|
237
|
+
return fail('Wallet not initialized. Run: setup');
|
|
238
|
+
}
|
|
239
|
+
// TODO IMPLEMENT THIS
|
|
240
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wallet identity helpers.
|
|
3
|
+
*/
|
|
4
|
+
import type { WalletIdentity } from '../types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Load wallet identity from disk.
|
|
7
|
+
* @returns Identity object with rootKeyHex and identityKey
|
|
8
|
+
* @throws Error if wallet not initialized
|
|
9
|
+
*/
|
|
10
|
+
export declare function loadWalletIdentity(): WalletIdentity;
|
|
11
|
+
/**
|
|
12
|
+
* Load identity and private key for relay message signing.
|
|
13
|
+
* @returns Object with identityKey and privKey
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadIdentity(): Promise<{
|
|
16
|
+
identityKey: string;
|
|
17
|
+
privKey: any;
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* Sign a relay message using ECDSA.
|
|
21
|
+
* @param privKey - Private key for signing
|
|
22
|
+
* @param to - Recipient's identity key
|
|
23
|
+
* @param type - Message type
|
|
24
|
+
* @param payload - Message payload
|
|
25
|
+
* @returns Hex-encoded DER signature
|
|
26
|
+
*/
|
|
27
|
+
export declare function signRelayMessage(privKey: any, to: string, type: string, payload: unknown): Promise<string>;
|
|
28
|
+
/**
|
|
29
|
+
* Verify a relay message signature.
|
|
30
|
+
* @param fromKey - Sender's public key
|
|
31
|
+
* @param to - Recipient's identity key
|
|
32
|
+
* @param type - Message type
|
|
33
|
+
* @param payload - Message payload
|
|
34
|
+
* @param signatureHex - Hex-encoded DER signature
|
|
35
|
+
* @returns Verification result
|
|
36
|
+
*/
|
|
37
|
+
export declare function verifyRelaySignature(fromKey: string, to: string, type: string, payload: unknown, signatureHex: string | undefined): Promise<{
|
|
38
|
+
valid: boolean;
|
|
39
|
+
reason?: string;
|
|
40
|
+
}>;
|
|
41
|
+
/**
|
|
42
|
+
* Derive wallet address components from a private key.
|
|
43
|
+
*
|
|
44
|
+
* IMPORTANT: This uses BRC-29 key derivation to create a child key.
|
|
45
|
+
* Any transactions spending to this address MUST use the matching
|
|
46
|
+
* child private key for signing, NOT the root key.
|
|
47
|
+
*
|
|
48
|
+
* Use deriveWalletKeys() to get both the address and signing key.
|
|
49
|
+
*/
|
|
50
|
+
export declare function deriveWalletAddress(privKey: any): Promise<{
|
|
51
|
+
address: string;
|
|
52
|
+
hash160: Uint8Array;
|
|
53
|
+
pubKey: any;
|
|
54
|
+
}>;
|
|
55
|
+
/**
|
|
56
|
+
* Derive wallet keys for both address AND transaction signing.
|
|
57
|
+
*
|
|
58
|
+
* CRITICAL: Use this function to get the child private key for signing
|
|
59
|
+
* transactions that spend from the derived address. Do NOT use the
|
|
60
|
+
* root private key - it will cause signature verification failures!
|
|
61
|
+
*
|
|
62
|
+
* @param rootPrivKey - Root private key from wallet identity
|
|
63
|
+
* @returns Object with address, hash160, and CHILD private key for signing
|
|
64
|
+
*/
|
|
65
|
+
export declare function deriveWalletKeys(rootPrivKey: any): Promise<{
|
|
66
|
+
address: string;
|
|
67
|
+
hash160: Uint8Array;
|
|
68
|
+
pubKey: any;
|
|
69
|
+
childPrivKey: any;
|
|
70
|
+
}>;
|