@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.
- package/AUDIT/README.md +9 -0
- package/CHANGELOG.md +5 -0
- package/README.md +62 -18
- package/SECURITY.md +71 -0
- package/browser/_version.d.ts +1 -1
- package/browser/abi/ABICoder.d.ts +8 -0
- package/browser/buffer/BinaryReader.d.ts +16 -1
- package/browser/buffer/BinaryWriter.d.ts +11 -1
- package/browser/deterministic/ExtendedAddressMap.d.ts +19 -0
- package/browser/index.js +1201 -874
- package/browser/keypair/Address.d.ts +4 -1
- package/browser/mnemonic/Mnemonic.d.ts +1 -1
- package/browser/noble-curves.js +1087 -1116
- package/browser/noble-hashes.js +25 -25
- package/browser/opnet.d.ts +1 -0
- package/browser/transaction/browser/WalletNetworks.d.ts +3 -3
- package/browser/transaction/browser/types/Unisat.d.ts +2 -2
- package/browser/utils/lengths.d.ts +3 -1
- package/browser/utils/types.d.ts +3 -0
- package/browser/vendors.js +950 -911
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/abi/ABICoder.d.ts +8 -0
- package/build/abi/ABICoder.js +32 -0
- package/build/buffer/BinaryReader.d.ts +16 -1
- package/build/buffer/BinaryReader.js +66 -1
- package/build/buffer/BinaryWriter.d.ts +11 -1
- package/build/buffer/BinaryWriter.js +66 -1
- package/build/deterministic/ExtendedAddressMap.d.ts +19 -0
- package/build/deterministic/ExtendedAddressMap.js +87 -0
- package/build/keypair/Address.d.ts +4 -1
- package/build/keypair/Address.js +48 -13
- package/build/mnemonic/Mnemonic.d.ts +1 -1
- package/build/mnemonic/Mnemonic.js +2 -2
- package/build/opnet.d.ts +1 -0
- package/build/opnet.js +1 -0
- package/build/transaction/browser/WalletNetworks.d.ts +3 -3
- package/build/transaction/browser/WalletNetworks.js +3 -3
- package/build/transaction/browser/extensions/UnisatSigner.js +3 -3
- package/build/transaction/browser/types/Unisat.d.ts +2 -2
- package/build/transaction/builders/MultiSignTransaction.js +2 -2
- package/build/transaction/shared/TweakedTransaction.js +3 -3
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/build/utils/lengths.d.ts +3 -1
- package/build/utils/lengths.js +3 -1
- package/build/utils/types.d.ts +3 -0
- package/package.json +13 -13
- package/src/_version.ts +1 -1
- package/src/abi/ABICoder.ts +43 -0
- package/src/buffer/BinaryReader.ts +158 -2
- package/src/buffer/BinaryWriter.ts +143 -1
- package/src/deterministic/ExtendedAddressMap.ts +122 -0
- package/src/keypair/Address.ts +79 -14
- package/src/mnemonic/Mnemonic.ts +2 -2
- package/src/opnet.ts +1 -0
- package/src/transaction/browser/WalletNetworks.ts +3 -3
- package/src/transaction/browser/extensions/UnisatSigner.ts +3 -3
- package/src/transaction/browser/types/Unisat.ts +2 -2
- package/src/transaction/builders/MultiSignTransaction.ts +2 -2
- package/src/transaction/shared/TweakedTransaction.ts +3 -3
- package/src/utils/lengths.ts +3 -1
- package/src/utils/types.ts +4 -1
- package/test/binary-reader-writer.test.ts +457 -0
- package/test/derivePath.test.ts +26 -25
package/src/keypair/Address.ts
CHANGED
|
@@ -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
|
|
208
|
-
const
|
|
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(
|
|
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
|
package/src/mnemonic/Mnemonic.ts
CHANGED
|
@@ -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
|
|
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.
|
|
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';
|
|
@@ -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.
|
|
110
|
+
case WalletNetworks.Mainnet:
|
|
111
111
|
this._network = networks.bitcoin;
|
|
112
112
|
break;
|
|
113
|
-
case WalletNetworks.
|
|
113
|
+
case WalletNetworks.Testnet:
|
|
114
114
|
this._network = networks.testnet;
|
|
115
115
|
break;
|
|
116
|
-
case WalletNetworks.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
962
|
+
Reflect.deleteProperty(input, 'witnessUtxo'); // ensure we do NOT have witnessUtxo
|
|
963
963
|
}
|
|
964
964
|
}
|
|
965
965
|
|
package/src/utils/lengths.ts
CHANGED
|
@@ -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
|
|
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
|
|
package/src/utils/types.ts
CHANGED
|
@@ -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;
|