mainnet-js 1.1.18 → 1.1.20
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/index.html +1 -1
- package/dist/{mainnet-1.1.18.js → mainnet-1.1.20.js} +2 -2
- package/dist/module/network/ElectrumNetworkProvider.d.ts.map +1 -1
- package/dist/module/network/ElectrumNetworkProvider.js +1 -1
- package/dist/module/network/ElectrumNetworkProvider.js.map +1 -1
- package/dist/module/wallet/Bcmr.d.ts +2 -1
- package/dist/module/wallet/Bcmr.d.ts.map +1 -1
- package/dist/module/wallet/Bcmr.js +40 -35
- package/dist/module/wallet/Bcmr.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/network/ElectrumNetworkProvider.ts +2 -1
- package/src/wallet/Bcmr.test.headless.js +83 -6
- package/src/wallet/Bcmr.test.ts +81 -31
- package/src/wallet/Bcmr.ts +44 -38
package/src/wallet/Bcmr.test.ts
CHANGED
|
@@ -231,7 +231,10 @@ describe(`Test BCMR support`, () => {
|
|
|
231
231
|
expect(chain[0].contentHash).toBe(
|
|
232
232
|
"516d62577247354173703569476d557751486f67534a47525832367a75526e754c575079745a66694c3735735a76"
|
|
233
233
|
);
|
|
234
|
-
expect(chain[0].
|
|
234
|
+
expect(chain[0].uris[0]).toBe(
|
|
235
|
+
"ipfs://QmbWrG5Asp5iGmUwQHogSJGRX26zuRnuLWPytZfiL75sZv"
|
|
236
|
+
);
|
|
237
|
+
expect(chain[0].httpsUrl).toBe(
|
|
235
238
|
"https://dweb.link/ipfs/QmbWrG5Asp5iGmUwQHogSJGRX26zuRnuLWPytZfiL75sZv"
|
|
236
239
|
);
|
|
237
240
|
expect(chain[0].txHash).toBe(response.txId);
|
|
@@ -247,7 +250,7 @@ describe(`Test BCMR support`, () => {
|
|
|
247
250
|
const chunks = [
|
|
248
251
|
"BCMR",
|
|
249
252
|
contentHashBin,
|
|
250
|
-
"mainnet.cash
|
|
253
|
+
"mainnet.cash",
|
|
251
254
|
];
|
|
252
255
|
const opreturnData = OpReturnData.fromArray(chunks);
|
|
253
256
|
|
|
@@ -261,13 +264,16 @@ describe(`Test BCMR support`, () => {
|
|
|
261
264
|
});
|
|
262
265
|
expect(chain.length).toBe(1);
|
|
263
266
|
expect(chain[0].contentHash).toBe(binToHex(contentHashBin));
|
|
264
|
-
expect(chain[0].
|
|
267
|
+
expect(chain[0].uris[0]).toBe(
|
|
268
|
+
"mainnet.cash"
|
|
269
|
+
);
|
|
270
|
+
expect(chain[0].httpsUrl).toBe(
|
|
265
271
|
"https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json"
|
|
266
272
|
);
|
|
267
273
|
expect(chain[0].txHash).toBe(response.txId);
|
|
268
274
|
});
|
|
269
275
|
|
|
270
|
-
test("Auth chain: BCMR, sha256 content hash,
|
|
276
|
+
test("Auth chain: BCMR, sha256 content hash, 2 uris", async () => {
|
|
271
277
|
const alice = await RegTestWallet.fromId(
|
|
272
278
|
`wif:regtest:${process.env.PRIVATE_WIF!}`
|
|
273
279
|
);
|
|
@@ -276,20 +282,24 @@ describe(`Test BCMR support`, () => {
|
|
|
276
282
|
const chunks = [
|
|
277
283
|
"BCMR",
|
|
278
284
|
sha256.hash(utf8ToBin("registry_contents")),
|
|
279
|
-
"mainnet.cash
|
|
280
|
-
"
|
|
285
|
+
"mainnet.cash",
|
|
286
|
+
"ipfs://QmbWrG5Asp5iGmUwQHogSJGRX26zuRnuLWPytZfiL75sZv",
|
|
281
287
|
];
|
|
282
288
|
const opreturnData = OpReturnData.fromArray(chunks);
|
|
283
289
|
const response = await alice.send([
|
|
284
290
|
new SendRequest({ cashaddr: bob.cashaddr!, value: 1000, unit: "sat" }),
|
|
285
291
|
opreturnData,
|
|
286
292
|
]);
|
|
287
|
-
await
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
).
|
|
293
|
+
const chain = await BCMR.buildAuthChain({
|
|
294
|
+
transactionHash: response.txId!,
|
|
295
|
+
network: Network.REGTEST,
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
expect(chain.length).toBe(1);
|
|
299
|
+
expect(chain[0].uris.length).toBe(2);
|
|
300
|
+
expect(chain[0].uris[0]).toBe("mainnet.cash");
|
|
301
|
+
expect(chain[0].uris[1]).toBe("ipfs://QmbWrG5Asp5iGmUwQHogSJGRX26zuRnuLWPytZfiL75sZv");
|
|
302
|
+
expect(chain[0].httpsUrl).toBe("https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json");
|
|
293
303
|
});
|
|
294
304
|
|
|
295
305
|
test("Auth chain: all OP_PUSDHDATA encodings", async () => {
|
|
@@ -346,7 +356,10 @@ describe(`Test BCMR support`, () => {
|
|
|
346
356
|
});
|
|
347
357
|
expect(chain.length).toBe(1);
|
|
348
358
|
expect(chain[0].txHash).toBe(response.txId!);
|
|
349
|
-
expect(chain[0].
|
|
359
|
+
expect(chain[0].uris[0]).toBe(
|
|
360
|
+
"mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json"
|
|
361
|
+
);
|
|
362
|
+
expect(chain[0].httpsUrl).toBe(
|
|
350
363
|
"https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json"
|
|
351
364
|
);
|
|
352
365
|
|
|
@@ -392,7 +405,7 @@ describe(`Test BCMR support`, () => {
|
|
|
392
405
|
let chunks = [
|
|
393
406
|
"BCMR",
|
|
394
407
|
registryContentHashBinBitcoinByteOrder,
|
|
395
|
-
"mainnet.cash
|
|
408
|
+
"mainnet.cash",
|
|
396
409
|
];
|
|
397
410
|
const opreturnData = OpReturnData.fromArray(chunks);
|
|
398
411
|
const response = await alice.send([
|
|
@@ -430,19 +443,23 @@ describe(`Test BCMR support`, () => {
|
|
|
430
443
|
|
|
431
444
|
expect(chain.length).toBe(3);
|
|
432
445
|
expect(chain[0].txHash).toBe(response.txId!);
|
|
433
|
-
expect(chain[0].
|
|
434
|
-
"
|
|
446
|
+
expect(chain[0].uris[0]).toBe(
|
|
447
|
+
"mainnet.cash"
|
|
435
448
|
);
|
|
449
|
+
expect(chain[0].httpsUrl).toBe("https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json");
|
|
436
450
|
|
|
437
451
|
expect(chain[1].txHash).toBe(response2.txId!);
|
|
438
|
-
expect(chain[1].
|
|
439
|
-
"
|
|
452
|
+
expect(chain[1].uris[0]).toBe(
|
|
453
|
+
"mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v2.json"
|
|
440
454
|
);
|
|
455
|
+
expect(chain[1].httpsUrl).toBe("https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v2.json");
|
|
456
|
+
|
|
441
457
|
|
|
442
458
|
expect(chain[2].txHash).toBe(response3.txId!);
|
|
443
|
-
expect(chain[2].
|
|
444
|
-
"
|
|
459
|
+
expect(chain[2].uris[0]).toBe(
|
|
460
|
+
"mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v3.json"
|
|
445
461
|
);
|
|
462
|
+
expect(chain[2].httpsUrl).toBe("https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v3.json");
|
|
446
463
|
|
|
447
464
|
// extra checks for resolving chains not from head
|
|
448
465
|
if (index === 0) {
|
|
@@ -453,7 +470,10 @@ describe(`Test BCMR support`, () => {
|
|
|
453
470
|
});
|
|
454
471
|
expect(noFollow.length).toBe(1);
|
|
455
472
|
expect(noFollow[0].txHash).toBe(response2.txId!);
|
|
456
|
-
expect(noFollow[0].
|
|
473
|
+
expect(noFollow[0].uris[0]).toBe(
|
|
474
|
+
"mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v2.json"
|
|
475
|
+
);
|
|
476
|
+
expect(noFollow[0].httpsUrl).toBe(
|
|
457
477
|
"https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v2.json"
|
|
458
478
|
);
|
|
459
479
|
|
|
@@ -465,12 +485,18 @@ describe(`Test BCMR support`, () => {
|
|
|
465
485
|
expect(follow.length).toBe(2);
|
|
466
486
|
|
|
467
487
|
expect(follow[0].txHash).toBe(response2.txId!);
|
|
468
|
-
expect(follow[0].
|
|
488
|
+
expect(follow[0].uris[0]).toBe(
|
|
489
|
+
"mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v2.json"
|
|
490
|
+
);
|
|
491
|
+
expect(follow[0].httpsUrl).toBe(
|
|
469
492
|
"https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v2.json"
|
|
470
493
|
);
|
|
471
494
|
|
|
472
495
|
expect(follow[1].txHash).toBe(response3.txId!);
|
|
473
|
-
expect(follow[1].
|
|
496
|
+
expect(follow[1].uris[0]).toBe(
|
|
497
|
+
"mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v3.json"
|
|
498
|
+
);
|
|
499
|
+
expect(follow[1].httpsUrl).toBe(
|
|
474
500
|
"https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v3.json"
|
|
475
501
|
);
|
|
476
502
|
}
|
|
@@ -610,22 +636,34 @@ describe(`Test BCMR support`, () => {
|
|
|
610
636
|
expect(chain.length).toBe(4);
|
|
611
637
|
|
|
612
638
|
expect(chain[0].txHash).toBe(response.txId!);
|
|
613
|
-
expect(chain[0].
|
|
639
|
+
expect(chain[0].uris[0]).toBe(
|
|
640
|
+
"mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v1.json"
|
|
641
|
+
);
|
|
642
|
+
expect(chain[0].httpsUrl).toBe(
|
|
614
643
|
"https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v1.json"
|
|
615
644
|
);
|
|
616
645
|
|
|
617
646
|
expect(chain[1].txHash).toBe(response2.txId!);
|
|
618
|
-
expect(chain[1].
|
|
647
|
+
expect(chain[1].uris[0]).toBe(
|
|
648
|
+
"mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v2.json"
|
|
649
|
+
);
|
|
650
|
+
expect(chain[1].httpsUrl).toBe(
|
|
619
651
|
"https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v2.json"
|
|
620
652
|
);
|
|
621
653
|
|
|
622
654
|
expect(chain[2].txHash).toBe(response3.txId!);
|
|
623
|
-
expect(chain[2].
|
|
655
|
+
expect(chain[2].uris[0]).toBe(
|
|
656
|
+
"mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v3.json"
|
|
657
|
+
);
|
|
658
|
+
expect(chain[2].httpsUrl).toBe(
|
|
624
659
|
"https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v3.json"
|
|
625
660
|
);
|
|
626
661
|
|
|
627
662
|
expect(chain[3].txHash).toBe(response4.txId!);
|
|
628
|
-
expect(chain[3].
|
|
663
|
+
expect(chain[3].uris[0]).toBe(
|
|
664
|
+
"mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v4.json"
|
|
665
|
+
);
|
|
666
|
+
expect(chain[3].httpsUrl).toBe(
|
|
629
667
|
"https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v4.json"
|
|
630
668
|
);
|
|
631
669
|
|
|
@@ -679,7 +717,10 @@ describe(`Test BCMR support`, () => {
|
|
|
679
717
|
expect(chain[0].contentHash).toBe(
|
|
680
718
|
"516d62577247354173703569476d557751486f67534a47525832367a75526e754c575079745a66694c3735735a76"
|
|
681
719
|
);
|
|
682
|
-
expect(chain[0].
|
|
720
|
+
expect(chain[0].uris[0]).toBe(
|
|
721
|
+
"ipfs://QmbWrG5Asp5iGmUwQHogSJGRX26zuRnuLWPytZfiL75sZv"
|
|
722
|
+
);
|
|
723
|
+
expect(chain[0].httpsUrl).toBe(
|
|
683
724
|
"https://dweb.link/ipfs/QmbWrG5Asp5iGmUwQHogSJGRX26zuRnuLWPytZfiL75sZv"
|
|
684
725
|
);
|
|
685
726
|
expect(chain[0].txHash).toBe(genesisResponse.txId);
|
|
@@ -715,7 +756,10 @@ describe(`Test BCMR support`, () => {
|
|
|
715
756
|
});
|
|
716
757
|
expect(chain.length).toBe(1);
|
|
717
758
|
expect(chain[0].contentHash).toBe(binToHex(contentHashBin));
|
|
718
|
-
expect(chain[0].
|
|
759
|
+
expect(chain[0].uris[0]).toBe(
|
|
760
|
+
"mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json"
|
|
761
|
+
);
|
|
762
|
+
expect(chain[0].httpsUrl).toBe(
|
|
719
763
|
"https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json"
|
|
720
764
|
);
|
|
721
765
|
expect(chain[0].txHash).toBe(response.txId);
|
|
@@ -749,13 +793,19 @@ describe(`Test BCMR support`, () => {
|
|
|
749
793
|
});
|
|
750
794
|
expect(gappedChain.length).toBe(2);
|
|
751
795
|
expect(gappedChain[0].contentHash).toBe(binToHex(contentHashBin));
|
|
752
|
-
expect(gappedChain[0].
|
|
796
|
+
expect(gappedChain[0].uris[0]).toBe(
|
|
797
|
+
"mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json"
|
|
798
|
+
);
|
|
799
|
+
expect(gappedChain[0].httpsUrl).toBe(
|
|
753
800
|
"https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json"
|
|
754
801
|
);
|
|
755
802
|
expect(gappedChain[0].txHash).toBe(response.txId);
|
|
756
803
|
|
|
757
804
|
expect(gappedChain[1].contentHash).toBe(binToHex(contentHashBin));
|
|
758
|
-
expect(gappedChain[1].
|
|
805
|
+
expect(gappedChain[1].uris[0]).toBe(
|
|
806
|
+
"mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json"
|
|
807
|
+
);
|
|
808
|
+
expect(gappedChain[1].httpsUrl).toBe(
|
|
759
809
|
"https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry.json"
|
|
760
810
|
);
|
|
761
811
|
expect(gappedChain[1].txHash).toBe(chainHeadResponse.txId);
|
package/src/wallet/Bcmr.ts
CHANGED
|
@@ -14,11 +14,13 @@ import ElectrumNetworkProvider from "../network/ElectrumNetworkProvider.js";
|
|
|
14
14
|
import { ElectrumRawTransaction } from "../network/interface.js";
|
|
15
15
|
import { IdentitySnapshot, Registry } from "./bcmr-v2.schema.js";
|
|
16
16
|
import { initProvider } from "../network/Connection.js";
|
|
17
|
+
import { OpReturnData } from "./model.js";
|
|
17
18
|
|
|
18
19
|
export interface AuthChainElement {
|
|
19
20
|
txHash: string;
|
|
20
21
|
contentHash: string;
|
|
21
|
-
|
|
22
|
+
uris: string[];
|
|
23
|
+
httpsUrl: string;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
export type AuthChain = AuthChainElement[];
|
|
@@ -236,58 +238,62 @@ export class BCMR {
|
|
|
236
238
|
return {
|
|
237
239
|
txHash: hash,
|
|
238
240
|
contentHash: "",
|
|
239
|
-
|
|
241
|
+
uris: [],
|
|
242
|
+
httpsUrl: "",
|
|
240
243
|
};
|
|
241
244
|
}
|
|
242
245
|
|
|
243
246
|
const opReturnHex = opReturns[0];
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
let position = 1;
|
|
247
|
-
|
|
248
|
-
// handle direct push, OP_PUSHDATA1, OP_PUSHDATA2;
|
|
249
|
-
// OP_PUSHDATA4 is not supported in OP_RETURNs by consensus
|
|
250
|
-
while (opReturn[position]) {
|
|
251
|
-
let length = 0;
|
|
252
|
-
if (opReturn[position] === 0x4c) {
|
|
253
|
-
length = opReturn[position + 1];
|
|
254
|
-
position += 2;
|
|
255
|
-
} else if (opReturn[position] === 0x4d) {
|
|
256
|
-
length = binToNumberUint16LE(
|
|
257
|
-
opReturn.slice(position + 1, position + 3)
|
|
258
|
-
);
|
|
259
|
-
position += 3;
|
|
260
|
-
} else {
|
|
261
|
-
length = opReturn[position];
|
|
262
|
-
position += 1;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
chunks.push(opReturn.slice(position, position + length));
|
|
266
|
-
position += length;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
if (chunks.length < 2 || chunks.length > 3) {
|
|
247
|
+
const chunks = OpReturnData.parseBinary(hexToBin(opReturnHex));
|
|
248
|
+
if (chunks.length < 2) {
|
|
270
249
|
throw new Error(`Malformed BCMR output: ${opReturnHex}`);
|
|
271
250
|
}
|
|
272
251
|
|
|
273
252
|
const result: AuthChainElement = {
|
|
274
253
|
txHash: hash,
|
|
275
254
|
contentHash: "",
|
|
276
|
-
|
|
255
|
+
uris: [],
|
|
256
|
+
httpsUrl: "",
|
|
277
257
|
};
|
|
278
258
|
|
|
279
259
|
if (chunks.length === 2) {
|
|
280
260
|
// IPFS Publication Output
|
|
281
261
|
result.contentHash = binToHex(chunks[1]);
|
|
282
262
|
const ipfsCid = binToUtf8(chunks[1]);
|
|
283
|
-
result.
|
|
263
|
+
result.uris = [`ipfs://${ipfsCid}`];
|
|
264
|
+
result.httpsUrl = `https://dweb.link/ipfs/${ipfsCid}`;
|
|
284
265
|
} else {
|
|
285
|
-
//
|
|
266
|
+
// URI Publication Output
|
|
286
267
|
// content hash is in OP_SHA256 byte order per spec
|
|
287
268
|
result.contentHash = binToHex(chunks[1].slice());
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
269
|
+
|
|
270
|
+
const uris = chunks.slice(2);
|
|
271
|
+
|
|
272
|
+
for (const uri of uris) {
|
|
273
|
+
const uriString = binToUtf8(uri);
|
|
274
|
+
result.uris.push(uriString);
|
|
275
|
+
|
|
276
|
+
if (result.httpsUrl) {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (uriString.indexOf("https://") === 0) {
|
|
281
|
+
result.httpsUrl = uriString;
|
|
282
|
+
} else if (uriString.indexOf("https://") === -1) {
|
|
283
|
+
result.httpsUrl = uriString;
|
|
284
|
+
|
|
285
|
+
// case for domain name specifier, like example.com
|
|
286
|
+
if (uriString.indexOf("/") === -1) {
|
|
287
|
+
result.httpsUrl = `${result.httpsUrl}/.well-known/bitcoin-cash-metadata-registry.json`
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
result.httpsUrl = `https://${result.httpsUrl}`;
|
|
291
|
+
} else if (uriString.indexOf("ipfs://") === 0 ) {
|
|
292
|
+
const ipfsCid = uriString.replace("ipfs://", "");
|
|
293
|
+
result.httpsUrl = `https://dweb.link/ipfs/${ipfsCid}`
|
|
294
|
+
} else {
|
|
295
|
+
throw new Error(`Unsupported uri type: ${uriString}`)
|
|
296
|
+
}
|
|
291
297
|
}
|
|
292
298
|
}
|
|
293
299
|
return result;
|
|
@@ -317,7 +323,7 @@ export class BCMR {
|
|
|
317
323
|
if (options.resolveBase) {
|
|
318
324
|
// check for accelerated path if "authchain" extension is in registry
|
|
319
325
|
const registry: Registry = await this.fetchMetadataRegistry(
|
|
320
|
-
element.
|
|
326
|
+
element.httpsUrl,
|
|
321
327
|
element.contentHash
|
|
322
328
|
);
|
|
323
329
|
if (
|
|
@@ -379,13 +385,13 @@ export class BCMR {
|
|
|
379
385
|
|
|
380
386
|
// combine the authchain element with the rest obtained
|
|
381
387
|
return [...chainBase, element, ...chainHead].filter(
|
|
382
|
-
(val) => val.
|
|
388
|
+
(val) => val.httpsUrl.length
|
|
383
389
|
);
|
|
384
390
|
}
|
|
385
391
|
}
|
|
386
392
|
|
|
387
393
|
// return the last chain element (or the only found in an edge case)
|
|
388
|
-
return [...chainBase, element].filter((val) => val.
|
|
394
|
+
return [...chainBase, element].filter((val) => val.httpsUrl.length);
|
|
389
395
|
}
|
|
390
396
|
|
|
391
397
|
/**
|
|
@@ -420,7 +426,7 @@ export class BCMR {
|
|
|
420
426
|
}
|
|
421
427
|
|
|
422
428
|
const registry = await this.fetchMetadataRegistry(
|
|
423
|
-
authChain.reverse()[0].
|
|
429
|
+
authChain.reverse()[0].httpsUrl
|
|
424
430
|
);
|
|
425
431
|
|
|
426
432
|
this.addMetadataRegistry(registry);
|