@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.
- package/dist/api/OneSatApi.d.ts +100 -0
- package/dist/api/OneSatApi.js +156 -0
- package/dist/api/balance/index.d.ts +38 -0
- package/dist/api/balance/index.js +82 -0
- package/dist/api/broadcast/index.d.ts +22 -0
- package/dist/api/broadcast/index.js +45 -0
- package/dist/api/constants.d.ts +21 -0
- package/dist/api/constants.js +29 -0
- package/dist/api/index.d.ts +36 -0
- package/dist/api/index.js +38 -0
- package/dist/api/inscriptions/index.d.ts +25 -0
- package/dist/api/inscriptions/index.js +50 -0
- package/dist/api/locks/index.d.ts +44 -0
- package/dist/api/locks/index.js +233 -0
- package/dist/api/ordinals/index.d.ts +87 -0
- package/dist/api/ordinals/index.js +446 -0
- package/dist/api/payments/index.d.ts +37 -0
- package/dist/api/payments/index.js +130 -0
- package/dist/api/signing/index.d.ts +32 -0
- package/dist/api/signing/index.js +41 -0
- package/dist/api/tokens/index.d.ts +88 -0
- package/dist/api/tokens/index.js +400 -0
- package/dist/cwi/chrome.d.ts +11 -0
- package/dist/cwi/chrome.js +39 -0
- package/dist/cwi/event.d.ts +11 -0
- package/dist/cwi/event.js +38 -0
- package/dist/cwi/factory.d.ts +14 -0
- package/dist/cwi/factory.js +44 -0
- package/dist/cwi/index.d.ts +11 -0
- package/dist/cwi/index.js +11 -0
- package/dist/cwi/types.d.ts +39 -0
- package/dist/cwi/types.js +39 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +5 -1
- package/dist/indexers/Bsv21Indexer.js +1 -1
- package/dist/indexers/CosignIndexer.js +2 -1
- package/dist/indexers/InscriptionIndexer.js +4 -5
- package/dist/indexers/LockIndexer.js +2 -1
- package/dist/indexers/MapIndexer.js +1 -1
- package/dist/indexers/OrdLockIndexer.js +2 -1
- package/dist/indexers/OriginIndexer.js +1 -1
- package/dist/indexers/index.d.ts +1 -1
- package/dist/indexers/types.d.ts +18 -0
- package/dist/services/OneSatServices.d.ts +19 -10
- package/dist/services/OneSatServices.js +201 -39
- package/dist/services/client/ChaintracksClient.d.ts +55 -13
- package/dist/services/client/ChaintracksClient.js +123 -28
- package/dist/services/client/OrdfsClient.d.ts +2 -2
- package/dist/services/client/OrdfsClient.js +4 -3
- package/dist/services/client/TxoClient.js +9 -0
- package/dist/sync/AddressManager.d.ts +85 -0
- package/dist/sync/AddressManager.js +107 -0
- package/dist/sync/SyncManager.d.ts +207 -0
- package/dist/sync/SyncManager.js +507 -0
- package/dist/sync/index.d.ts +4 -0
- package/dist/sync/index.js +2 -0
- package/package.json +5 -4
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type { ChainTracker } from "@bsv/sdk";
|
|
2
|
-
import type { BlockHeader,
|
|
2
|
+
import type { BaseBlockHeader, BlockHeader, Chain } from "@bsv/wallet-toolbox";
|
|
3
|
+
import type { ClientOptions } from "../types";
|
|
3
4
|
import { BaseClient } from "./BaseClient";
|
|
4
5
|
/**
|
|
5
6
|
* Client for /1sat/chaintracks/* routes.
|
|
6
|
-
*
|
|
7
|
+
* Implements ChaintracksClientApi interface from @bsv/wallet-toolbox.
|
|
7
8
|
*
|
|
8
9
|
* Routes:
|
|
9
10
|
* - GET /tip - Get chain tip
|
|
10
11
|
* - GET /tip/stream - SSE stream of new blocks
|
|
11
|
-
* - GET /height - Get current height
|
|
12
12
|
* - GET /network - Get network type
|
|
13
13
|
* - GET /headers?height=N&count=M - Get raw header bytes
|
|
14
14
|
* - GET /header/height/:height - Get header by height
|
|
@@ -17,6 +17,9 @@ import { BaseClient } from "./BaseClient";
|
|
|
17
17
|
export declare class ChaintracksClient extends BaseClient implements ChainTracker {
|
|
18
18
|
private eventSource;
|
|
19
19
|
private subscribers;
|
|
20
|
+
private cachedTip;
|
|
21
|
+
private cachedTipTime;
|
|
22
|
+
private static readonly TIP_CACHE_TTL_MS;
|
|
20
23
|
constructor(baseUrl: string, options?: ClientOptions);
|
|
21
24
|
/**
|
|
22
25
|
* Get current blockchain height (ChainTracker interface)
|
|
@@ -27,25 +30,64 @@ export declare class ChaintracksClient extends BaseClient implements ChainTracke
|
|
|
27
30
|
*/
|
|
28
31
|
isValidRootForHeight(root: string, height: number): Promise<boolean>;
|
|
29
32
|
/**
|
|
30
|
-
* Get the network
|
|
33
|
+
* Get the blockchain network (main or test)
|
|
31
34
|
*/
|
|
32
|
-
|
|
35
|
+
getChain(): Promise<Chain>;
|
|
33
36
|
/**
|
|
34
|
-
* Get
|
|
37
|
+
* Get service info - synthetic for remote client
|
|
35
38
|
*/
|
|
36
|
-
|
|
39
|
+
getInfo(): Promise<{
|
|
40
|
+
chain: Chain;
|
|
41
|
+
heightBulk: number;
|
|
42
|
+
heightLive: number;
|
|
43
|
+
storage: string;
|
|
44
|
+
bulkIngestors: string[];
|
|
45
|
+
liveIngestors: string[];
|
|
46
|
+
packages: {
|
|
47
|
+
name: string;
|
|
48
|
+
version: string;
|
|
49
|
+
}[];
|
|
50
|
+
}>;
|
|
37
51
|
/**
|
|
38
|
-
* Get
|
|
52
|
+
* Get current chain height
|
|
39
53
|
*/
|
|
40
|
-
|
|
54
|
+
getPresentHeight(): Promise<number>;
|
|
41
55
|
/**
|
|
42
|
-
* Get
|
|
56
|
+
* Get headers as serialized 80-byte hex string
|
|
57
|
+
*/
|
|
58
|
+
getHeaders(height: number, count: number): Promise<string>;
|
|
59
|
+
/**
|
|
60
|
+
* Get the current chain tip header (cached for 30 seconds)
|
|
61
|
+
*/
|
|
62
|
+
findChainTipHeader(): Promise<BlockHeader>;
|
|
63
|
+
/**
|
|
64
|
+
* Get the current chain tip hash
|
|
43
65
|
*/
|
|
44
|
-
|
|
66
|
+
findChainTipHash(): Promise<string>;
|
|
45
67
|
/**
|
|
46
|
-
* Get
|
|
68
|
+
* Get block header by height
|
|
69
|
+
*/
|
|
70
|
+
findHeaderForHeight(height: number): Promise<BlockHeader | undefined>;
|
|
71
|
+
/**
|
|
72
|
+
* Get block header by hash
|
|
47
73
|
*/
|
|
48
|
-
|
|
74
|
+
findHeaderForBlockHash(hash: string): Promise<BlockHeader | undefined>;
|
|
75
|
+
/** No-op: Remote server tracks the chain */
|
|
76
|
+
addHeader(_header: BaseBlockHeader): Promise<void>;
|
|
77
|
+
/** No-op: Client is always ready */
|
|
78
|
+
startListening(): Promise<void>;
|
|
79
|
+
/** No-op: Resolves immediately */
|
|
80
|
+
listening(): Promise<void>;
|
|
81
|
+
/** Always true for remote client */
|
|
82
|
+
isListening(): Promise<boolean>;
|
|
83
|
+
/** Always true for remote client */
|
|
84
|
+
isSynchronized(): Promise<boolean>;
|
|
85
|
+
/** Not implemented for remote client */
|
|
86
|
+
subscribeReorgs(_listener: (depth: number, oldTip: BlockHeader, newTip: BlockHeader, deactivatedHeaders?: BlockHeader[]) => void): Promise<string>;
|
|
87
|
+
/** Unsubscribe from events */
|
|
88
|
+
unsubscribe(_subscriptionId: string): Promise<boolean>;
|
|
89
|
+
/** Subscribe to new header events */
|
|
90
|
+
subscribeHeaders(listener: (header: BlockHeader) => void): Promise<string>;
|
|
49
91
|
/**
|
|
50
92
|
* Get raw header bytes for one or more headers
|
|
51
93
|
*/
|
|
@@ -36,22 +36,29 @@ async function doubleSha256(data) {
|
|
|
36
36
|
*/
|
|
37
37
|
async function parseHeader(data, height) {
|
|
38
38
|
const version = readUint32LE(data, 0);
|
|
39
|
-
const
|
|
39
|
+
const previousHash = toHexLE(data.slice(4, 36));
|
|
40
40
|
const merkleRoot = toHexLE(data.slice(36, 68));
|
|
41
41
|
const time = readUint32LE(data, 68);
|
|
42
42
|
const bits = readUint32LE(data, 72);
|
|
43
43
|
const nonce = readUint32LE(data, 76);
|
|
44
44
|
const hash = toHexLE(await doubleSha256(data));
|
|
45
|
-
return { height, hash, version,
|
|
45
|
+
return { height, hash, version, previousHash, merkleRoot, time, bits, nonce };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Convert bytes to hex string (big-endian / natural order)
|
|
49
|
+
*/
|
|
50
|
+
function toHex(data) {
|
|
51
|
+
return Array.from(data)
|
|
52
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
53
|
+
.join("");
|
|
46
54
|
}
|
|
47
55
|
/**
|
|
48
56
|
* Client for /1sat/chaintracks/* routes.
|
|
49
|
-
*
|
|
57
|
+
* Implements ChaintracksClientApi interface from @bsv/wallet-toolbox.
|
|
50
58
|
*
|
|
51
59
|
* Routes:
|
|
52
60
|
* - GET /tip - Get chain tip
|
|
53
61
|
* - GET /tip/stream - SSE stream of new blocks
|
|
54
|
-
* - GET /height - Get current height
|
|
55
62
|
* - GET /network - Get network type
|
|
56
63
|
* - GET /headers?height=N&count=M - Get raw header bytes
|
|
57
64
|
* - GET /header/height/:height - Get header by height
|
|
@@ -60,6 +67,10 @@ async function parseHeader(data, height) {
|
|
|
60
67
|
export class ChaintracksClient extends BaseClient {
|
|
61
68
|
eventSource = null;
|
|
62
69
|
subscribers = new Set();
|
|
70
|
+
// Chain tip cache (30 second TTL)
|
|
71
|
+
cachedTip = null;
|
|
72
|
+
cachedTipTime = 0;
|
|
73
|
+
static TIP_CACHE_TTL_MS = 30_000;
|
|
63
74
|
constructor(baseUrl, options = {}) {
|
|
64
75
|
super(`${baseUrl}/1sat/chaintracks`, options);
|
|
65
76
|
}
|
|
@@ -67,7 +78,7 @@ export class ChaintracksClient extends BaseClient {
|
|
|
67
78
|
* Get current blockchain height (ChainTracker interface)
|
|
68
79
|
*/
|
|
69
80
|
async currentHeight() {
|
|
70
|
-
const tip = await this.
|
|
81
|
+
const tip = await this.findChainTipHeader();
|
|
71
82
|
return tip.height;
|
|
72
83
|
}
|
|
73
84
|
/**
|
|
@@ -75,9 +86,8 @@ export class ChaintracksClient extends BaseClient {
|
|
|
75
86
|
*/
|
|
76
87
|
async isValidRootForHeight(root, height) {
|
|
77
88
|
try {
|
|
78
|
-
const header = await this.
|
|
79
|
-
|
|
80
|
-
return isValid;
|
|
89
|
+
const header = await this.findHeaderForHeight(height);
|
|
90
|
+
return header?.merkleRoot === root;
|
|
81
91
|
}
|
|
82
92
|
catch (e) {
|
|
83
93
|
console.error(`isValidRootForHeight(${height}) failed:`, e);
|
|
@@ -85,43 +95,128 @@ export class ChaintracksClient extends BaseClient {
|
|
|
85
95
|
}
|
|
86
96
|
}
|
|
87
97
|
/**
|
|
88
|
-
* Get the network
|
|
98
|
+
* Get the blockchain network (main or test)
|
|
89
99
|
*/
|
|
90
|
-
async
|
|
100
|
+
async getChain() {
|
|
91
101
|
const data = await this.request("/network");
|
|
92
102
|
return data.network;
|
|
93
103
|
}
|
|
94
104
|
/**
|
|
95
|
-
* Get
|
|
105
|
+
* Get service info - synthetic for remote client
|
|
96
106
|
*/
|
|
97
|
-
async
|
|
98
|
-
|
|
107
|
+
async getInfo() {
|
|
108
|
+
const tip = await this.findChainTipHeader();
|
|
109
|
+
const chain = await this.getChain();
|
|
110
|
+
return {
|
|
111
|
+
chain,
|
|
112
|
+
heightBulk: tip.height,
|
|
113
|
+
heightLive: tip.height,
|
|
114
|
+
storage: "remote",
|
|
115
|
+
bulkIngestors: [],
|
|
116
|
+
liveIngestors: [],
|
|
117
|
+
packages: [],
|
|
118
|
+
};
|
|
99
119
|
}
|
|
100
120
|
/**
|
|
101
|
-
* Get
|
|
121
|
+
* Get current chain height
|
|
102
122
|
*/
|
|
103
|
-
async
|
|
104
|
-
return this.
|
|
123
|
+
async getPresentHeight() {
|
|
124
|
+
return this.currentHeight();
|
|
105
125
|
}
|
|
106
126
|
/**
|
|
107
|
-
* Get
|
|
127
|
+
* Get headers as serialized 80-byte hex string
|
|
108
128
|
*/
|
|
109
|
-
async
|
|
110
|
-
|
|
129
|
+
async getHeaders(height, count) {
|
|
130
|
+
const data = await this.requestBinary(`/headers?height=${height}&count=${count}`);
|
|
131
|
+
return toHex(data);
|
|
111
132
|
}
|
|
112
133
|
/**
|
|
113
|
-
* Get
|
|
134
|
+
* Get the current chain tip header (cached for 30 seconds)
|
|
114
135
|
*/
|
|
115
|
-
async
|
|
116
|
-
const
|
|
117
|
-
if (
|
|
118
|
-
|
|
136
|
+
async findChainTipHeader() {
|
|
137
|
+
const now = Date.now();
|
|
138
|
+
if (this.cachedTip && now - this.cachedTipTime < ChaintracksClient.TIP_CACHE_TTL_MS) {
|
|
139
|
+
return this.cachedTip;
|
|
119
140
|
}
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
141
|
+
const header = await this.request("/tip");
|
|
142
|
+
console.log("[ChaintracksClient] findChainTipHeader:", header.height, header.hash);
|
|
143
|
+
this.cachedTip = header;
|
|
144
|
+
this.cachedTipTime = now;
|
|
145
|
+
return header;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Get the current chain tip hash
|
|
149
|
+
*/
|
|
150
|
+
async findChainTipHash() {
|
|
151
|
+
const tip = await this.findChainTipHeader();
|
|
152
|
+
return tip.hash;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get block header by height
|
|
156
|
+
*/
|
|
157
|
+
async findHeaderForHeight(height) {
|
|
158
|
+
try {
|
|
159
|
+
return await this.request(`/header/height/${height}`);
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Get block header by hash
|
|
167
|
+
*/
|
|
168
|
+
async findHeaderForBlockHash(hash) {
|
|
169
|
+
try {
|
|
170
|
+
return await this.request(`/header/hash/${hash}`);
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/** No-op: Remote server tracks the chain */
|
|
177
|
+
async addHeader(_header) { }
|
|
178
|
+
/** No-op: Client is always ready */
|
|
179
|
+
async startListening() { }
|
|
180
|
+
/** No-op: Resolves immediately */
|
|
181
|
+
async listening() { }
|
|
182
|
+
/** Always true for remote client */
|
|
183
|
+
async isListening() {
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
/** Always true for remote client */
|
|
187
|
+
async isSynchronized() {
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
/** Not implemented for remote client */
|
|
191
|
+
async subscribeReorgs(_listener) {
|
|
192
|
+
throw new Error("Method not implemented.");
|
|
193
|
+
}
|
|
194
|
+
/** Unsubscribe from events */
|
|
195
|
+
async unsubscribe(_subscriptionId) {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
/** Subscribe to new header events */
|
|
199
|
+
async subscribeHeaders(listener) {
|
|
200
|
+
this.subscribers.add(listener);
|
|
201
|
+
if (!this.eventSource) {
|
|
202
|
+
this.eventSource = new EventSource(`${this.baseUrl}/tip/stream`);
|
|
203
|
+
this.eventSource.onmessage = (event) => {
|
|
204
|
+
try {
|
|
205
|
+
const header = JSON.parse(event.data);
|
|
206
|
+
for (const cb of this.subscribers) {
|
|
207
|
+
cb(header);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
// Ignore parse errors
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
this.eventSource.onerror = () => {
|
|
215
|
+
this.eventSource?.close();
|
|
216
|
+
this.eventSource = null;
|
|
217
|
+
};
|
|
123
218
|
}
|
|
124
|
-
return
|
|
219
|
+
return "subscription";
|
|
125
220
|
}
|
|
126
221
|
/**
|
|
127
222
|
* Get raw header bytes for one or more headers
|
|
@@ -4,8 +4,8 @@ import { BaseClient } from "./BaseClient";
|
|
|
4
4
|
* Client for ordfs routes.
|
|
5
5
|
* Provides inscription content and metadata.
|
|
6
6
|
*
|
|
7
|
-
* Content is served from /
|
|
8
|
-
* API routes use /1sat/ordfs (e.g., https://
|
|
7
|
+
* Content is served from /content (e.g., https://1sat.shruggr.cloud/content/:outpoint)
|
|
8
|
+
* API routes use /1sat/ordfs (e.g., https://1sat.shruggr.cloud/1sat/ordfs/metadata/:outpoint)
|
|
9
9
|
*/
|
|
10
10
|
export declare class OrdfsClient extends BaseClient {
|
|
11
11
|
private readonly contentBaseUrl;
|
|
@@ -3,14 +3,15 @@ import { BaseClient } from "./BaseClient";
|
|
|
3
3
|
* Client for ordfs routes.
|
|
4
4
|
* Provides inscription content and metadata.
|
|
5
5
|
*
|
|
6
|
-
* Content is served from /
|
|
7
|
-
* API routes use /1sat/ordfs (e.g., https://
|
|
6
|
+
* Content is served from /content (e.g., https://1sat.shruggr.cloud/content/:outpoint)
|
|
7
|
+
* API routes use /1sat/ordfs (e.g., https://1sat.shruggr.cloud/1sat/ordfs/metadata/:outpoint)
|
|
8
8
|
*/
|
|
9
9
|
export class OrdfsClient extends BaseClient {
|
|
10
10
|
contentBaseUrl;
|
|
11
11
|
constructor(baseUrl, options = {}) {
|
|
12
12
|
super(`${baseUrl}/1sat/ordfs`, options);
|
|
13
|
-
|
|
13
|
+
// Content is at root /content, not under /1sat/
|
|
14
|
+
this.contentBaseUrl = `${baseUrl.replace(/\/$/, "")}/content`;
|
|
14
15
|
}
|
|
15
16
|
/**
|
|
16
17
|
* Get metadata for an inscription
|
|
@@ -21,6 +21,9 @@ export class TxoClient extends BaseClient {
|
|
|
21
21
|
async get(outpoint, opts) {
|
|
22
22
|
const qs = this.buildQueryString({
|
|
23
23
|
tags: opts?.tags,
|
|
24
|
+
sats: opts?.sats,
|
|
25
|
+
spend: opts?.spend,
|
|
26
|
+
block: opts?.block,
|
|
24
27
|
});
|
|
25
28
|
return this.request(`/${outpoint}${qs}`);
|
|
26
29
|
}
|
|
@@ -30,6 +33,9 @@ export class TxoClient extends BaseClient {
|
|
|
30
33
|
async getBatch(outpoints, opts) {
|
|
31
34
|
const qs = this.buildQueryString({
|
|
32
35
|
tags: opts?.tags,
|
|
36
|
+
sats: opts?.sats,
|
|
37
|
+
spend: opts?.spend,
|
|
38
|
+
block: opts?.block,
|
|
33
39
|
});
|
|
34
40
|
return this.request(`/outpoints${qs}`, {
|
|
35
41
|
method: "POST",
|
|
@@ -61,6 +67,9 @@ export class TxoClient extends BaseClient {
|
|
|
61
67
|
async getByTxid(txid, opts) {
|
|
62
68
|
const qs = this.buildQueryString({
|
|
63
69
|
tags: opts?.tags,
|
|
70
|
+
sats: opts?.sats,
|
|
71
|
+
spend: opts?.spend,
|
|
72
|
+
block: opts?.block,
|
|
64
73
|
});
|
|
65
74
|
return this.request(`/tx/${txid}${qs}`);
|
|
66
75
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AddressManager - Manages yours receive addresses using BRC-29 derivation format.
|
|
3
|
+
*
|
|
4
|
+
* Yours receive addresses are fixed, public addresses that users share publicly.
|
|
5
|
+
* They are derived deterministically from the identity key using:
|
|
6
|
+
* - derivationPrefix: "yours receive" (fixed)
|
|
7
|
+
* - derivationSuffix: "0", "1", "2", ... (sequential counter)
|
|
8
|
+
* - senderIdentityKey: our own identity public key (self-referential derivation)
|
|
9
|
+
*
|
|
10
|
+
* This allows:
|
|
11
|
+
* 1. Deterministic regeneration on wallet restore
|
|
12
|
+
* 2. Syncing external payments to these addresses
|
|
13
|
+
* 3. Auto-signing via BRC-29/ScriptTemplateBRC29 (wallet knows the derivation info)
|
|
14
|
+
*
|
|
15
|
+
* Address derivation is done externally (in yours-wallet) and passed to this class.
|
|
16
|
+
*/
|
|
17
|
+
import { type WalletProtocol } from "@bsv/sdk";
|
|
18
|
+
/** Fixed prefix for yours receive addresses */
|
|
19
|
+
export declare const YOURS_PREFIX = "yours";
|
|
20
|
+
/** BRC-29 protocol ID - used by wallet-toolbox for key derivation and signing */
|
|
21
|
+
export declare const BRC29_PROTOCOL_ID: WalletProtocol;
|
|
22
|
+
/**
|
|
23
|
+
* Derivation info for a yours receive address.
|
|
24
|
+
* This is what's needed for internalizeAction's paymentRemittance.
|
|
25
|
+
*/
|
|
26
|
+
export interface AddressDerivation {
|
|
27
|
+
/** The Bitcoin address (base58check) */
|
|
28
|
+
address: string;
|
|
29
|
+
/** The key index (0, 1, 2, etc.) for internal lookups */
|
|
30
|
+
index: number;
|
|
31
|
+
/** Base64-encoded derivation prefix (e.g., base64("yours receive")) */
|
|
32
|
+
derivationPrefix: string;
|
|
33
|
+
/** Base64-encoded derivation suffix (e.g., base64("0"), base64("1"), etc.) */
|
|
34
|
+
derivationSuffix: string;
|
|
35
|
+
/** Our own identity public key (self-referential) */
|
|
36
|
+
senderIdentityKey: string;
|
|
37
|
+
/** The public key for this address */
|
|
38
|
+
publicKey: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* AddressManager manages yours receive addresses.
|
|
42
|
+
* Accepts pre-derived addresses - derivation is done externally.
|
|
43
|
+
*/
|
|
44
|
+
export declare class AddressManager {
|
|
45
|
+
private addressMap;
|
|
46
|
+
private maxKeyIndex;
|
|
47
|
+
/**
|
|
48
|
+
* @param derivations - Pre-derived address derivations
|
|
49
|
+
*/
|
|
50
|
+
constructor(derivations: AddressDerivation[]);
|
|
51
|
+
/**
|
|
52
|
+
* Add a new address derivation.
|
|
53
|
+
*/
|
|
54
|
+
addAddress(derivation: AddressDerivation): void;
|
|
55
|
+
/**
|
|
56
|
+
* Get the current max key index.
|
|
57
|
+
* This should be persisted to chrome.storage.
|
|
58
|
+
*/
|
|
59
|
+
getMaxKeyIndex(): number;
|
|
60
|
+
/**
|
|
61
|
+
* Get all known addresses.
|
|
62
|
+
*/
|
|
63
|
+
getAddresses(): string[];
|
|
64
|
+
/**
|
|
65
|
+
* Get derivation info for an address, or undefined if not ours.
|
|
66
|
+
*/
|
|
67
|
+
getDerivation(address: string): AddressDerivation | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* Check if an address belongs to this wallet.
|
|
70
|
+
*/
|
|
71
|
+
isOurAddress(address: string): boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Get the primary receive address (index 0).
|
|
74
|
+
*/
|
|
75
|
+
getPrimaryAddress(): string | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* Get address at a specific index.
|
|
78
|
+
*/
|
|
79
|
+
getAddressAtIndex(index: number): AddressDerivation | undefined;
|
|
80
|
+
/**
|
|
81
|
+
* Build the locking script for an address at a specific index.
|
|
82
|
+
* Useful for verifying outputs match expected scripts.
|
|
83
|
+
*/
|
|
84
|
+
getLockingScriptAtIndex(index: number): string | undefined;
|
|
85
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AddressManager - Manages yours receive addresses using BRC-29 derivation format.
|
|
3
|
+
*
|
|
4
|
+
* Yours receive addresses are fixed, public addresses that users share publicly.
|
|
5
|
+
* They are derived deterministically from the identity key using:
|
|
6
|
+
* - derivationPrefix: "yours receive" (fixed)
|
|
7
|
+
* - derivationSuffix: "0", "1", "2", ... (sequential counter)
|
|
8
|
+
* - senderIdentityKey: our own identity public key (self-referential derivation)
|
|
9
|
+
*
|
|
10
|
+
* This allows:
|
|
11
|
+
* 1. Deterministic regeneration on wallet restore
|
|
12
|
+
* 2. Syncing external payments to these addresses
|
|
13
|
+
* 3. Auto-signing via BRC-29/ScriptTemplateBRC29 (wallet knows the derivation info)
|
|
14
|
+
*
|
|
15
|
+
* Address derivation is done externally (in yours-wallet) and passed to this class.
|
|
16
|
+
*/
|
|
17
|
+
import { P2PKH } from "@bsv/sdk";
|
|
18
|
+
/** Fixed prefix for yours receive addresses */
|
|
19
|
+
export const YOURS_PREFIX = 'yours';
|
|
20
|
+
/** BRC-29 protocol ID - used by wallet-toolbox for key derivation and signing */
|
|
21
|
+
export const BRC29_PROTOCOL_ID = [2, "3241645161d8"];
|
|
22
|
+
/**
|
|
23
|
+
* AddressManager manages yours receive addresses.
|
|
24
|
+
* Accepts pre-derived addresses - derivation is done externally.
|
|
25
|
+
*/
|
|
26
|
+
export class AddressManager {
|
|
27
|
+
addressMap = new Map();
|
|
28
|
+
maxKeyIndex = -1;
|
|
29
|
+
/**
|
|
30
|
+
* @param derivations - Pre-derived address derivations
|
|
31
|
+
*/
|
|
32
|
+
constructor(derivations) {
|
|
33
|
+
for (const derivation of derivations) {
|
|
34
|
+
this.addressMap.set(derivation.address, derivation);
|
|
35
|
+
if (derivation.index > this.maxKeyIndex) {
|
|
36
|
+
this.maxKeyIndex = derivation.index;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Add a new address derivation.
|
|
42
|
+
*/
|
|
43
|
+
addAddress(derivation) {
|
|
44
|
+
this.addressMap.set(derivation.address, derivation);
|
|
45
|
+
if (derivation.index > this.maxKeyIndex) {
|
|
46
|
+
this.maxKeyIndex = derivation.index;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get the current max key index.
|
|
51
|
+
* This should be persisted to chrome.storage.
|
|
52
|
+
*/
|
|
53
|
+
getMaxKeyIndex() {
|
|
54
|
+
return this.maxKeyIndex;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get all known addresses.
|
|
58
|
+
*/
|
|
59
|
+
getAddresses() {
|
|
60
|
+
return Array.from(this.addressMap.keys());
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get derivation info for an address, or undefined if not ours.
|
|
64
|
+
*/
|
|
65
|
+
getDerivation(address) {
|
|
66
|
+
return this.addressMap.get(address);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Check if an address belongs to this wallet.
|
|
70
|
+
*/
|
|
71
|
+
isOurAddress(address) {
|
|
72
|
+
return this.addressMap.has(address);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get the primary receive address (index 0).
|
|
76
|
+
*/
|
|
77
|
+
getPrimaryAddress() {
|
|
78
|
+
for (const derivation of this.addressMap.values()) {
|
|
79
|
+
if (derivation.index === 0) {
|
|
80
|
+
return derivation.address;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get address at a specific index.
|
|
87
|
+
*/
|
|
88
|
+
getAddressAtIndex(index) {
|
|
89
|
+
for (const derivation of this.addressMap.values()) {
|
|
90
|
+
if (derivation.index === index) {
|
|
91
|
+
return derivation;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Build the locking script for an address at a specific index.
|
|
98
|
+
* Useful for verifying outputs match expected scripts.
|
|
99
|
+
*/
|
|
100
|
+
getLockingScriptAtIndex(index) {
|
|
101
|
+
const derivation = this.getAddressAtIndex(index);
|
|
102
|
+
if (!derivation)
|
|
103
|
+
return undefined;
|
|
104
|
+
const p2pkh = new P2PKH();
|
|
105
|
+
return p2pkh.lock(derivation.address).toHex();
|
|
106
|
+
}
|
|
107
|
+
}
|