@btc-vision/transaction 1.8.0-alpha.1 → 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/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 +3 -1
- package/browser/index.js +1102 -861
- package/browser/keypair/Address.d.ts +1 -0
- package/browser/utils/lengths.d.ts +3 -1
- package/browser/utils/types.d.ts +3 -0
- 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 +3 -1
- package/build/deterministic/ExtendedAddressMap.js +44 -17
- package/build/keypair/Address.d.ts +1 -0
- package/build/keypair/Address.js +19 -4
- 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 +1 -1
- 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 +59 -20
- package/src/keypair/Address.ts +27 -6
- 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 +4 -4
package/src/keypair/Address.ts
CHANGED
|
@@ -207,7 +207,8 @@ export class Address extends Uint8Array {
|
|
|
207
207
|
*/
|
|
208
208
|
public static fromBigInt(value: bigint, tweakedValue?: bigint): Address {
|
|
209
209
|
const address = Address.bigintToUint8Array(value);
|
|
210
|
-
const legacyAddress =
|
|
210
|
+
const legacyAddress =
|
|
211
|
+
tweakedValue !== undefined ? Address.bigintToUint8Array(tweakedValue) : undefined;
|
|
211
212
|
|
|
212
213
|
return new Address(address, legacyAddress);
|
|
213
214
|
}
|
|
@@ -769,6 +770,7 @@ export class Address extends Uint8Array {
|
|
|
769
770
|
|
|
770
771
|
public toTweakedHybridPublicKeyHex(): string {
|
|
771
772
|
this.ensureLegacyProcessed();
|
|
773
|
+
this.ensureTweakedUncompressed();
|
|
772
774
|
if (!this.#tweakedUncompressed) {
|
|
773
775
|
throw new Error('Legacy public key not set');
|
|
774
776
|
}
|
|
@@ -778,6 +780,7 @@ export class Address extends Uint8Array {
|
|
|
778
780
|
|
|
779
781
|
public toTweakedHybridPublicKeyBuffer(): Buffer {
|
|
780
782
|
this.ensureLegacyProcessed();
|
|
783
|
+
this.ensureTweakedUncompressed();
|
|
781
784
|
if (!this.#tweakedUncompressed) {
|
|
782
785
|
throw new Error('Legacy public key not set');
|
|
783
786
|
}
|
|
@@ -785,6 +788,29 @@ export class Address extends Uint8Array {
|
|
|
785
788
|
return this.#tweakedUncompressed;
|
|
786
789
|
}
|
|
787
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
|
+
|
|
788
814
|
/**
|
|
789
815
|
* Sets the MLDSA key portion of the address.
|
|
790
816
|
* @param {ArrayLike<number>} mldsaPublicKey - The MLDSA public key or its hash
|
|
@@ -837,11 +863,6 @@ export class Address extends Uint8Array {
|
|
|
837
863
|
// Length validation already done in constructor
|
|
838
864
|
|
|
839
865
|
if (pending.length === ADDRESS_BYTE_LENGTH) {
|
|
840
|
-
// 32-byte input: already tweaked x-only, just generate hybrid
|
|
841
|
-
const buf = Buffer.alloc(ADDRESS_BYTE_LENGTH);
|
|
842
|
-
buf.set(pending);
|
|
843
|
-
|
|
844
|
-
this.#tweakedUncompressed = ContractAddress.generateHybridKeyFromHash(buf);
|
|
845
866
|
this.#legacyPublicKey = pending;
|
|
846
867
|
} else {
|
|
847
868
|
// 33 or 65 bytes: full autoFormat processing with EC operations
|
|
@@ -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;
|
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { Address, BinaryReader, BinaryWriter, ExtendedAddressMap } from '../src/opnet.js';
|
|
3
|
+
|
|
4
|
+
describe('BinaryReader/BinaryWriter', () => {
|
|
5
|
+
// Helper to create an Address with both MLDSA and tweaked keys
|
|
6
|
+
const createFullAddress = (mldsaValue: bigint, tweakedValue: bigint): Address => {
|
|
7
|
+
return Address.fromBigInt(mldsaValue, tweakedValue);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
describe('Signed Integer Methods', () => {
|
|
11
|
+
describe('i8', () => {
|
|
12
|
+
it('should write and read positive i8', () => {
|
|
13
|
+
const writer = new BinaryWriter();
|
|
14
|
+
writer.writeI8(127);
|
|
15
|
+
writer.writeI8(0);
|
|
16
|
+
writer.writeI8(1);
|
|
17
|
+
|
|
18
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
19
|
+
expect(reader.readI8()).toBe(127);
|
|
20
|
+
expect(reader.readI8()).toBe(0);
|
|
21
|
+
expect(reader.readI8()).toBe(1);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should write and read negative i8', () => {
|
|
25
|
+
const writer = new BinaryWriter();
|
|
26
|
+
writer.writeI8(-128);
|
|
27
|
+
writer.writeI8(-1);
|
|
28
|
+
writer.writeI8(-50);
|
|
29
|
+
|
|
30
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
31
|
+
expect(reader.readI8()).toBe(-128);
|
|
32
|
+
expect(reader.readI8()).toBe(-1);
|
|
33
|
+
expect(reader.readI8()).toBe(-50);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should throw on out of range i8', () => {
|
|
37
|
+
const writer = new BinaryWriter();
|
|
38
|
+
expect(() => writer.writeI8(128)).toThrow();
|
|
39
|
+
expect(() => writer.writeI8(-129)).toThrow();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('i16', () => {
|
|
44
|
+
it('should write and read positive i16 big-endian', () => {
|
|
45
|
+
const writer = new BinaryWriter();
|
|
46
|
+
writer.writeI16(32767);
|
|
47
|
+
writer.writeI16(256);
|
|
48
|
+
writer.writeI16(0);
|
|
49
|
+
|
|
50
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
51
|
+
expect(reader.readI16()).toBe(32767);
|
|
52
|
+
expect(reader.readI16()).toBe(256);
|
|
53
|
+
expect(reader.readI16()).toBe(0);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should write and read negative i16 big-endian', () => {
|
|
57
|
+
const writer = new BinaryWriter();
|
|
58
|
+
writer.writeI16(-32768);
|
|
59
|
+
writer.writeI16(-1);
|
|
60
|
+
writer.writeI16(-256);
|
|
61
|
+
|
|
62
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
63
|
+
expect(reader.readI16()).toBe(-32768);
|
|
64
|
+
expect(reader.readI16()).toBe(-1);
|
|
65
|
+
expect(reader.readI16()).toBe(-256);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should write and read i16 little-endian', () => {
|
|
69
|
+
const writer = new BinaryWriter();
|
|
70
|
+
writer.writeI16(12345, false);
|
|
71
|
+
writer.writeI16(-12345, false);
|
|
72
|
+
|
|
73
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
74
|
+
expect(reader.readI16(false)).toBe(12345);
|
|
75
|
+
expect(reader.readI16(false)).toBe(-12345);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should throw on out of range i16', () => {
|
|
79
|
+
const writer = new BinaryWriter();
|
|
80
|
+
expect(() => writer.writeI16(32768)).toThrow();
|
|
81
|
+
expect(() => writer.writeI16(-32769)).toThrow();
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('i32', () => {
|
|
86
|
+
it('should write and read positive i32 big-endian', () => {
|
|
87
|
+
const writer = new BinaryWriter();
|
|
88
|
+
writer.writeI32(2147483647);
|
|
89
|
+
writer.writeI32(65536);
|
|
90
|
+
writer.writeI32(0);
|
|
91
|
+
|
|
92
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
93
|
+
expect(reader.readI32()).toBe(2147483647);
|
|
94
|
+
expect(reader.readI32()).toBe(65536);
|
|
95
|
+
expect(reader.readI32()).toBe(0);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should write and read negative i32 big-endian', () => {
|
|
99
|
+
const writer = new BinaryWriter();
|
|
100
|
+
writer.writeI32(-2147483648);
|
|
101
|
+
writer.writeI32(-1);
|
|
102
|
+
writer.writeI32(-65536);
|
|
103
|
+
|
|
104
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
105
|
+
expect(reader.readI32()).toBe(-2147483648);
|
|
106
|
+
expect(reader.readI32()).toBe(-1);
|
|
107
|
+
expect(reader.readI32()).toBe(-65536);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should write and read i32 little-endian', () => {
|
|
111
|
+
const writer = new BinaryWriter();
|
|
112
|
+
writer.writeI32(123456789, false);
|
|
113
|
+
writer.writeI32(-123456789, false);
|
|
114
|
+
|
|
115
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
116
|
+
expect(reader.readI32(false)).toBe(123456789);
|
|
117
|
+
expect(reader.readI32(false)).toBe(-123456789);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should throw on out of range i32', () => {
|
|
121
|
+
const writer = new BinaryWriter();
|
|
122
|
+
expect(() => writer.writeI32(2147483648)).toThrow();
|
|
123
|
+
expect(() => writer.writeI32(-2147483649)).toThrow();
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe('i64', () => {
|
|
128
|
+
it('should write and read positive i64 big-endian', () => {
|
|
129
|
+
const writer = new BinaryWriter();
|
|
130
|
+
writer.writeI64(9223372036854775807n);
|
|
131
|
+
writer.writeI64(4294967296n);
|
|
132
|
+
writer.writeI64(0n);
|
|
133
|
+
|
|
134
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
135
|
+
expect(reader.readI64()).toBe(9223372036854775807n);
|
|
136
|
+
expect(reader.readI64()).toBe(4294967296n);
|
|
137
|
+
expect(reader.readI64()).toBe(0n);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should write and read negative i64 big-endian', () => {
|
|
141
|
+
const writer = new BinaryWriter();
|
|
142
|
+
writer.writeI64(-9223372036854775808n);
|
|
143
|
+
writer.writeI64(-1n);
|
|
144
|
+
writer.writeI64(-4294967296n);
|
|
145
|
+
|
|
146
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
147
|
+
expect(reader.readI64()).toBe(-9223372036854775808n);
|
|
148
|
+
expect(reader.readI64()).toBe(-1n);
|
|
149
|
+
expect(reader.readI64()).toBe(-4294967296n);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('should write and read i64 little-endian', () => {
|
|
153
|
+
const writer = new BinaryWriter();
|
|
154
|
+
writer.writeI64(1234567890123456789n, false);
|
|
155
|
+
writer.writeI64(-1234567890123456789n, false);
|
|
156
|
+
|
|
157
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
158
|
+
expect(reader.readI64(false)).toBe(1234567890123456789n);
|
|
159
|
+
expect(reader.readI64(false)).toBe(-1234567890123456789n);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('should throw on out of range i64', () => {
|
|
163
|
+
const writer = new BinaryWriter();
|
|
164
|
+
expect(() => writer.writeI64(9223372036854775808n)).toThrow();
|
|
165
|
+
expect(() => writer.writeI64(-9223372036854775809n)).toThrow();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe('Extended Address Methods', () => {
|
|
171
|
+
describe('readExtendedAddress / writeExtendedAddress', () => {
|
|
172
|
+
it('should write and read extended address', () => {
|
|
173
|
+
const writer = new BinaryWriter();
|
|
174
|
+
const address = createFullAddress(123n, 456n);
|
|
175
|
+
|
|
176
|
+
writer.writeExtendedAddress(address);
|
|
177
|
+
|
|
178
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
179
|
+
const result = reader.readExtendedAddress();
|
|
180
|
+
|
|
181
|
+
expect(result.toBigInt()).toBe(123n);
|
|
182
|
+
expect(result.tweakedToBigInt()).toBe(456n);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('should write and read multiple extended addresses', () => {
|
|
186
|
+
const writer = new BinaryWriter();
|
|
187
|
+
const addr1 = createFullAddress(100n, 200n);
|
|
188
|
+
const addr2 = createFullAddress(300n, 400n);
|
|
189
|
+
const addr3 = createFullAddress(500n, 600n);
|
|
190
|
+
|
|
191
|
+
writer.writeExtendedAddress(addr1);
|
|
192
|
+
writer.writeExtendedAddress(addr2);
|
|
193
|
+
writer.writeExtendedAddress(addr3);
|
|
194
|
+
|
|
195
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
196
|
+
|
|
197
|
+
const result1 = reader.readExtendedAddress();
|
|
198
|
+
expect(result1.toBigInt()).toBe(100n);
|
|
199
|
+
expect(result1.tweakedToBigInt()).toBe(200n);
|
|
200
|
+
|
|
201
|
+
const result2 = reader.readExtendedAddress();
|
|
202
|
+
expect(result2.toBigInt()).toBe(300n);
|
|
203
|
+
expect(result2.tweakedToBigInt()).toBe(400n);
|
|
204
|
+
|
|
205
|
+
const result3 = reader.readExtendedAddress();
|
|
206
|
+
expect(result3.toBigInt()).toBe(500n);
|
|
207
|
+
expect(result3.tweakedToBigInt()).toBe(600n);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('should handle zero addresses', () => {
|
|
211
|
+
const writer = new BinaryWriter();
|
|
212
|
+
const address = createFullAddress(0n, 0n);
|
|
213
|
+
|
|
214
|
+
writer.writeExtendedAddress(address);
|
|
215
|
+
|
|
216
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
217
|
+
const result = reader.readExtendedAddress();
|
|
218
|
+
|
|
219
|
+
expect(result.toBigInt()).toBe(0n);
|
|
220
|
+
expect(result.tweakedToBigInt()).toBe(0n);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('should handle max value addresses', () => {
|
|
224
|
+
const writer = new BinaryWriter();
|
|
225
|
+
const maxValue = 2n ** 256n - 1n;
|
|
226
|
+
const address = createFullAddress(maxValue, maxValue);
|
|
227
|
+
|
|
228
|
+
writer.writeExtendedAddress(address);
|
|
229
|
+
|
|
230
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
231
|
+
const result = reader.readExtendedAddress();
|
|
232
|
+
|
|
233
|
+
expect(result.toBigInt()).toBe(maxValue);
|
|
234
|
+
expect(result.tweakedToBigInt()).toBe(maxValue);
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
describe('readExtendedAddressArray / writeExtendedAddressArray', () => {
|
|
239
|
+
it('should write and read empty array', () => {
|
|
240
|
+
const writer = new BinaryWriter();
|
|
241
|
+
writer.writeExtendedAddressArray([]);
|
|
242
|
+
|
|
243
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
244
|
+
const result = reader.readExtendedAddressArray();
|
|
245
|
+
|
|
246
|
+
expect(result).toEqual([]);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('should write and read array of extended addresses', () => {
|
|
250
|
+
const writer = new BinaryWriter();
|
|
251
|
+
const addresses = [
|
|
252
|
+
createFullAddress(1n, 2n),
|
|
253
|
+
createFullAddress(3n, 4n),
|
|
254
|
+
createFullAddress(5n, 6n),
|
|
255
|
+
];
|
|
256
|
+
|
|
257
|
+
writer.writeExtendedAddressArray(addresses);
|
|
258
|
+
|
|
259
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
260
|
+
const result = reader.readExtendedAddressArray();
|
|
261
|
+
|
|
262
|
+
expect(result.length).toBe(3);
|
|
263
|
+
expect(result[0].toBigInt()).toBe(1n);
|
|
264
|
+
expect(result[0].tweakedToBigInt()).toBe(2n);
|
|
265
|
+
expect(result[1].toBigInt()).toBe(3n);
|
|
266
|
+
expect(result[1].tweakedToBigInt()).toBe(4n);
|
|
267
|
+
expect(result[2].toBigInt()).toBe(5n);
|
|
268
|
+
expect(result[2].tweakedToBigInt()).toBe(6n);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('should handle large arrays', () => {
|
|
272
|
+
const writer = new BinaryWriter();
|
|
273
|
+
const addresses: Address[] = [];
|
|
274
|
+
for (let i = 0; i < 100; i++) {
|
|
275
|
+
addresses.push(createFullAddress(BigInt(i), BigInt(i * 2)));
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
writer.writeExtendedAddressArray(addresses);
|
|
279
|
+
|
|
280
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
281
|
+
const result = reader.readExtendedAddressArray();
|
|
282
|
+
|
|
283
|
+
expect(result.length).toBe(100);
|
|
284
|
+
for (let i = 0; i < 100; i++) {
|
|
285
|
+
expect(result[i].toBigInt()).toBe(BigInt(i));
|
|
286
|
+
expect(result[i].tweakedToBigInt()).toBe(BigInt(i * 2));
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
describe('ExtendedAddressMapU256 Methods', () => {
|
|
293
|
+
describe('readExtendedAddressMapU256 / writeExtendedAddressMapU256', () => {
|
|
294
|
+
it('should write and read empty map', () => {
|
|
295
|
+
const writer = new BinaryWriter();
|
|
296
|
+
const map = new ExtendedAddressMap<bigint>();
|
|
297
|
+
|
|
298
|
+
writer.writeExtendedAddressMapU256(map);
|
|
299
|
+
|
|
300
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
301
|
+
const result = reader.readExtendedAddressMapU256();
|
|
302
|
+
|
|
303
|
+
expect(result.size).toBe(0);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it('should write and read map with entries', () => {
|
|
307
|
+
const writer = new BinaryWriter();
|
|
308
|
+
const map = new ExtendedAddressMap<bigint>();
|
|
309
|
+
|
|
310
|
+
const addr1 = createFullAddress(100n, 200n);
|
|
311
|
+
const addr2 = createFullAddress(300n, 400n);
|
|
312
|
+
|
|
313
|
+
map.set(addr1, 1000n);
|
|
314
|
+
map.set(addr2, 2000n);
|
|
315
|
+
|
|
316
|
+
writer.writeExtendedAddressMapU256(map);
|
|
317
|
+
|
|
318
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
319
|
+
const result = reader.readExtendedAddressMapU256();
|
|
320
|
+
|
|
321
|
+
expect(result.size).toBe(2);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
it('should handle large u256 values', () => {
|
|
325
|
+
const writer = new BinaryWriter();
|
|
326
|
+
const map = new ExtendedAddressMap<bigint>();
|
|
327
|
+
|
|
328
|
+
const addr = createFullAddress(1n, 2n);
|
|
329
|
+
const largeValue = 2n ** 256n - 1n;
|
|
330
|
+
|
|
331
|
+
map.set(addr, largeValue);
|
|
332
|
+
|
|
333
|
+
writer.writeExtendedAddressMapU256(map);
|
|
334
|
+
|
|
335
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
336
|
+
const result = reader.readExtendedAddressMapU256();
|
|
337
|
+
|
|
338
|
+
expect(result.size).toBe(1);
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
describe('Schnorr Signature Methods', () => {
|
|
344
|
+
describe('readSchnorrSignature / writeSchnorrSignature', () => {
|
|
345
|
+
it('should write and read Schnorr signature', () => {
|
|
346
|
+
const writer = new BinaryWriter();
|
|
347
|
+
const address = createFullAddress(12345n, 67890n);
|
|
348
|
+
const signature = new Uint8Array(64);
|
|
349
|
+
for (let i = 0; i < 64; i++) {
|
|
350
|
+
signature[i] = i;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
writer.writeSchnorrSignature(address, signature);
|
|
354
|
+
|
|
355
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
356
|
+
const result = reader.readSchnorrSignature();
|
|
357
|
+
|
|
358
|
+
expect(result.address.toBigInt()).toBe(12345n);
|
|
359
|
+
expect(result.address.tweakedToBigInt()).toBe(67890n);
|
|
360
|
+
expect(result.signature.length).toBe(64);
|
|
361
|
+
for (let i = 0; i < 64; i++) {
|
|
362
|
+
expect(result.signature[i]).toBe(i);
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it('should throw on invalid signature length', () => {
|
|
367
|
+
const writer = new BinaryWriter();
|
|
368
|
+
const address = createFullAddress(1n, 2n);
|
|
369
|
+
const invalidSignature = new Uint8Array(32); // Should be 64
|
|
370
|
+
|
|
371
|
+
expect(() => writer.writeSchnorrSignature(address, invalidSignature)).toThrow();
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it('should handle multiple signatures', () => {
|
|
375
|
+
const writer = new BinaryWriter();
|
|
376
|
+
|
|
377
|
+
const sig1 = new Uint8Array(64).fill(1);
|
|
378
|
+
const sig2 = new Uint8Array(64).fill(2);
|
|
379
|
+
|
|
380
|
+
writer.writeSchnorrSignature(createFullAddress(1n, 2n), sig1);
|
|
381
|
+
writer.writeSchnorrSignature(createFullAddress(3n, 4n), sig2);
|
|
382
|
+
|
|
383
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
384
|
+
|
|
385
|
+
const result1 = reader.readSchnorrSignature();
|
|
386
|
+
expect(result1.address.toBigInt()).toBe(1n);
|
|
387
|
+
expect(result1.signature[0]).toBe(1);
|
|
388
|
+
|
|
389
|
+
const result2 = reader.readSchnorrSignature();
|
|
390
|
+
expect(result2.address.toBigInt()).toBe(3n);
|
|
391
|
+
expect(result2.signature[0]).toBe(2);
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
describe('Mixed Operations', () => {
|
|
397
|
+
it('should handle mixed data types in sequence', () => {
|
|
398
|
+
const writer = new BinaryWriter();
|
|
399
|
+
|
|
400
|
+
// Write various types
|
|
401
|
+
writer.writeI8(-50);
|
|
402
|
+
writer.writeI16(-1000);
|
|
403
|
+
writer.writeI32(-100000);
|
|
404
|
+
writer.writeI64(-10000000000n);
|
|
405
|
+
writer.writeExtendedAddress(createFullAddress(111n, 222n));
|
|
406
|
+
writer.writeU256(999n);
|
|
407
|
+
|
|
408
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
409
|
+
|
|
410
|
+
expect(reader.readI8()).toBe(-50);
|
|
411
|
+
expect(reader.readI16()).toBe(-1000);
|
|
412
|
+
expect(reader.readI32()).toBe(-100000);
|
|
413
|
+
expect(reader.readI64()).toBe(-10000000000n);
|
|
414
|
+
|
|
415
|
+
const addr = reader.readExtendedAddress();
|
|
416
|
+
expect(addr.toBigInt()).toBe(111n);
|
|
417
|
+
expect(addr.tweakedToBigInt()).toBe(222n);
|
|
418
|
+
|
|
419
|
+
expect(reader.readU256()).toBe(999n);
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
it('should correctly track buffer position', () => {
|
|
423
|
+
const writer = new BinaryWriter();
|
|
424
|
+
|
|
425
|
+
writer.writeI8(1);
|
|
426
|
+
writer.writeI16(2);
|
|
427
|
+
writer.writeI32(3);
|
|
428
|
+
writer.writeI64(4n);
|
|
429
|
+
writer.writeExtendedAddress(createFullAddress(5n, 6n));
|
|
430
|
+
|
|
431
|
+
const buffer = writer.getBuffer();
|
|
432
|
+
// i8: 1 byte, i16: 2 bytes, i32: 4 bytes, i64: 8 bytes, extended address: 64 bytes
|
|
433
|
+
expect(buffer.length).toBe(1 + 2 + 4 + 8 + 64);
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
describe('Error Handling', () => {
|
|
438
|
+
it('should throw when reading beyond buffer', () => {
|
|
439
|
+
const writer = new BinaryWriter();
|
|
440
|
+
writer.writeI8(1);
|
|
441
|
+
|
|
442
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
443
|
+
reader.readI8();
|
|
444
|
+
|
|
445
|
+
expect(() => reader.readI8()).toThrow();
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
it('should throw when reading extended address from insufficient buffer', () => {
|
|
449
|
+
const writer = new BinaryWriter();
|
|
450
|
+
writer.writeU256(1n); // Only 32 bytes
|
|
451
|
+
|
|
452
|
+
const reader = new BinaryReader(writer.getBuffer());
|
|
453
|
+
|
|
454
|
+
expect(() => reader.readExtendedAddress()).toThrow();
|
|
455
|
+
});
|
|
456
|
+
});
|
|
457
|
+
});
|
package/test/derivePath.test.ts
CHANGED
|
@@ -419,7 +419,7 @@ describe('Mnemonic.deriveOPWallet', () => {
|
|
|
419
419
|
});
|
|
420
420
|
});
|
|
421
421
|
|
|
422
|
-
describe('
|
|
422
|
+
describe('deriveMultipleUnisat', () => {
|
|
423
423
|
it('should derive multiple wallets', () => {
|
|
424
424
|
const mnemonic = new Mnemonic(
|
|
425
425
|
testMnemonic,
|
|
@@ -428,7 +428,7 @@ describe('Mnemonic.deriveOPWallet', () => {
|
|
|
428
428
|
MLDSASecurityLevel.LEVEL2,
|
|
429
429
|
);
|
|
430
430
|
|
|
431
|
-
const wallets = mnemonic.
|
|
431
|
+
const wallets = mnemonic.deriveMultipleUnisat(AddressTypes.P2TR, 5);
|
|
432
432
|
|
|
433
433
|
expect(wallets.length).toBe(5);
|
|
434
434
|
expect(wallets[0].p2tr).toBeDefined();
|
|
@@ -443,7 +443,7 @@ describe('Mnemonic.deriveOPWallet', () => {
|
|
|
443
443
|
MLDSASecurityLevel.LEVEL2,
|
|
444
444
|
);
|
|
445
445
|
|
|
446
|
-
const wallets = mnemonic.
|
|
446
|
+
const wallets = mnemonic.deriveMultipleUnisat(AddressTypes.P2TR, 3);
|
|
447
447
|
|
|
448
448
|
const addresses = wallets.map((w) => w.p2tr);
|
|
449
449
|
const uniqueAddresses = new Set(addresses);
|
|
@@ -459,7 +459,7 @@ describe('Mnemonic.deriveOPWallet', () => {
|
|
|
459
459
|
MLDSASecurityLevel.LEVEL2,
|
|
460
460
|
);
|
|
461
461
|
|
|
462
|
-
const wallets = mnemonic.
|
|
462
|
+
const wallets = mnemonic.deriveMultipleUnisat(AddressTypes.P2TR, 2, 5);
|
|
463
463
|
const wallet5 = mnemonic.deriveOPWallet(AddressTypes.P2TR, 5);
|
|
464
464
|
|
|
465
465
|
expect(wallets[0].p2tr).toBe(wallet5.p2tr);
|