@mainnet-cash/bcmr 2.7.23

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.
@@ -0,0 +1,467 @@
1
+ const playwright = require("playwright");
2
+ const PAGE_URL = "http://localhost:8080/bcmr/index.html";
3
+
4
+ describe(`Wallet should function in the browser`, () => {
5
+ let browser;
6
+ let page;
7
+
8
+ const registry = {
9
+ $schema: "https://cashtokens.org/bcmr-v2.schema.json",
10
+ version: {
11
+ major: 0,
12
+ minor: 1,
13
+ patch: 0,
14
+ },
15
+ latestRevision: "2023-01-26T18:51:35.115Z",
16
+ registryIdentity: {
17
+ name: "example bcmr",
18
+ description: "example bcmr for tokens on chipnet",
19
+ },
20
+ identities: {
21
+ "0000000000000000000000000000000000000000000000000000000000000000": {
22
+ "2023-01-26T18:51:35.115Z": {
23
+ name: "test tokens",
24
+ description: "",
25
+ uris: {
26
+ icon: "https://example.com/nft",
27
+ },
28
+ token: {
29
+ category:
30
+ "0000000000000000000000000000000000000000000000000000000000000000",
31
+ symbol: "TOK",
32
+ decimals: 8,
33
+ nfts: {
34
+ description: "",
35
+ parse: {
36
+ bytecode: "00d2",
37
+ types: {
38
+ "00": {
39
+ name: "NFT Item 0",
40
+ description: "NFT Item 0 in the collection",
41
+ uris: {
42
+ icon: "https://example.com/nft/00.jpg",
43
+ },
44
+ },
45
+ },
46
+ },
47
+ },
48
+ },
49
+ },
50
+ },
51
+ },
52
+ extensions: {},
53
+ };
54
+
55
+ /**
56
+ * Create the browser and page context
57
+ */
58
+ beforeAll(async () => {
59
+ browser = await playwright["chromium"].launch();
60
+ page = await browser.newPage();
61
+
62
+ if (!page) {
63
+ throw new Error("Connection wasn't established");
64
+ }
65
+
66
+ // Open the page
67
+ await page.goto(PAGE_URL, {
68
+ waitUntil: "networkidle0",
69
+ });
70
+ });
71
+
72
+ afterAll(async () => {
73
+ await browser.close();
74
+ });
75
+
76
+ test("Add metadata registry and get token info", async () => {
77
+ await page.evaluate(
78
+ async ([id, registry]) => {
79
+ expect(
80
+ BCMR.getTokenInfo(
81
+ "0000000000000000000000000000000000000000000000000000000000000000"
82
+ )
83
+ ).toBe(undefined);
84
+ BCMR.addMetadataRegistry(registry);
85
+ const tokenInfo = BCMR.getTokenInfo(
86
+ "0000000000000000000000000000000000000000000000000000000000000000"
87
+ );
88
+ expect(tokenInfo?.token?.symbol).toBe("TOK");
89
+ expect(tokenInfo?.token?.decimals).toBe(8);
90
+
91
+ // check adding the same registry does not produce a duplicate
92
+ expect(BCMR.metadataRegistries.length).toBe(1);
93
+ BCMR.addMetadataRegistry(registry);
94
+ expect(BCMR.metadataRegistries.length).toBe(1);
95
+ },
96
+ [process.env.ALICE_ID, registry]
97
+ );
98
+ });
99
+
100
+ test(`Add metadata from uri and get token info`, async () => {
101
+ await page.evaluate(
102
+ async ([id, registry]) => {
103
+ BCMR.resetRegistries();
104
+
105
+ setupFetchMock(
106
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json",
107
+ registry
108
+ );
109
+
110
+ expect(
111
+ BCMR.getTokenInfo(
112
+ "0000000000000000000000000000000000000000000000000000000000000000"
113
+ )
114
+ ).toBe(undefined);
115
+ await BCMR.addMetadataRegistryFromUri(
116
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json"
117
+ );
118
+ const tokenInfo = BCMR.getTokenInfo(
119
+ "0000000000000000000000000000000000000000000000000000000000000000"
120
+ );
121
+ expect(tokenInfo?.token?.symbol).toBe("TOK");
122
+ expect(tokenInfo?.token?.decimals).toBe(8);
123
+
124
+ // check adding the same registry does not produce a duplicate
125
+ expect(BCMR.metadataRegistries.length).toBe(1);
126
+ await BCMR.addMetadataRegistryFromUri(
127
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json"
128
+ );
129
+ expect(BCMR.metadataRegistries.length).toBe(1);
130
+
131
+ removeFetchMock(
132
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json"
133
+ );
134
+ },
135
+ [process.env.ALICE_ID, registry]
136
+ );
137
+ });
138
+
139
+ test("Auth chain with 1 element, add resolved registry", async () => {
140
+ await page.evaluate(
141
+ async ([id, registry]) => {
142
+ BCMR.resetRegistries();
143
+
144
+ const alice = await RegTestWallet.fromId(id);
145
+ const bob = await RegTestWallet.newRandom();
146
+
147
+ const registryContent = JSON.stringify(registry, null, 2);
148
+ const registryContentHashBin = sha256.hash(utf8ToBin(registryContent));
149
+ const registryContentHashBinBitcoinByteOrder = registryContentHashBin;
150
+
151
+ let chunks = [
152
+ "BCMR",
153
+ registryContentHashBinBitcoinByteOrder,
154
+ "mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json",
155
+ ];
156
+ const opreturnData = OpReturnData.fromArray(chunks);
157
+ const response = await alice.send([
158
+ new SendRequest({
159
+ cashaddr: bob.cashaddr,
160
+ value: 10000,
161
+ unit: "sat",
162
+ }),
163
+ opreturnData,
164
+ ]);
165
+
166
+ setupFetchMock(
167
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json",
168
+ registry
169
+ );
170
+
171
+ expect(
172
+ BCMR.getTokenInfo(
173
+ "0000000000000000000000000000000000000000000000000000000000000000"
174
+ )
175
+ ).toBe(undefined);
176
+ const chain = await BCMR.addMetadataRegistryAuthChain({
177
+ transactionHash: response.txId,
178
+ network: Network.REGTEST,
179
+ });
180
+ expect(chain.length).toBe(1);
181
+ expect(chain[0].txHash).toBe(response.txId);
182
+ expect(chain[0].uris[0]).toBe(
183
+ "mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json"
184
+ );
185
+
186
+ const tokenInfo = BCMR.getTokenInfo(
187
+ "0000000000000000000000000000000000000000000000000000000000000000"
188
+ );
189
+ expect(tokenInfo?.token?.symbol).toBe("TOK");
190
+ expect(tokenInfo?.token?.decimals).toBe(8);
191
+
192
+ // check adding the same registry does not produce a duplicate
193
+ expect(BCMR.metadataRegistries.length).toBe(1);
194
+ const otherChain = await BCMR.addMetadataRegistryAuthChain({
195
+ transactionHash: response.txId,
196
+ network: Network.REGTEST,
197
+ });
198
+ expect(otherChain.length).toBe(1);
199
+ expect(BCMR.metadataRegistries.length).toBe(1);
200
+
201
+ removeFetchMock(
202
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json"
203
+ );
204
+ },
205
+ [process.env.ALICE_ID, registry]
206
+ );
207
+ });
208
+
209
+ test("Authchain tail resolution info in registry acceleration path", async () => {
210
+ await page.evaluate(
211
+ async ([id, registry]) => {
212
+ BCMR.resetRegistries();
213
+
214
+ const alice = await RegTestWallet.fromId(id);
215
+ const bob = await RegTestWallet.newRandom();
216
+
217
+ const registry_v1 = { ...registry };
218
+ registry_v1.extensions = { authchain: {} };
219
+ const contentHash_v1 = sha256.hash(
220
+ utf8ToBin(JSON.stringify(registry_v1, null, 2))
221
+ );
222
+ setupFetchMock(
223
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v1.json",
224
+ JSON.stringify(registry_v1, null, 2)
225
+ );
226
+ let chunks = [
227
+ "BCMR",
228
+ contentHash_v1,
229
+ "mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v1.json",
230
+ ];
231
+ const opreturnData = OpReturnData.fromArray(chunks);
232
+ const response = await alice.send([
233
+ new SendRequest({
234
+ cashaddr: bob.cashaddr,
235
+ value: 10000,
236
+ unit: "sat",
237
+ }),
238
+ opreturnData,
239
+ ]);
240
+
241
+ const registry_v2 = { ...registry };
242
+ registry_v2.extensions = {
243
+ authchain: { 0: await bob.provider.getRawTransaction(response.txId) },
244
+ };
245
+ const contentHash_v2 = sha256.hash(
246
+ utf8ToBin(JSON.stringify(registry_v2, null, 2))
247
+ );
248
+ setupFetchMock(
249
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v2.json",
250
+ JSON.stringify(registry_v2, null, 2)
251
+ );
252
+ chunks = [
253
+ "BCMR",
254
+ contentHash_v2,
255
+ "mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v2.json",
256
+ ];
257
+ const opreturnData2 = OpReturnData.fromArray(chunks);
258
+ const response2 = await bob.send([
259
+ new SendRequest({ cashaddr: bob.cashaddr, value: 9500, unit: "sat" }),
260
+ opreturnData2,
261
+ ]);
262
+
263
+ const registry_v3 = { ...registry };
264
+ registry_v3.extensions = {
265
+ authchain: {
266
+ 0: await bob.provider.getRawTransaction(response.txId),
267
+ 1: await bob.provider.getRawTransaction(response2.txId),
268
+ },
269
+ };
270
+ const contentHash_v3 = sha256.hash(
271
+ utf8ToBin(JSON.stringify(registry_v3, null, 2))
272
+ );
273
+ setupFetchMock(
274
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v3.json",
275
+ JSON.stringify(registry_v3, null, 2)
276
+ );
277
+ chunks = [
278
+ "BCMR",
279
+ contentHash_v3,
280
+ "mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v3.json",
281
+ ];
282
+ const opreturnData3 = OpReturnData.fromArray(chunks);
283
+ const response3 = await bob.send([
284
+ new SendRequest({ cashaddr: bob.cashaddr, value: 9000, unit: "sat" }),
285
+ opreturnData3,
286
+ ]);
287
+
288
+ const registry_v4 = { ...registry };
289
+ registry_v4.extensions = {};
290
+ const contentHash_v4 = sha256.hash(
291
+ utf8ToBin(JSON.stringify(registry_v4, null, 2))
292
+ );
293
+ setupFetchMock(
294
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v4.json",
295
+ JSON.stringify(registry_v4, null, 2)
296
+ );
297
+ chunks = [
298
+ "BCMR",
299
+ contentHash_v4,
300
+ "mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v4.json",
301
+ ];
302
+ const opreturnData4 = OpReturnData.fromArray(chunks);
303
+ const response4 = await bob.send([
304
+ new SendRequest({ cashaddr: bob.cashaddr, value: 8500, unit: "sat" }),
305
+ opreturnData4,
306
+ ]);
307
+
308
+ let chain = await BCMR.buildAuthChain({
309
+ transactionHash: response.txId,
310
+ network: Network.REGTEST,
311
+ });
312
+ expect(chain.length).toBe(4);
313
+
314
+ chain = await BCMR.buildAuthChain({
315
+ transactionHash: response.txId,
316
+ network: Network.REGTEST,
317
+ followToHead: false,
318
+ });
319
+ expect(chain.length).toBe(1);
320
+
321
+ // tail acceleration available, do not follow head
322
+ chain = await BCMR.buildAuthChain({
323
+ transactionHash: response3.txId,
324
+ network: Network.REGTEST,
325
+ followToHead: false,
326
+ resolveBase: true,
327
+ });
328
+ expect(chain.length).toBe(3);
329
+
330
+ // resolve single element
331
+ chain = await BCMR.buildAuthChain({
332
+ transactionHash: response3.txId,
333
+ network: Network.REGTEST,
334
+ followToHead: false,
335
+ resolveBase: false,
336
+ });
337
+ expect(chain.length).toBe(1);
338
+
339
+ // no acceleration available, will scan network
340
+ chain = await BCMR.buildAuthChain({
341
+ transactionHash: response4.txId,
342
+ network: Network.REGTEST,
343
+ resolveBase: true,
344
+ });
345
+ expect(chain.length).toBe(4);
346
+
347
+ expect(chain[0].txHash).toBe(response.txId);
348
+ expect(chain[0].uris[0]).toBe(
349
+ "mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v1.json"
350
+ );
351
+ expect(chain[0].httpsUrl).toBe(
352
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v1.json"
353
+ );
354
+
355
+ expect(chain[1].txHash).toBe(response2.txId);
356
+ expect(chain[1].uris[0]).toBe(
357
+ "mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v2.json"
358
+ );
359
+ expect(chain[1].httpsUrl).toBe(
360
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v2.json"
361
+ );
362
+
363
+ expect(chain[2].txHash).toBe(response3.txId);
364
+ expect(chain[2].uris[0]).toBe(
365
+ "mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v3.json"
366
+ );
367
+ expect(chain[2].httpsUrl).toBe(
368
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v3.json"
369
+ );
370
+
371
+ expect(chain[3].txHash).toBe(response4.txId);
372
+ expect(chain[3].uris[0]).toBe(
373
+ "mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v4.json"
374
+ );
375
+ expect(chain[3].httpsUrl).toBe(
376
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v4.json"
377
+ );
378
+
379
+ removeFetchMock(
380
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v1.json"
381
+ );
382
+ removeFetchMock(
383
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v2.json"
384
+ );
385
+ removeFetchMock(
386
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v3.json"
387
+ );
388
+ removeFetchMock(
389
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v4.json"
390
+ );
391
+ },
392
+ [process.env.ALICE_ID, registry]
393
+ );
394
+ });
395
+
396
+ test("Auth chain: BCMR, ipfs hash", async () => {
397
+ await page.evaluate(
398
+ async ([id, registry]) => {
399
+ const alice = await RegTestWallet.fromId(id);
400
+ const bob = await RegTestWallet.newRandom();
401
+
402
+ const chunks = [
403
+ "BCMR",
404
+ "QmbWrG5Asp5iGmUwQHogSJGRX26zuRnuLWPytZfiL75sZv",
405
+ ];
406
+ const opreturnData = OpReturnData.fromArray(chunks);
407
+
408
+ const response = await alice.send([
409
+ new SendRequest({ cashaddr: bob.cashaddr, value: 1000, unit: "sat" }),
410
+ opreturnData,
411
+ ]);
412
+ const chain = await BCMR.buildAuthChain({
413
+ transactionHash: response.txId,
414
+ network: Network.REGTEST,
415
+ });
416
+ expect(chain.length).toBe(1);
417
+ expect(chain[0].contentHash).toBe(
418
+ "516d62577247354173703569476d557751486f67534a47525832367a75526e754c575079745a66694c3735735a76"
419
+ );
420
+ expect(chain[0].uris[0]).toBe(
421
+ "ipfs://QmbWrG5Asp5iGmUwQHogSJGRX26zuRnuLWPytZfiL75sZv"
422
+ );
423
+ expect(chain[0].httpsUrl).toBe(
424
+ "https://dweb.link/ipfs/QmbWrG5Asp5iGmUwQHogSJGRX26zuRnuLWPytZfiL75sZv"
425
+ );
426
+ expect(chain[0].txHash).toBe(response.txId);
427
+ },
428
+ [process.env.ALICE_ID, registry]
429
+ );
430
+ });
431
+
432
+ test("Auth chain: BCMR, sha256 content hash, 2 uris", async () => {
433
+ await page.evaluate(
434
+ async ([id, registry]) => {
435
+ const alice = await RegTestWallet.fromId(id);
436
+ const bob = await RegTestWallet.newRandom();
437
+
438
+ const chunks = [
439
+ "BCMR",
440
+ sha256.hash(utf8ToBin("registry_contents")),
441
+ "mainnet.cash",
442
+ "ipfs://QmbWrG5Asp5iGmUwQHogSJGRX26zuRnuLWPytZfiL75sZv",
443
+ ];
444
+ const opreturnData = OpReturnData.fromArray(chunks);
445
+ const response = await alice.send([
446
+ new SendRequest({ cashaddr: bob.cashaddr, value: 1000, unit: "sat" }),
447
+ opreturnData,
448
+ ]);
449
+ const chain = await BCMR.buildAuthChain({
450
+ transactionHash: response.txId,
451
+ network: Network.REGTEST,
452
+ });
453
+
454
+ expect(chain.length).toBe(1);
455
+ expect(chain[0].uris.length).toBe(2);
456
+ expect(chain[0].uris[0]).toBe("mainnet.cash");
457
+ expect(chain[0].uris[1]).toBe(
458
+ "ipfs://QmbWrG5Asp5iGmUwQHogSJGRX26zuRnuLWPytZfiL75sZv"
459
+ );
460
+ expect(chain[0].httpsUrl).toBe(
461
+ "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json"
462
+ );
463
+ },
464
+ [process.env.ALICE_ID, registry]
465
+ );
466
+ });
467
+ });