@btc-vision/transaction 1.7.31 → 1.8.0-alpha.2

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 (64) hide show
  1. package/AUDIT/README.md +9 -0
  2. package/CHANGELOG.md +5 -0
  3. package/README.md +62 -18
  4. package/SECURITY.md +71 -0
  5. package/browser/_version.d.ts +1 -1
  6. package/browser/abi/ABICoder.d.ts +8 -0
  7. package/browser/buffer/BinaryReader.d.ts +16 -1
  8. package/browser/buffer/BinaryWriter.d.ts +11 -1
  9. package/browser/deterministic/ExtendedAddressMap.d.ts +19 -0
  10. package/browser/index.js +1201 -874
  11. package/browser/keypair/Address.d.ts +4 -1
  12. package/browser/mnemonic/Mnemonic.d.ts +1 -1
  13. package/browser/noble-curves.js +1087 -1116
  14. package/browser/noble-hashes.js +25 -25
  15. package/browser/opnet.d.ts +1 -0
  16. package/browser/transaction/browser/WalletNetworks.d.ts +3 -3
  17. package/browser/transaction/browser/types/Unisat.d.ts +2 -2
  18. package/browser/utils/lengths.d.ts +3 -1
  19. package/browser/utils/types.d.ts +3 -0
  20. package/browser/vendors.js +950 -911
  21. package/build/_version.d.ts +1 -1
  22. package/build/_version.js +1 -1
  23. package/build/abi/ABICoder.d.ts +8 -0
  24. package/build/abi/ABICoder.js +32 -0
  25. package/build/buffer/BinaryReader.d.ts +16 -1
  26. package/build/buffer/BinaryReader.js +66 -1
  27. package/build/buffer/BinaryWriter.d.ts +11 -1
  28. package/build/buffer/BinaryWriter.js +66 -1
  29. package/build/deterministic/ExtendedAddressMap.d.ts +19 -0
  30. package/build/deterministic/ExtendedAddressMap.js +87 -0
  31. package/build/keypair/Address.d.ts +4 -1
  32. package/build/keypair/Address.js +48 -13
  33. package/build/mnemonic/Mnemonic.d.ts +1 -1
  34. package/build/mnemonic/Mnemonic.js +2 -2
  35. package/build/opnet.d.ts +1 -0
  36. package/build/opnet.js +1 -0
  37. package/build/transaction/browser/WalletNetworks.d.ts +3 -3
  38. package/build/transaction/browser/WalletNetworks.js +3 -3
  39. package/build/transaction/browser/extensions/UnisatSigner.js +3 -3
  40. package/build/transaction/browser/types/Unisat.d.ts +2 -2
  41. package/build/transaction/builders/MultiSignTransaction.js +2 -2
  42. package/build/transaction/shared/TweakedTransaction.js +3 -3
  43. package/build/tsconfig.build.tsbuildinfo +1 -1
  44. package/build/utils/lengths.d.ts +3 -1
  45. package/build/utils/lengths.js +3 -1
  46. package/build/utils/types.d.ts +3 -0
  47. package/package.json +13 -13
  48. package/src/_version.ts +1 -1
  49. package/src/abi/ABICoder.ts +43 -0
  50. package/src/buffer/BinaryReader.ts +158 -2
  51. package/src/buffer/BinaryWriter.ts +143 -1
  52. package/src/deterministic/ExtendedAddressMap.ts +122 -0
  53. package/src/keypair/Address.ts +79 -14
  54. package/src/mnemonic/Mnemonic.ts +2 -2
  55. package/src/opnet.ts +1 -0
  56. package/src/transaction/browser/WalletNetworks.ts +3 -3
  57. package/src/transaction/browser/extensions/UnisatSigner.ts +3 -3
  58. package/src/transaction/browser/types/Unisat.ts +2 -2
  59. package/src/transaction/builders/MultiSignTransaction.ts +2 -2
  60. package/src/transaction/shared/TweakedTransaction.ts +3 -3
  61. package/src/utils/lengths.ts +3 -1
  62. package/src/utils/types.ts +4 -1
  63. package/test/binary-reader-writer.test.ts +457 -0
  64. package/test/derivePath.test.ts +26 -25
@@ -32,6 +32,7 @@ export class Address extends Uint8Array {
32
32
  #p2wda: IP2WSHAddress | undefined;
33
33
  #mldsaPublicKey: Uint8Array | undefined;
34
34
  #cachedBigInt: bigint | undefined;
35
+ #cachedBigIntTweaked: bigint | undefined;
35
36
  #cachedUint64Array: [bigint, bigint, bigint, bigint] | undefined;
36
37
  #originalMDLSAPublicKey: Uint8Array | undefined;
37
38
  #mldsaLevel: MLDSASecurityLevel | undefined;
@@ -192,6 +193,7 @@ export class Address extends Uint8Array {
192
193
  * This is the inverse operation of toBigInt().
193
194
  *
194
195
  * @param {bigint} value - The 256-bit unsigned integer to convert (0 to 2^256-1)
196
+ * @param {bigint} [tweakedValue] - Optional tweaked public key as a 256-bit unsigned integer
195
197
  * @returns {Address} A new Address instance containing the converted value
196
198
  *
197
199
  * @throws {RangeError} If the value is negative or exceeds 2^256-1
@@ -203,16 +205,12 @@ export class Address extends Uint8Array {
203
205
  * console.log(address.toHex()); // 0x0000000000000000000000000000000000000000000000000000abc123...
204
206
  * ```
205
207
  */
206
- public static fromBigInt(value: bigint): Address {
207
- const buffer = new Uint8Array(32);
208
- const view = new DataView(buffer.buffer);
209
-
210
- view.setBigUint64(0, (value >> 192n) & 0xffffffffffffffffn, false);
211
- view.setBigUint64(8, (value >> 128n) & 0xffffffffffffffffn, false);
212
- view.setBigUint64(16, (value >> 64n) & 0xffffffffffffffffn, false);
213
- view.setBigUint64(24, value & 0xffffffffffffffffn, false);
208
+ public static fromBigInt(value: bigint, tweakedValue?: bigint): Address {
209
+ const address = Address.bigintToUint8Array(value);
210
+ const legacyAddress =
211
+ tweakedValue !== undefined ? Address.bigintToUint8Array(tweakedValue) : undefined;
214
212
 
215
- return new Address(buffer);
213
+ return new Address(address, legacyAddress);
216
214
  }
217
215
 
218
216
  /**
@@ -253,6 +251,18 @@ export class Address extends Uint8Array {
253
251
  return new Address(buffer);
254
252
  }
255
253
 
254
+ private static bigintToUint8Array(value: bigint): Uint8Array {
255
+ const buffer = new Uint8Array(32);
256
+ const view = new DataView(buffer.buffer);
257
+
258
+ view.setBigUint64(0, (value >> 192n) & 0xffffffffffffffffn, false);
259
+ view.setBigUint64(8, (value >> 128n) & 0xffffffffffffffffn, false);
260
+ view.setBigUint64(16, (value >> 64n) & 0xffffffffffffffffn, false);
261
+ view.setBigUint64(24, value & 0xffffffffffffffffn, false);
262
+
263
+ return buffer;
264
+ }
265
+
256
266
  /**
257
267
  * Converts the address to four 64-bit unsigned integers.
258
268
  *
@@ -419,6 +429,41 @@ export class Address extends Uint8Array {
419
429
  return this.#cachedBigInt;
420
430
  }
421
431
 
432
+ /**
433
+ * Converts the tweaked public key to a BigInt representation.
434
+ *
435
+ * This method uses an optimized DataView approach to read the 32-byte address
436
+ * as four 64-bit big-endian unsigned integers, then combines them using bitwise
437
+ * operations. This is approximately 10-20x faster than string-based conversion.
438
+ *
439
+ * @returns {bigint} The address as a 256-bit unsigned integer
440
+ *
441
+ * @example
442
+ * ```typescript
443
+ * const address = Address.fromString('0x0123456789abcdef...', '0xtweaked...');
444
+ * const bigIntValue = address.tweakedToBigInt();
445
+ * console.log(bigIntValue); // 123456789...n
446
+ * ```
447
+ */
448
+ public tweakedToBigInt(): bigint {
449
+ if (!this.legacyPublicKey) {
450
+ throw new Error('Legacy public key not set');
451
+ }
452
+
453
+ if (this.#cachedBigIntTweaked !== undefined) {
454
+ return this.#cachedBigIntTweaked;
455
+ }
456
+
457
+ const view = new DataView(this.legacyPublicKey.buffer, this.byteOffset, 32);
458
+ this.#cachedBigIntTweaked =
459
+ (view.getBigUint64(0, false) << 192n) |
460
+ (view.getBigUint64(8, false) << 128n) |
461
+ (view.getBigUint64(16, false) << 64n) |
462
+ view.getBigUint64(24, false);
463
+
464
+ return this.#cachedBigIntTweaked;
465
+ }
466
+
422
467
  public equals(a: Address): boolean {
423
468
  const b: Address = this as Address;
424
469
 
@@ -725,6 +770,7 @@ export class Address extends Uint8Array {
725
770
 
726
771
  public toTweakedHybridPublicKeyHex(): string {
727
772
  this.ensureLegacyProcessed();
773
+ this.ensureTweakedUncompressed();
728
774
  if (!this.#tweakedUncompressed) {
729
775
  throw new Error('Legacy public key not set');
730
776
  }
@@ -734,6 +780,7 @@ export class Address extends Uint8Array {
734
780
 
735
781
  public toTweakedHybridPublicKeyBuffer(): Buffer {
736
782
  this.ensureLegacyProcessed();
783
+ this.ensureTweakedUncompressed();
737
784
  if (!this.#tweakedUncompressed) {
738
785
  throw new Error('Legacy public key not set');
739
786
  }
@@ -741,6 +788,29 @@ export class Address extends Uint8Array {
741
788
  return this.#tweakedUncompressed;
742
789
  }
743
790
 
791
+ /**
792
+ * Lazily generates the tweaked uncompressed/hybrid key from the legacy public key.
793
+ * Only called when toTweakedHybridPublicKey* methods are accessed.
794
+ */
795
+ private ensureTweakedUncompressed(): void {
796
+ if (this.#tweakedUncompressed) return;
797
+
798
+ const key = this.#legacyPublicKey;
799
+ if (!key) return;
800
+
801
+ // Only attempt hybrid key generation for 32-byte keys that weren't processed through autoFormat
802
+ if (key.length === ADDRESS_BYTE_LENGTH && !this.#originalPublicKey) {
803
+ try {
804
+ const buf = Buffer.alloc(ADDRESS_BYTE_LENGTH);
805
+ buf.set(key);
806
+ this.#tweakedUncompressed = ContractAddress.generateHybridKeyFromHash(buf);
807
+ } catch {
808
+ // Hybrid key generation may fail for keys that aren't valid EC points
809
+ // (e.g., zero addresses). Leave #tweakedUncompressed undefined.
810
+ }
811
+ }
812
+ }
813
+
744
814
  /**
745
815
  * Sets the MLDSA key portion of the address.
746
816
  * @param {ArrayLike<number>} mldsaPublicKey - The MLDSA public key or its hash
@@ -793,11 +863,6 @@ export class Address extends Uint8Array {
793
863
  // Length validation already done in constructor
794
864
 
795
865
  if (pending.length === ADDRESS_BYTE_LENGTH) {
796
- // 32-byte input: already tweaked x-only, just generate hybrid
797
- const buf = Buffer.alloc(ADDRESS_BYTE_LENGTH);
798
- buf.set(pending);
799
-
800
- this.#tweakedUncompressed = ContractAddress.generateHybridKeyFromHash(buf);
801
866
  this.#legacyPublicKey = pending;
802
867
  } else {
803
868
  // 33 or 65 bytes: full autoFormat processing with EC operations
@@ -263,7 +263,7 @@ export class Mnemonic {
263
263
  * @param isChange - Whether this is a change address (default: false)
264
264
  * @returns A Wallet instance with both classical and quantum keys
265
265
  */
266
- public deriveUnisat(
266
+ public deriveOPWallet(
267
267
  addressType: AddressTypes = AddressTypes.P2TR,
268
268
  index: number = 0,
269
269
  account: number = 0,
@@ -338,7 +338,7 @@ export class Mnemonic {
338
338
  const wallets: Wallet[] = [];
339
339
 
340
340
  for (let i = 0; i < count; i++) {
341
- wallets.push(this.deriveUnisat(addressType, startIndex + i, account, isChange));
341
+ wallets.push(this.deriveOPWallet(addressType, startIndex + i, account, isChange));
342
342
  }
343
343
 
344
344
  return wallets;
package/src/opnet.ts CHANGED
@@ -125,6 +125,7 @@ export * from './abi/ABICoder.js';
125
125
  export * from './buffer/BinaryReader.js';
126
126
  export * from './buffer/BinaryWriter.js';
127
127
  export * from './deterministic/AddressMap.js';
128
+ export * from './deterministic/ExtendedAddressMap.js';
128
129
  export * from './deterministic/AddressSet.js';
129
130
  export * from './deterministic/DeterministicMap.js';
130
131
  export * from './deterministic/DeterministicSet.js';
@@ -1,7 +1,7 @@
1
1
  export enum WalletNetworks {
2
- testnet = 'testnet',
3
- mainnet = 'mainnet',
4
- regtest = 'regtest',
2
+ Mainnet = 'mainnet',
3
+ Testnet = 'testnet',
4
+ Regtest = 'regtest',
5
5
  }
6
6
 
7
7
  export enum UnisatChainType {
@@ -107,13 +107,13 @@ export class UnisatSigner extends CustomKeypair {
107
107
 
108
108
  const network = await this.unisat.getNetwork();
109
109
  switch (network) {
110
- case WalletNetworks.mainnet:
110
+ case WalletNetworks.Mainnet:
111
111
  this._network = networks.bitcoin;
112
112
  break;
113
- case WalletNetworks.testnet:
113
+ case WalletNetworks.Testnet:
114
114
  this._network = networks.testnet;
115
115
  break;
116
- case WalletNetworks.regtest:
116
+ case WalletNetworks.Regtest:
117
117
  this._network = networks.regtest;
118
118
  break;
119
119
  default:
@@ -51,8 +51,8 @@ export interface PsbtSignatureOptions {
51
51
  export interface Unisat {
52
52
  web3?: Web3Provider;
53
53
 
54
- disconnect: () => void;
55
- connect: () => void;
54
+ disconnect: () => Promise<void>;
55
+ connect: () => Promise<void>;
56
56
 
57
57
  sendBitcoin(
58
58
  toAddress: string,
@@ -227,7 +227,7 @@ export class MultiSignTransaction extends TransactionBuilder<TransactionType.MUL
227
227
  input.tapScriptSig = (input.tapScriptSig || []).concat(partialSignatures);
228
228
  }
229
229
 
230
- delete input.finalScriptWitness;
230
+ Reflect.deleteProperty(input, 'finalScriptWitness');
231
231
 
232
232
  const signHashTypes: number[] = MultiSignTransaction.signHashTypesArray
233
233
  ? [MultiSignTransaction.calculateSignHash(MultiSignTransaction.signHashTypesArray)]
@@ -397,7 +397,7 @@ export class MultiSignTransaction extends TransactionBuilder<TransactionType.MUL
397
397
  );
398
398
  }
399
399
 
400
- delete input.finalScriptWitness;
400
+ Reflect.deleteProperty(input, 'finalScriptWitness');
401
401
 
402
402
  psbt.finalizeInput(
403
403
  i,
@@ -948,18 +948,18 @@ export abstract class TweakedTransaction extends Logger {
948
948
  if (isP2WPKH(redeemOutput)) {
949
949
  // P2SH-P2WPKH
950
950
  // Use witnessUtxo + redeemScript
951
- delete input.nonWitnessUtxo; // ensure we do NOT have nonWitnessUtxo
951
+ Reflect.deleteProperty(input, 'nonWitnessUtxo'); // ensure we do NOT have nonWitnessUtxo
952
952
  // witnessScript is not needed
953
953
  } else if (isP2WSHScript(redeemOutput)) {
954
954
  // P2SH-P2WSH
955
955
  // Use witnessUtxo + redeemScript + witnessScript
956
- delete input.nonWitnessUtxo; // ensure we do NOT have nonWitnessUtxo
956
+ Reflect.deleteProperty(input, 'nonWitnessUtxo'); // ensure we do NOT have nonWitnessUtxo
957
957
 
958
958
  this.processP2WSHInput(utxo, input, i);
959
959
  } else {
960
960
  // Legacy P2SH
961
961
  // Use nonWitnessUtxo
962
- delete input.witnessUtxo; // ensure we do NOT have witnessUtxo
962
+ Reflect.deleteProperty(input, 'witnessUtxo'); // ensure we do NOT have witnessUtxo
963
963
  }
964
964
  }
965
965
 
@@ -1,4 +1,6 @@
1
1
  export const ADDRESS_BYTE_LENGTH: number = 32;
2
+ export const EXTENDED_ADDRESS_BYTE_LENGTH: number = 64;
3
+ export const SCHNORR_SIGNATURE_BYTE_LENGTH: number = 64;
2
4
  export const SELECTOR_BYTE_LENGTH: number = 4;
3
5
 
4
6
  export const U256_BYTE_LENGTH: number = 32;
@@ -11,7 +13,7 @@ export const U8_BYTE_LENGTH: number = 1;
11
13
  export const I256_BYTE_LENGTH: number = 32;
12
14
  export const I128_BYTE_LENGTH: number = 16;
13
15
  export const I64_BYTE_LENGTH: number = 8;
14
- export const number_BYTE_LENGTH: number = 4;
16
+ export const I32_BYTE_LENGTH: number = 4;
15
17
  export const I16_BYTE_LENGTH: number = 2;
16
18
  export const I8_BYTE_LENGTH: number = 1;
17
19
 
@@ -8,11 +8,14 @@ export type MemorySlotData<T> = T;
8
8
  export type PointerStorage = DeterministicMap<MemorySlotPointer, MemorySlotData<bigint>>;
9
9
  export type BlockchainStorage = DeterministicMap<string, PointerStorage>;
10
10
 
11
+ export type i8 = number;
12
+ export type i16 = number;
11
13
  export type i32 = number;
14
+ export type i64 = bigint;
15
+
12
16
  export type u8 = number;
13
17
  export type u16 = number;
14
18
  export type u32 = number;
15
-
16
19
  export type u64 = bigint;
17
20
 
18
21
  export type Selector = number;