mainnet-js 2.7.22 → 2.7.24

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.
Files changed (42) hide show
  1. package/dist/index.html +1 -1
  2. package/dist/{mainnet-2.7.22.js → mainnet-2.7.24.js} +4 -24
  3. package/dist/module/index.d.ts +0 -2
  4. package/dist/module/index.d.ts.map +1 -1
  5. package/dist/module/index.js +0 -2
  6. package/dist/module/index.js.map +1 -1
  7. package/dist/module/network/index.d.ts +1 -1
  8. package/dist/module/network/index.d.ts.map +1 -1
  9. package/dist/module/network/index.js +1 -1
  10. package/dist/module/network/index.js.map +1 -1
  11. package/dist/module/util/index.d.ts +0 -1
  12. package/dist/module/util/index.d.ts.map +1 -1
  13. package/dist/module/util/index.js +0 -1
  14. package/dist/module/util/index.js.map +1 -1
  15. package/dist/module/wallet/Base.d.ts +1 -2
  16. package/dist/module/wallet/Base.d.ts.map +1 -1
  17. package/dist/module/wallet/Base.js +0 -4
  18. package/dist/module/wallet/Base.js.map +1 -1
  19. package/dist/tsconfig.tsbuildinfo +1 -1
  20. package/package.json +1 -1
  21. package/src/index.ts +0 -2
  22. package/src/network/index.ts +1 -0
  23. package/src/util/index.ts +0 -1
  24. package/src/wallet/Base.ts +0 -9
  25. package/dist/module/util/walletConnect.d.ts +0 -22
  26. package/dist/module/util/walletConnect.d.ts.map +0 -1
  27. package/dist/module/util/walletConnect.js +0 -57
  28. package/dist/module/util/walletConnect.js.map +0 -1
  29. package/dist/module/wallet/Bcmr.d.ts +0 -108
  30. package/dist/module/wallet/Bcmr.d.ts.map +0 -1
  31. package/dist/module/wallet/Bcmr.js +0 -413
  32. package/dist/module/wallet/Bcmr.js.map +0 -1
  33. package/dist/module/wallet/bcmr-v2.schema.d.ts +0 -833
  34. package/dist/module/wallet/bcmr-v2.schema.d.ts.map +0 -1
  35. package/dist/module/wallet/bcmr-v2.schema.js +0 -2
  36. package/dist/module/wallet/bcmr-v2.schema.js.map +0 -1
  37. package/src/util/walletConnect.test.ts +0 -115
  38. package/src/util/walletConnect.ts +0 -156
  39. package/src/wallet/Bcmr.test.headless.js +0 -467
  40. package/src/wallet/Bcmr.test.ts +0 -979
  41. package/src/wallet/Bcmr.ts +0 -556
  42. package/src/wallet/bcmr-v2.schema.ts +0 -893
@@ -1,556 +0,0 @@
1
- import {
2
- binToHex,
3
- binToUtf8,
4
- decodeTransaction,
5
- hexToBin,
6
- sha256,
7
- Transaction,
8
- utf8ToBin,
9
- } from "@bitauth/libauth";
10
- import { Network, TxI } from "../interface.js";
11
- import ElectrumNetworkProvider from "../network/ElectrumNetworkProvider.js";
12
- import { ElectrumRawTransaction } from "../network/interface.js";
13
- import { IdentitySnapshot, Registry } from "./bcmr-v2.schema.js";
14
- import { initProvider } from "../network/Connection.js";
15
- import { OpReturnData } from "./model.js";
16
- import { Config } from "../config.js";
17
-
18
- export interface AuthChainElement {
19
- txHash: string;
20
- contentHash: string;
21
- uris: string[];
22
- httpsUrl: string;
23
- }
24
-
25
- export type AuthChain = AuthChainElement[];
26
-
27
- // Implementation of CHIP-BCMR v2.0.0-draft, refer to https://github.com/bitjson/chip-bcmr
28
- export class BCMR {
29
- // List of tracked registries
30
- public static metadataRegistries: Registry[] = [];
31
-
32
- public static getRegistries(): Registry[] {
33
- return this.metadataRegistries;
34
- }
35
-
36
- public static resetRegistries(): void {
37
- this.metadataRegistries = [];
38
- }
39
-
40
- /**
41
- * fetchMetadataRegistry Fetch the BCMR registry JSON file from a remote URI, optionally verifying its content hash
42
- *
43
- * @param {string} uri URI of the registry to fetch from
44
- * @param {string?} contentHash SHA256 hash of the resource the `uri` parameter points at.
45
- * If specified, calculates the hash of the data fetched from `uri` and matches it with provided one.
46
- * Yields an error upon mismatch.
47
- *
48
- * @returns {Registry} resolved registry
49
- */
50
- public static async fetchMetadataRegistry(
51
- uri: string,
52
- contentHash?: string
53
- ): Promise<Registry> {
54
- if (uri.indexOf("https://") < 0) {
55
- uri = `https://${uri}`;
56
- }
57
-
58
- // content hashes HTTPS Publication Outputs per spec
59
- if (contentHash) {
60
- // request as text and verify hash
61
- const response = await fetch(uri);
62
- const data = await response.text();
63
- const hash = binToHex(sha256.hash(utf8ToBin(data)));
64
- if (contentHash != hash) {
65
- throw new Error(
66
- `Content hash mismatch for URI: ${uri}\nreceived: ${hash}\nrequired: ${contentHash}`
67
- );
68
- }
69
-
70
- return JSON.parse(data) as Registry;
71
- }
72
-
73
- // request as JSON
74
- const response = await fetch(uri);
75
- const data = await response.json();
76
- return data as Registry;
77
- }
78
-
79
- /**
80
- * addMetadataRegistry Add the metadata registry to the list of tracked registries
81
- *
82
- * @param {Registry} registry Registry object per schema specification, see https://raw.githubusercontent.com/bitjson/chip-bcmr/master/bcmr-v1.schema.json
83
- *
84
- */
85
- public static addMetadataRegistry(registry: Registry): void {
86
- if (
87
- this.metadataRegistries.some(
88
- (val) => JSON.stringify(val) === JSON.stringify(registry)
89
- )
90
- ) {
91
- return;
92
- }
93
- this.metadataRegistries.push(registry);
94
- }
95
-
96
- /**
97
- * addMetadataRegistryFromUri Add the metadata registry by fetching a JSON file from a remote URI, optionally verifying its content hash
98
- *
99
- * @param {string} uri URI of the registry to fetch from
100
- * @param {string?} contentHash SHA256 hash of the resource the `uri` parameter points at.
101
- * If specified, calculates the hash of the data fetched from `uri` and matches it with provided one.
102
- * Yields an error upon mismatch.
103
- *
104
- */
105
- public static async addMetadataRegistryFromUri(
106
- uri: string,
107
- contentHash?: string
108
- ): Promise<void> {
109
- const registry = await this.fetchMetadataRegistry(uri, contentHash);
110
- this.addMetadataRegistry(registry);
111
- }
112
-
113
- // helper function to enforce the constraints on the 0th output, decode the BCMR's OP_RETURN data
114
- // returns resolved AuthChainElement
115
- public static makeAuthChainElement(
116
- rawTx: ElectrumRawTransaction | Transaction,
117
- hash: string
118
- ): AuthChainElement {
119
- let opReturns: string[];
120
- let spends0thOutput = false;
121
- if (rawTx.hasOwnProperty("vout")) {
122
- const electrumTransaction = rawTx as ElectrumRawTransaction;
123
- opReturns = electrumTransaction.vout
124
- .filter((val) => val.scriptPubKey.type === "nulldata")
125
- .map((val) => val.scriptPubKey.hex);
126
- spends0thOutput = electrumTransaction.vin.some((val) => val.vout === 0);
127
- } else {
128
- const libauthTransaction = rawTx as Transaction;
129
- opReturns = libauthTransaction.outputs
130
- .map((val) => binToHex(val.lockingBytecode))
131
- .filter((val) => val.indexOf("6a") === 0);
132
- spends0thOutput = libauthTransaction.inputs.some(
133
- (val) => val.outpointIndex === 0
134
- );
135
- }
136
-
137
- if (!spends0thOutput) {
138
- throw new Error(
139
- "Invalid authchain transaction (does not spend 0th output of previous transaction)"
140
- );
141
- }
142
-
143
- const bcmrOpReturns = opReturns.filter(
144
- (val) =>
145
- val.indexOf("6a0442434d52") === 0 ||
146
- val.indexOf("6a4c0442434d52") === 0 ||
147
- val.indexOf("6a4d040042434d52") === 0 ||
148
- val.indexOf("6a4e0400000042434d52") === 0
149
- );
150
-
151
- if (bcmrOpReturns.length === 0) {
152
- return {
153
- txHash: hash,
154
- contentHash: "",
155
- uris: [],
156
- httpsUrl: "",
157
- };
158
- }
159
-
160
- const opReturnHex = opReturns[0];
161
- const chunks = OpReturnData.parseBinary(hexToBin(opReturnHex));
162
- if (chunks.length < 2) {
163
- throw new Error(`Malformed BCMR output: ${opReturnHex}`);
164
- }
165
-
166
- const result: AuthChainElement = {
167
- txHash: hash,
168
- contentHash: "",
169
- uris: [],
170
- httpsUrl: "",
171
- };
172
-
173
- if (chunks.length === 2) {
174
- // IPFS Publication Output
175
- result.contentHash = binToHex(chunks[1]);
176
- const ipfsCid = binToUtf8(chunks[1]);
177
- result.uris = [`ipfs://${ipfsCid}`];
178
- result.httpsUrl = `${Config.DefaultIpfsGateway}${ipfsCid}`;
179
- } else {
180
- // URI Publication Output
181
- // content hash is in OP_SHA256 byte order per spec
182
- result.contentHash = binToHex(chunks[1].slice());
183
-
184
- const uris = chunks.slice(2);
185
-
186
- for (const uri of uris) {
187
- const uriString = binToUtf8(uri);
188
- result.uris.push(uriString);
189
-
190
- if (result.httpsUrl) {
191
- continue;
192
- }
193
-
194
- if (uriString.indexOf("ipfs://") === 0) {
195
- const ipfsCid = uriString.replace("ipfs://", "");
196
- result.httpsUrl = `${Config.DefaultIpfsGateway}${ipfsCid}`;
197
- } else if (uriString.indexOf("https://") === 0) {
198
- result.httpsUrl = uriString;
199
- } else if (uriString.indexOf("https://") === -1) {
200
- result.httpsUrl = uriString;
201
-
202
- // case for domain name specifier, like example.com
203
- if (uriString.indexOf("/") === -1) {
204
- const parts = uriString.toLowerCase().split(".");
205
- if (!(parts?.[0]?.indexOf("baf") === 0 && parts?.[1] === "ipfs")) {
206
- result.httpsUrl = `${result.httpsUrl}/.well-known/bitcoin-cash-metadata-registry.json`;
207
- }
208
- }
209
-
210
- result.httpsUrl = `https://${result.httpsUrl}`;
211
- } else {
212
- throw new Error(`Unsupported uri type: ${uriString}`);
213
- }
214
- }
215
- }
216
- return result;
217
- }
218
-
219
- /**
220
- * buildAuthChain Build an authchain - Zeroth-Descendant Transaction Chain, refer to https://github.com/bitjson/chip-bcmr#zeroth-descendant-transaction-chains
221
- * The authchain in this implementation is specific to resolve to a valid metadata registry
222
- *
223
- * @param {string} options.transactionHash (required) transaction hash from which to build the auth chain
224
- * @param {Network?} options.network (default=mainnet) network to query the data from
225
- * @param {boolean?} options.resolveBase (default=false) boolean flag to indicate that autchain building should resolve and verify elements back to base or be stopped at this exact chain element
226
- * @param {boolean?} options.followToHead (default=true) boolean flag to indicate that autchain building should progress to head or be stopped at this exact chain element
227
- * @param {ElectrumRawTransaction?} options.rawTx cached raw transaction obtained previously, spares a Fulcrum call
228
- * @param {TxI[]?} options.historyCache cached address history to be reused if authchain building proceeds with the same address, spares a flurry of Fulcrum calls
229
- *
230
- * @returns {AuthChain} returns the resolved authchain
231
- */
232
- public static async buildAuthChain(options: {
233
- transactionHash: string;
234
- network?: Network;
235
- resolveBase?: boolean;
236
- followToHead?: boolean;
237
- rawTx?: ElectrumRawTransaction;
238
- historyCache?: TxI[];
239
- }): Promise<AuthChain> {
240
- if (options.network === undefined) {
241
- options.network = Network.MAINNET;
242
- }
243
-
244
- if (options.followToHead === undefined) {
245
- options.followToHead = true;
246
- }
247
-
248
- if (options.resolveBase === undefined) {
249
- options.resolveBase = false;
250
- }
251
-
252
- const provider = (await initProvider(
253
- options.network
254
- )!) as ElectrumNetworkProvider;
255
-
256
- if (options.rawTx === undefined) {
257
- options.rawTx = await provider.getRawTransactionObject(
258
- options.transactionHash
259
- );
260
- }
261
-
262
- // figure out the autchain by moving towards authhead
263
- const getAuthChainChild = async () => {
264
- const history =
265
- options.historyCache ||
266
- (await provider.getHistory(
267
- options.rawTx!.vout[0].scriptPubKey.addresses[0]
268
- ));
269
- const thisTx = history.find(
270
- (val) => val.tx_hash === options.transactionHash
271
- );
272
- let filteredHistory = history.filter((val) =>
273
- val.height > 0
274
- ? val.height >= thisTx!.height || val.height <= 0
275
- : val.height <= 0 && val.tx_hash !== thisTx!.tx_hash
276
- );
277
-
278
- for (const historyTx of filteredHistory) {
279
- const historyRawTx = await provider.getRawTransactionObject(
280
- historyTx.tx_hash
281
- );
282
- const authChainVin = historyRawTx.vin.find(
283
- (val) => val.txid === options.transactionHash && val.vout === 0
284
- );
285
- // if we've found continuation of authchain, we shall recurse into it
286
- if (authChainVin) {
287
- // reuse queried address history if the next element in chain is the same address
288
- const historyCache =
289
- options.rawTx!.vout[0].scriptPubKey.addresses[0] ===
290
- historyRawTx.vout[0].scriptPubKey.addresses[0]
291
- ? filteredHistory
292
- : undefined;
293
-
294
- // combine the authchain element with the rest obtained
295
- return { rawTx: historyRawTx, historyCache };
296
- }
297
- }
298
- return undefined;
299
- };
300
-
301
- // make authchain element and combine with the rest obtained
302
- let element: AuthChainElement;
303
- try {
304
- element = BCMR.makeAuthChainElement(options.rawTx, options.rawTx.hash);
305
- } catch (error) {
306
- // special case for cashtoken authchain lookup by categoryId - allow to fail first lookup and inspect the genesis transaction
307
- // follow authchain to head and look for BCMR outputs
308
- const child = await getAuthChainChild();
309
- if (child) {
310
- return await BCMR.buildAuthChain({
311
- ...options,
312
- transactionHash: child.rawTx.hash,
313
- rawTx: child.rawTx,
314
- historyCache: child.historyCache,
315
- });
316
- } else {
317
- throw error;
318
- }
319
- }
320
-
321
- let chainBase: AuthChain = [];
322
- if (options.resolveBase) {
323
- // check for accelerated path if "authchain" extension is in registry
324
- const registry: Registry = await this.fetchMetadataRegistry(
325
- element.httpsUrl,
326
- element.contentHash
327
- );
328
- if (
329
- registry.extensions &&
330
- registry.extensions["authchain"] &&
331
- Object.keys(registry.extensions["authchain"]).length
332
- ) {
333
- const chainTxArray = Object.values(
334
- registry.extensions!["authchain"]
335
- ) as string[];
336
-
337
- chainBase = chainTxArray
338
- .map((tx) => {
339
- const transactionBin = hexToBin(tx);
340
- const decoded = decodeTransaction(transactionBin);
341
- if (typeof decoded === "string") {
342
- throw new Error(
343
- `Error decoding transaction ${JSON.stringify(tx)}, ${decoded}`
344
- );
345
- }
346
- const hash = binToHex(
347
- sha256.hash(sha256.hash(transactionBin)).reverse()
348
- );
349
- return { decoded, hash };
350
- })
351
- .map(({ decoded, hash }) => BCMR.makeAuthChainElement(decoded, hash));
352
- } else {
353
- // simply go back in history towards authhead
354
- let stop = false;
355
- let tx: ElectrumRawTransaction = { ...options.rawTx! };
356
- let maxElements = 10;
357
- while (stop == false || maxElements === 0) {
358
- const vin = tx.vin.find((val) => val.vout === 0);
359
- tx = await provider.getRawTransactionObject(vin!.txid);
360
- try {
361
- const pastElement = BCMR.makeAuthChainElement(tx, tx.hash);
362
- chainBase.unshift(pastElement);
363
- maxElements--;
364
- } catch {
365
- stop = true;
366
- }
367
- }
368
- }
369
- }
370
-
371
- // if we follow to head, we need to locate the next transaction spending our 0th output
372
- // and repeat the building process recursively
373
- if (options.followToHead) {
374
- const child = await getAuthChainChild();
375
- if (child) {
376
- const chainHead = await BCMR.buildAuthChain({
377
- transactionHash: child.rawTx.hash,
378
- network: options.network,
379
- rawTx: child.rawTx,
380
- historyCache: child.historyCache,
381
- followToHead: options.followToHead,
382
- resolveBase: false,
383
- });
384
-
385
- // combine the authchain element with the rest obtained
386
- return [...chainBase, element, ...chainHead].filter(
387
- (val) => val.httpsUrl.length
388
- );
389
- }
390
- }
391
-
392
- // return the last chain element (or the only found in an edge case)
393
- return [...chainBase, element].filter((val) => val.httpsUrl.length);
394
- }
395
-
396
- /**
397
- * fetchAuthChainFromChaingraph Fetch the authchain information from a trusted external indexer
398
- * The authchain in this implementation is specific to resolve to a valid metadata registry
399
- *
400
- * @param {string} options.chaingraphUrl (required) URL of a chaingraph indexer instance to fetch info from
401
- * @param {string} options.transactionHash (required) transaction hash from which to build the auth chain
402
- * @param {string?} options.network (default=undefined) network to query the data from, specific to the queried instance,
403
- * can be 'mainnet', 'chipnet', or anything else.
404
- * if left undefined all chaingraph transactions will be looked at, disregarding the chain
405
- *
406
- * @returns {AuthChain} returns the resolved authchain
407
- */
408
- public static async fetchAuthChainFromChaingraph(options: {
409
- chaingraphUrl: string;
410
- transactionHash: string;
411
- network?: string;
412
- }): Promise<AuthChain> {
413
- if (!options.chaingraphUrl) {
414
- throw new Error("Provide `chaingraphUrl` param.");
415
- }
416
-
417
- const response = await fetch(options.chaingraphUrl, {
418
- method: "POST",
419
- headers: {
420
- Accept: "*/*",
421
- "Content-Type": "application/json",
422
- },
423
- body: JSON.stringify({
424
- operationName: null,
425
- variables: {},
426
- query: `
427
- {
428
- transaction(
429
- where: {
430
- hash:{_eq:"\\\\x${options.transactionHash}"}
431
- }
432
- ) {
433
- hash
434
- authchains {
435
- authchain_length
436
- migrations(
437
- where: {
438
- transaction: {
439
- outputs: { locking_bytecode_pattern: { _like: "6a04%" } }
440
- }
441
- }
442
- ) {
443
- transaction {
444
- hash
445
- inputs(where:{ outpoint_index: { _eq:"0" } }){
446
- outpoint_index
447
- }
448
- outputs(where: { locking_bytecode_pattern: { _like: "6a04%" } }) {
449
- output_index
450
- locking_bytecode
451
- }
452
- }
453
- }
454
- }
455
- }
456
- }`,
457
- }),
458
- });
459
-
460
- const responseData = await response.json();
461
-
462
- const result: AuthChain = [];
463
- const migrations =
464
- responseData.data.transaction[0]?.authchains[0].migrations;
465
- if (!migrations) {
466
- return result;
467
- }
468
-
469
- for (const migration of migrations) {
470
- const transaction = migration.transaction[0];
471
- if (!transaction) {
472
- continue;
473
- }
474
- transaction.inputs.forEach(
475
- (input) => (input.outpointIndex = Number(input.outpoint_index))
476
- );
477
- transaction.outputs.forEach((output) => {
478
- output.outputIndex = Number(output.output_index);
479
- output.lockingBytecode = hexToBin(
480
- output.locking_bytecode.replace("\\x", "")
481
- );
482
- });
483
- const txHash = transaction.hash.replace("\\x", "");
484
- result.push(
485
- BCMR.makeAuthChainElement(transaction as Transaction, txHash)
486
- );
487
- }
488
-
489
- return result.filter(
490
- (element) => element.contentHash.length && element.httpsUrl.length
491
- );
492
- }
493
-
494
- /**
495
- * addMetadataRegistryAuthChain Add BCMR metadata registry by resolving an authchain
496
- *
497
- * @param {string} options.transactionHash (required) transaction hash from which to build the auth chain
498
- * @param {Network?} options.network (default=mainnet) network to query the data from
499
- * @param {boolean?} options.followToHead (default=true) boolean flag to indicate that autchain building should progress to head (most recent registry version) or be stopped at this exact chain element
500
- * @param {ElectrumRawTransaction?} options.rawTx cached raw transaction obtained previously, spares a Fulcrum call
501
- *
502
- * @returns {AuthChain} returns the resolved authchain
503
- */
504
- public static async addMetadataRegistryAuthChain(options: {
505
- transactionHash: string;
506
- network?: Network;
507
- followToHead?: boolean;
508
- rawTx?: ElectrumRawTransaction;
509
- }): Promise<AuthChain> {
510
- const authChain = await this.buildAuthChain({
511
- ...options,
512
- resolveBase: false,
513
- });
514
-
515
- if (!authChain.length) {
516
- throw new Error(
517
- `There were no BCMR entries in the resolved authchain ${JSON.stringify(
518
- authChain,
519
- null,
520
- 2
521
- )}`
522
- );
523
- }
524
-
525
- const registry = await this.fetchMetadataRegistry(
526
- authChain.reverse()[0].httpsUrl
527
- );
528
-
529
- this.addMetadataRegistry(registry);
530
- return authChain;
531
- }
532
-
533
- /**
534
- * getTokenInfo Return the token info (or the identity snapshot as per spec)
535
- *
536
- * @param {string} tokenId token id to look up
537
- *
538
- * @returns {IdentitySnapshot?} return the info for the token found, otherwise undefined
539
- */
540
- public static getTokenInfo(tokenId: string): IdentitySnapshot | undefined {
541
- for (const registry of this.metadataRegistries.slice().reverse()) {
542
- const history = registry.identities?.[tokenId];
543
- if (!history) {
544
- continue;
545
- }
546
- const latestIdentityIndex = Object.keys(history)[0];
547
- if (latestIdentityIndex === undefined) {
548
- continue;
549
- }
550
-
551
- return history[latestIdentityIndex];
552
- }
553
-
554
- return undefined;
555
- }
556
- }