@layerzerolabs/chain-utils 0.0.45 → 0.0.47
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/.turbo/turbo-build.log +36 -27
- package/.turbo/turbo-test.log +11 -3
- package/dist/7BDQVICT.cjs +1332 -0
- package/dist/7BDQVICT.cjs.map +1 -0
- package/dist/{UXYWZBHJ.js → FJIAQ3QL.js} +4 -3
- package/dist/FJIAQ3QL.js.map +1 -0
- package/dist/IUWKW475.js +187 -0
- package/dist/IUWKW475.js.map +1 -0
- package/dist/IVFVZYWG.cjs +197 -0
- package/dist/IVFVZYWG.cjs.map +1 -0
- package/dist/J6P5K7DC.cjs +51 -0
- package/dist/J6P5K7DC.cjs.map +1 -0
- package/dist/{223VIKVV.cjs → NOJYY7DN.cjs} +5 -4
- package/dist/NOJYY7DN.cjs.map +1 -0
- package/dist/PBOTNOCJ.js +1326 -0
- package/dist/PBOTNOCJ.js.map +1 -0
- package/dist/YXE7PREU.js +45 -0
- package/dist/YXE7PREU.js.map +1 -0
- package/dist/addressParser.cjs +29 -0
- package/dist/{addresses.js.map → addressParser.cjs.map} +1 -1
- package/dist/addressParser.d.ts +40 -0
- package/dist/addressParser.d.ts.map +1 -0
- package/dist/addressParser.js +4 -0
- package/dist/{addresses.cjs.map → addressParser.js.map} +1 -1
- package/dist/addressParser.test.cjs +18491 -0
- package/dist/addressParser.test.cjs.map +1 -0
- package/dist/addressParser.test.js +18469 -0
- package/dist/addressParser.test.js.map +1 -0
- package/dist/index.cjs +20 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/utils.cjs +3 -3
- package/dist/utils.js +2 -2
- package/package.json +9 -7
- package/src/addressParser.test.ts +269 -0
- package/src/addressParser.ts +258 -0
- package/src/index.ts +1 -1
- package/dist/223VIKVV.cjs.map +0 -1
- package/dist/UXYWZBHJ.js.map +0 -1
- package/dist/VPRYQZSC.cjs +0 -50
- package/dist/VPRYQZSC.cjs.map +0 -1
- package/dist/VUOMXK5T.js +0 -6
- package/dist/VUOMXK5T.js.map +0 -1
- package/dist/WF3JPRDE.js +0 -42
- package/dist/WF3JPRDE.js.map +0 -1
- package/dist/YJF4D23A.cjs +0 -8
- package/dist/YJF4D23A.cjs.map +0 -1
- package/dist/addresses.cjs +0 -21
- package/dist/addresses.d.ts +0 -10
- package/dist/addresses.d.ts.map +0 -1
- package/dist/addresses.js +0 -4
- package/src/addresses.ts +0 -47
package/dist/index.cjs
CHANGED
|
@@ -1,26 +1,35 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
require('./
|
|
3
|
+
var IVFVZYWG_cjs = require('./IVFVZYWG.cjs');
|
|
4
|
+
var NOJYY7DN_cjs = require('./NOJYY7DN.cjs');
|
|
5
|
+
var J6P5K7DC_cjs = require('./J6P5K7DC.cjs');
|
|
6
6
|
|
|
7
|
+
// src/index.ts
|
|
8
|
+
J6P5K7DC_cjs.init_cjs_shims();
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
Object.defineProperty(exports, "AddressEncoding", {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function () { return IVFVZYWG_cjs.AddressEncoding; }
|
|
13
|
+
});
|
|
14
|
+
Object.defineProperty(exports, "addressParser", {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: function () { return IVFVZYWG_cjs.addressParser; }
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(exports, "base58AddressParser", {
|
|
10
19
|
enumerable: true,
|
|
11
|
-
get: function () { return
|
|
20
|
+
get: function () { return IVFVZYWG_cjs.base58AddressParser; }
|
|
12
21
|
});
|
|
13
|
-
Object.defineProperty(exports, "
|
|
22
|
+
Object.defineProperty(exports, "hexAddressParser", {
|
|
14
23
|
enumerable: true,
|
|
15
|
-
get: function () { return
|
|
24
|
+
get: function () { return IVFVZYWG_cjs.hexAddressParser; }
|
|
16
25
|
});
|
|
17
|
-
Object.defineProperty(exports, "
|
|
26
|
+
Object.defineProperty(exports, "tonAddressParser", {
|
|
18
27
|
enumerable: true,
|
|
19
|
-
get: function () { return
|
|
28
|
+
get: function () { return IVFVZYWG_cjs.tonAddressParser; }
|
|
20
29
|
});
|
|
21
30
|
Object.defineProperty(exports, "getNetworkName", {
|
|
22
31
|
enumerable: true,
|
|
23
|
-
get: function () { return
|
|
32
|
+
get: function () { return NOJYY7DN_cjs.getNetworkName; }
|
|
24
33
|
});
|
|
25
34
|
//# sourceMappingURL=index.cjs.map
|
|
26
35
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.cjs"}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["init_cjs_shims"],"mappings":";;;;;;;AAAAA,2BAAA,EAAA","file":"index.cjs","sourcesContent":["export * from './addressParser';\nexport * from './utils';\n"]}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { getNetworkName } from './
|
|
3
|
-
import './
|
|
1
|
+
export { AddressEncoding, addressParser, base58AddressParser, hexAddressParser, tonAddressParser } from './IUWKW475.js';
|
|
2
|
+
export { getNetworkName } from './FJIAQ3QL.js';
|
|
3
|
+
import { init_esm_shims } from './YXE7PREU.js';
|
|
4
|
+
|
|
5
|
+
// src/index.ts
|
|
6
|
+
init_esm_shims();
|
|
4
7
|
//# sourceMappingURL=index.js.map
|
|
5
8
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAAA,cAAA,EAAA","file":"index.js","sourcesContent":["export * from './addressParser';\nexport * from './utils';\n"]}
|
package/dist/utils.cjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('./
|
|
3
|
+
var NOJYY7DN_cjs = require('./NOJYY7DN.cjs');
|
|
4
|
+
require('./J6P5K7DC.cjs');
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
Object.defineProperty(exports, "getNetworkName", {
|
|
9
9
|
enumerable: true,
|
|
10
|
-
get: function () { return
|
|
10
|
+
get: function () { return NOJYY7DN_cjs.getNetworkName; }
|
|
11
11
|
});
|
|
12
12
|
//# sourceMappingURL=utils.cjs.map
|
|
13
13
|
//# sourceMappingURL=utils.cjs.map
|
package/dist/utils.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@layerzerolabs/chain-utils",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.47",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -14,17 +14,19 @@
|
|
|
14
14
|
"module": "./dist/index.js",
|
|
15
15
|
"types": "./dist/index.d.ts",
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@noble/hashes": "^1.1.5",
|
|
18
17
|
"bs58": "^5.0.0",
|
|
19
|
-
"
|
|
20
|
-
"@layerzerolabs/common-
|
|
21
|
-
"@layerzerolabs/
|
|
18
|
+
"@layerzerolabs/common-chain-model": "0.0.47",
|
|
19
|
+
"@layerzerolabs/common-ton": "0.0.47",
|
|
20
|
+
"@layerzerolabs/layerzero-definitions": "0.0.47",
|
|
21
|
+
"@layerzerolabs/common-utils": "0.0.47",
|
|
22
|
+
"@layerzerolabs/static-chain-info": "0.0.47"
|
|
22
23
|
},
|
|
23
24
|
"devDependencies": {
|
|
24
25
|
"tsup": "^8.4.0",
|
|
25
26
|
"vitest": "^3.2.3",
|
|
26
|
-
"@layerzerolabs/tsup-configuration": "0.0.
|
|
27
|
-
"@layerzerolabs/typescript-configuration": "0.0.
|
|
27
|
+
"@layerzerolabs/tsup-configuration": "0.0.47",
|
|
28
|
+
"@layerzerolabs/typescript-configuration": "0.0.47",
|
|
29
|
+
"@layerzerolabs/typescript-utils": "0.0.47"
|
|
28
30
|
},
|
|
29
31
|
"publishConfig": {
|
|
30
32
|
"access": "restricted",
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import * as bs58 from 'bs58';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import type { NormalizedHexString } from '@layerzerolabs/common-chain-model';
|
|
5
|
+
import { normalizeHex } from '@layerzerolabs/common-chain-model';
|
|
6
|
+
import { bytesToHexPrefixed, hexToBytes, hexZeroPad } from '@layerzerolabs/common-utils';
|
|
7
|
+
import { ChainName } from '@layerzerolabs/layerzero-definitions';
|
|
8
|
+
|
|
9
|
+
import { addressParser } from './addressParser';
|
|
10
|
+
|
|
11
|
+
// Test data generators
|
|
12
|
+
const randomBytes = (length: number): Uint8Array => {
|
|
13
|
+
const bytes = new Uint8Array(length);
|
|
14
|
+
for (let i = 0; i < length; i++) {
|
|
15
|
+
bytes[i] = Math.floor(Math.random() * 256);
|
|
16
|
+
}
|
|
17
|
+
return bytes;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const randomHex = (byteLength: number): NormalizedHexString => {
|
|
21
|
+
return normalizeHex(bytesToHexPrefixed(randomBytes(byteLength)));
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const runPropertyTest = <T>(fn: () => T, iterations = 100): void => {
|
|
25
|
+
for (let i = 0; i < iterations; i++) {
|
|
26
|
+
fn();
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
describe('addressParser - hex/EVM chains', () => {
|
|
31
|
+
const evmChains = [ChainName.ETHEREUM, ChainName.AVALANCHE, ChainName.BSC, ChainName.POLYGON];
|
|
32
|
+
|
|
33
|
+
evmChains.forEach((chain) => {
|
|
34
|
+
describe(chain, () => {
|
|
35
|
+
const parser = addressParser(chain);
|
|
36
|
+
|
|
37
|
+
it('maintains roundtrip invariant: hex -> native -> hex', () => {
|
|
38
|
+
runPropertyTest(() => {
|
|
39
|
+
const input = randomHex(20);
|
|
40
|
+
const native = parser.normalizedToNative(input);
|
|
41
|
+
const back = parser.nativeToNormalized(native);
|
|
42
|
+
expect(back).toBe(input);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('maintains byte representation consistency', () => {
|
|
47
|
+
runPropertyTest(() => {
|
|
48
|
+
const input = randomHex(20);
|
|
49
|
+
const nativeStr = parser.normalizedToNativeString(input);
|
|
50
|
+
const bytesFromHex = hexToBytes(nativeStr);
|
|
51
|
+
const nativeBytes = parser.nativeToBytes(nativeStr);
|
|
52
|
+
|
|
53
|
+
expect(nativeBytes).toEqual(bytesFromHex);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('correctly pads addresses', () => {
|
|
58
|
+
runPropertyTest(() => {
|
|
59
|
+
const byteLength = Math.floor(Math.random() * 20) + 1; // 1-20 bytes
|
|
60
|
+
const input = randomHex(byteLength);
|
|
61
|
+
const native = parser.normalizedToNative(input);
|
|
62
|
+
expect(native.nativeAddress.length).toBe(42); // Always 20 bytes padded
|
|
63
|
+
expect(native.chainName).toBe(chain);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('normalizedToBytes32Hex pads correctly', () => {
|
|
70
|
+
runPropertyTest(() => {
|
|
71
|
+
const byteLength = Math.floor(Math.random() * 32) + 1; // 1-32 bytes
|
|
72
|
+
const input = randomHex(byteLength);
|
|
73
|
+
const padded = addressParser.normalizedToBytes32Hex(input);
|
|
74
|
+
expect(padded.length).toBe(66); // 32 bytes -> 64 hex chars + 0x
|
|
75
|
+
expect(padded).toBe(hexZeroPad(input as any, 32));
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('handles edge cases', () => {
|
|
80
|
+
const parser = addressParser(ChainName.ETHEREUM);
|
|
81
|
+
|
|
82
|
+
// Empty address
|
|
83
|
+
const empty = normalizeHex('0x');
|
|
84
|
+
expect(parser.normalizedToNative(empty).nativeAddress.length).toBe(42);
|
|
85
|
+
|
|
86
|
+
// Maximum value
|
|
87
|
+
const max = normalizeHex(('0x' + 'ff'.repeat(20)) as any);
|
|
88
|
+
expect(parser.nativeToNormalized(parser.normalizedToNative(max))).toBe(max);
|
|
89
|
+
|
|
90
|
+
// Single byte
|
|
91
|
+
const single = normalizeHex('0x01');
|
|
92
|
+
expect(parser.normalizedToNative(single).nativeAddress).toBe(hexZeroPad('0x01', 20));
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('addressParser - base58 chains (Solana)', () => {
|
|
97
|
+
const parser = addressParser(ChainName.SOLANA);
|
|
98
|
+
|
|
99
|
+
it('maintains roundtrip invariant: hex -> base58 -> hex', () => {
|
|
100
|
+
runPropertyTest(() => {
|
|
101
|
+
const byteLength = Math.floor(Math.random() * 32) + 1; // 1-32 bytes
|
|
102
|
+
const input = randomHex(byteLength);
|
|
103
|
+
const native = parser.normalizedToNative(input);
|
|
104
|
+
const back = parser.nativeToNormalized(native);
|
|
105
|
+
expect(back).toBe(input);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('maintains base58 encoding consistency', () => {
|
|
110
|
+
runPropertyTest(() => {
|
|
111
|
+
const input = randomHex(32);
|
|
112
|
+
const nativeStr = parser.normalizedToNativeString(input);
|
|
113
|
+
const expectedBase58 = bs58.encode(hexToBytes(input as any));
|
|
114
|
+
expect(nativeStr).toBe(expectedBase58);
|
|
115
|
+
|
|
116
|
+
// Verify bytes consistency
|
|
117
|
+
const nativeBytes = parser.nativeToBytes(nativeStr);
|
|
118
|
+
expect(nativeBytes).toEqual(bs58.decode(expectedBase58));
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('correctly handles 32-byte padding', () => {
|
|
123
|
+
runPropertyTest(() => {
|
|
124
|
+
const byteLength = Math.floor(Math.random() * 32) + 1;
|
|
125
|
+
const input = randomHex(byteLength);
|
|
126
|
+
const native = parser.normalizedToNativeString(input);
|
|
127
|
+
const padded = parser.nativeToBytes32Hex(native);
|
|
128
|
+
expect(padded.length).toBe(66);
|
|
129
|
+
|
|
130
|
+
// Verify padding preserves original value
|
|
131
|
+
expect(parser.nativeToNormalized(native)).toBe(
|
|
132
|
+
normalizeHex(bytesToHexPrefixed(hexToBytes(input as any))),
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('handles edge cases', () => {
|
|
138
|
+
// Single byte
|
|
139
|
+
const single = normalizeHex('0x01');
|
|
140
|
+
const singleNative = parser.normalizedToNative(single);
|
|
141
|
+
expect(parser.nativeToNormalized(singleNative)).toBe(single);
|
|
142
|
+
|
|
143
|
+
// Empty (though typically invalid for Solana)
|
|
144
|
+
const empty = normalizeHex('0x');
|
|
145
|
+
expect(() => parser.normalizedToNative(empty)).not.toThrow();
|
|
146
|
+
|
|
147
|
+
// 32 bytes (typical Solana address length)
|
|
148
|
+
const full32 = randomHex(32);
|
|
149
|
+
const native32 = parser.normalizedToNative(full32);
|
|
150
|
+
expect(parser.nativeToNormalized(native32)).toBe(full32);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
describe('addressParser - chain validation', () => {
|
|
155
|
+
it('validates chain names for nativeToBytes32Hex', () => {
|
|
156
|
+
const evmParser = addressParser(ChainName.ETHEREUM);
|
|
157
|
+
const solanaParser = addressParser(ChainName.SOLANA);
|
|
158
|
+
|
|
159
|
+
const evmAddress = evmParser.normalizedToNative(randomHex(20));
|
|
160
|
+
const solanaAddress = solanaParser.normalizedToNative(randomHex(32));
|
|
161
|
+
|
|
162
|
+
// nativeTo32BytesHex validates chain names for NativeAddress objects
|
|
163
|
+
expect(() => solanaParser.nativeToBytes32Hex(evmAddress as any)).toThrow(/Cannot convert/);
|
|
164
|
+
expect(() => evmParser.nativeToBytes32Hex(solanaAddress as any)).toThrow(/Cannot convert/);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('accepts string addresses without validation', () => {
|
|
168
|
+
const parser = addressParser(ChainName.ETHEREUM);
|
|
169
|
+
const randomAddress = '0x' + 'ab'.repeat(20);
|
|
170
|
+
|
|
171
|
+
// String addresses bypass chain validation for all methods
|
|
172
|
+
const result = parser.nativeToNormalized(randomAddress as any);
|
|
173
|
+
expect(result).toBe(normalizeHex(randomAddress as any));
|
|
174
|
+
|
|
175
|
+
const padded = parser.nativeToBytes32Hex(randomAddress as any);
|
|
176
|
+
expect(padded.length).toBe(66);
|
|
177
|
+
|
|
178
|
+
const bytes = parser.nativeToBytes(randomAddress as any);
|
|
179
|
+
expect(bytes).toEqual(hexToBytes(randomAddress));
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
describe('addressParser - TON', () => {
|
|
184
|
+
const parser = addressParser(ChainName.TON);
|
|
185
|
+
|
|
186
|
+
it('maintains roundtrip invariant: hex -> ton address -> hex', () => {
|
|
187
|
+
runPropertyTest(() => {
|
|
188
|
+
// TON addresses are typically 32 bytes (256 bits)
|
|
189
|
+
const byteLength = Math.floor(Math.random() * 32) + 1;
|
|
190
|
+
const input = randomHex(byteLength);
|
|
191
|
+
const native = parser.normalizedToNative(input);
|
|
192
|
+
const back = parser.nativeToNormalized(native);
|
|
193
|
+
|
|
194
|
+
expect(input).toBe(back);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('correctly handles TON address format', () => {
|
|
199
|
+
runPropertyTest(() => {
|
|
200
|
+
const input = randomHex(32);
|
|
201
|
+
const native = parser.normalizedToNative(input);
|
|
202
|
+
|
|
203
|
+
// TON addresses should have the correct chain name
|
|
204
|
+
expect(native.chainName).toBe(ChainName.TON);
|
|
205
|
+
|
|
206
|
+
// Should be a valid TON address string
|
|
207
|
+
expect(typeof native.nativeAddress).toBe('string');
|
|
208
|
+
expect(native.nativeAddress.length).toBeGreaterThan(0);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('maintains byte representation consistency', () => {
|
|
213
|
+
runPropertyTest(() => {
|
|
214
|
+
const input = randomHex(32);
|
|
215
|
+
const nativeStr = parser.normalizedToNativeString(input);
|
|
216
|
+
const nativeBytes = parser.nativeToBytes(nativeStr);
|
|
217
|
+
|
|
218
|
+
// Both should produce valid byte arrays
|
|
219
|
+
expect(nativeBytes).toBeInstanceOf(Uint8Array);
|
|
220
|
+
|
|
221
|
+
// Converting back should preserve the value
|
|
222
|
+
const backFromBytes = parser.nativeToNormalized(parser.normalizedToNative(input));
|
|
223
|
+
expect(backFromBytes).toBe(input);
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('correctly handles 32-byte padding', () => {
|
|
228
|
+
runPropertyTest(() => {
|
|
229
|
+
const byteLength = Math.floor(Math.random() * 32) + 1;
|
|
230
|
+
const input = randomHex(byteLength);
|
|
231
|
+
const native = parser.normalizedToNativeString(input);
|
|
232
|
+
const padded = parser.nativeToBytes32Hex(native);
|
|
233
|
+
|
|
234
|
+
expect(padded.length).toBe(66); // 32 bytes -> 64 hex chars + 0x
|
|
235
|
+
|
|
236
|
+
// Verify the numeric value is preserved
|
|
237
|
+
const paddedBigInt = BigInt(padded);
|
|
238
|
+
const inputBigInt = BigInt(input as any);
|
|
239
|
+
expect(paddedBigInt).toBe(inputBigInt);
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it('handles edge cases', () => {
|
|
244
|
+
// Zero address
|
|
245
|
+
const zero = normalizeHex('0x0');
|
|
246
|
+
const zeroNative = parser.normalizedToNative(zero);
|
|
247
|
+
expect(() => parser.nativeToNormalized(zeroNative)).not.toThrow();
|
|
248
|
+
|
|
249
|
+
// Large values
|
|
250
|
+
const large = normalizeHex(('0x' + 'ff'.repeat(32)) as any);
|
|
251
|
+
const largeNative = parser.normalizedToNative(large);
|
|
252
|
+
const largeBack = parser.nativeToNormalized(largeNative);
|
|
253
|
+
expect(BigInt(largeBack as any)).toBe(BigInt(large as any));
|
|
254
|
+
|
|
255
|
+
// Single byte
|
|
256
|
+
const single = normalizeHex('0x01');
|
|
257
|
+
const singleNative = parser.normalizedToNative(single);
|
|
258
|
+
const singleBack = parser.nativeToNormalized(singleNative);
|
|
259
|
+
expect(BigInt(singleBack as any)).toBe(1n);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
it('validates native addresses', () => {
|
|
263
|
+
const validAddress = parser.normalizedToNative(randomHex(32));
|
|
264
|
+
expect(parser.validateNative(validAddress.nativeAddress)).toBe(true);
|
|
265
|
+
|
|
266
|
+
// Invalid addresses should return false
|
|
267
|
+
expect(parser.validateNative('invalid-ton-address')).toBe(false);
|
|
268
|
+
});
|
|
269
|
+
});
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import bs58 from 'bs58';
|
|
2
|
+
|
|
3
|
+
import type { HexString, NormalizedHexString } from '@layerzerolabs/common-chain-model';
|
|
4
|
+
import { normalizeHex } from '@layerzerolabs/common-chain-model';
|
|
5
|
+
import { addressToHex, bigintToAddress, parseTonAddress } from '@layerzerolabs/common-ton';
|
|
6
|
+
import {
|
|
7
|
+
bytesToHexPrefixed,
|
|
8
|
+
hexToBytes,
|
|
9
|
+
hexZeroPad,
|
|
10
|
+
isBase58,
|
|
11
|
+
isHexString,
|
|
12
|
+
} from '@layerzerolabs/common-utils';
|
|
13
|
+
import type {
|
|
14
|
+
Base58String,
|
|
15
|
+
ChainsByEncoding,
|
|
16
|
+
NativeAddress,
|
|
17
|
+
ResolvedEncodingForChainName,
|
|
18
|
+
TonString,
|
|
19
|
+
} from '@layerzerolabs/layerzero-definitions';
|
|
20
|
+
import type { ChainNativeAddress } from '@layerzerolabs/layerzero-definitions';
|
|
21
|
+
import { ChainName } from '@layerzerolabs/layerzero-definitions';
|
|
22
|
+
import { StaticChainConfigs } from '@layerzerolabs/static-chain-info';
|
|
23
|
+
|
|
24
|
+
type NativeOrString<T extends ChainName | `${ChainName}`> =
|
|
25
|
+
| ChainNativeAddress<T>
|
|
26
|
+
| ResolvedEncodingForChainName<T>;
|
|
27
|
+
|
|
28
|
+
export enum AddressEncoding {
|
|
29
|
+
HEX = 'hex',
|
|
30
|
+
BASE58 = 'base58',
|
|
31
|
+
TON = 'ton',
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface AddressParser<T extends ChainName | `${ChainName}`> {
|
|
35
|
+
normalizedToNative: (address: NormalizedHexString) => ChainNativeAddress<T>;
|
|
36
|
+
normalizedToNativeString: (address: NormalizedHexString) => ResolvedEncodingForChainName<T>;
|
|
37
|
+
nativeToNormalized: (nativeAddress: NativeOrString<T>) => NormalizedHexString;
|
|
38
|
+
nativeToBytes: (nativeAddress: NativeOrString<T>) => Uint8Array;
|
|
39
|
+
nativeToBytes32Hex: (nativeAddress: NativeOrString<T>) => HexString;
|
|
40
|
+
nativeToBytes32: (nativeAddress: NativeOrString<T>) => Uint8Array;
|
|
41
|
+
validateNative: (nativeAddress: string) => nativeAddress is ResolvedEncodingForChainName<T>;
|
|
42
|
+
/**
|
|
43
|
+
* Parse a native address to a string if it is valid.
|
|
44
|
+
* Throws an error if the native address is invalid.
|
|
45
|
+
* @param nativeAddress - The native address to parse.
|
|
46
|
+
* @returns The parsed native address.
|
|
47
|
+
*/
|
|
48
|
+
parseNative: (nativeAddress: string) => NormalizedHexString;
|
|
49
|
+
parseNativeToHex: (nativeAddress: string) => HexString;
|
|
50
|
+
encoding: AddressEncoding;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function addressParser<T extends ChainName | `${ChainName}`>(
|
|
54
|
+
chainName: T,
|
|
55
|
+
): AddressParser<T> {
|
|
56
|
+
// FIXME: figure out a way to not have to cast here
|
|
57
|
+
if (chainName === ChainName.TON)
|
|
58
|
+
return tonAddressParser(chainName) as unknown as AddressParser<T>;
|
|
59
|
+
if (chainName === ChainName.SOLANA)
|
|
60
|
+
return base58AddressParser(chainName) as unknown as AddressParser<T>;
|
|
61
|
+
return hexAddressParser(chainName) as unknown as AddressParser<T>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export namespace addressParser {
|
|
65
|
+
export const normalizedToBytes32Hex = (address: NormalizedHexString) => {
|
|
66
|
+
return hexZeroPad(address as unknown as HexString, 32);
|
|
67
|
+
};
|
|
68
|
+
export const normalizedToBytes32 = (address: NormalizedHexString) => {
|
|
69
|
+
return hexToBytes(normalizedToBytes32Hex(address));
|
|
70
|
+
};
|
|
71
|
+
export const normalizedToBigInt = (address: NormalizedHexString) => {
|
|
72
|
+
return BigInt(address as unknown as HexString);
|
|
73
|
+
};
|
|
74
|
+
export const parseNative = (nativeAddress: NativeAddress) => {
|
|
75
|
+
return addressParser(nativeAddress.chainName).parseNative(nativeAddress.nativeAddress);
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const validateNative = <T extends ChainName | `${ChainName}`>(
|
|
80
|
+
nativeAddress: string,
|
|
81
|
+
expectedChainName: T,
|
|
82
|
+
): nativeAddress is ResolvedEncodingForChainName<T> => {
|
|
83
|
+
if (!addressParser(expectedChainName).validateNative(nativeAddress)) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
'Cannot convert: ' +
|
|
86
|
+
nativeAddress +
|
|
87
|
+
' - The native address does not match the expected format for the chain: ' +
|
|
88
|
+
expectedChainName,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
return true;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const getAddress = <T extends ChainName | `${ChainName}`>(nativeAddress: NativeOrString<T>) => {
|
|
95
|
+
return typeof nativeAddress === 'object' ? nativeAddress.nativeAddress : nativeAddress;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export const tonAddressParser: (
|
|
99
|
+
chainName: ChainsByEncoding[TonString],
|
|
100
|
+
) => AddressParser<ChainsByEncoding[TonString]> = (chainName) => {
|
|
101
|
+
return {
|
|
102
|
+
validateNative: (nativeAddress): nativeAddress is TonString => {
|
|
103
|
+
try {
|
|
104
|
+
parseTonAddress(nativeAddress);
|
|
105
|
+
return true;
|
|
106
|
+
} catch {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
normalizedToNative: (address) => {
|
|
111
|
+
const numericalValue = addressParser.normalizedToBigInt(address);
|
|
112
|
+
return {
|
|
113
|
+
nativeAddress: bigintToAddress(numericalValue).toString() as TonString,
|
|
114
|
+
chainName,
|
|
115
|
+
};
|
|
116
|
+
},
|
|
117
|
+
normalizedToNativeString: (address) => {
|
|
118
|
+
return addressParser(chainName).normalizedToNative(address).nativeAddress;
|
|
119
|
+
},
|
|
120
|
+
nativeToNormalized: (nativeAddress) => {
|
|
121
|
+
const address = getAddress(nativeAddress);
|
|
122
|
+
validateNative(address, chainName);
|
|
123
|
+
return normalizeHex(addressToHex(address));
|
|
124
|
+
},
|
|
125
|
+
nativeToBytes32Hex: (nativeAddress) => {
|
|
126
|
+
// naturally ton is 32 bytes, pad it anyway
|
|
127
|
+
return hexZeroPad(
|
|
128
|
+
addressParser(chainName).nativeToNormalized(nativeAddress) as unknown as HexString,
|
|
129
|
+
32,
|
|
130
|
+
);
|
|
131
|
+
},
|
|
132
|
+
nativeToBytes: (nativeAddress) => {
|
|
133
|
+
return hexToBytes(addressParser(chainName).nativeToBytes32Hex(nativeAddress));
|
|
134
|
+
},
|
|
135
|
+
nativeToBytes32: (nativeAddress) => {
|
|
136
|
+
return hexToBytes(addressParser(chainName).nativeToBytes32Hex(nativeAddress));
|
|
137
|
+
},
|
|
138
|
+
parseNative: (nativeAddress) => {
|
|
139
|
+
if (!validateNative(nativeAddress, chainName)) {
|
|
140
|
+
throw new Error('Invalid native address: ' + nativeAddress);
|
|
141
|
+
}
|
|
142
|
+
return addressParser(chainName).nativeToNormalized(nativeAddress);
|
|
143
|
+
},
|
|
144
|
+
parseNativeToHex: (nativeAddress) => {
|
|
145
|
+
return addressParser(chainName).parseNative(nativeAddress) as unknown as HexString;
|
|
146
|
+
},
|
|
147
|
+
encoding: AddressEncoding.TON,
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export const base58AddressParser = (
|
|
152
|
+
chainName: ChainsByEncoding[Base58String],
|
|
153
|
+
): AddressParser<ChainsByEncoding[Base58String]> => {
|
|
154
|
+
return {
|
|
155
|
+
validateNative: (nativeAddress): nativeAddress is Base58String => {
|
|
156
|
+
return isBase58(nativeAddress);
|
|
157
|
+
},
|
|
158
|
+
normalizedToNative: (address) => {
|
|
159
|
+
return {
|
|
160
|
+
nativeAddress: bs58.encode(
|
|
161
|
+
hexToBytes(address as unknown as HexString),
|
|
162
|
+
) as Base58String,
|
|
163
|
+
chainName,
|
|
164
|
+
};
|
|
165
|
+
},
|
|
166
|
+
normalizedToNativeString: (address) => {
|
|
167
|
+
return addressParser(chainName).normalizedToNative(address).nativeAddress;
|
|
168
|
+
},
|
|
169
|
+
nativeToNormalized: (nativeAddress) => {
|
|
170
|
+
const address = getAddress(nativeAddress);
|
|
171
|
+
validateNative(address, chainName);
|
|
172
|
+
const hex = bytesToHexPrefixed(bs58.decode(address));
|
|
173
|
+
return normalizeHex(hex);
|
|
174
|
+
},
|
|
175
|
+
nativeToBytes32Hex: (nativeAddress) => {
|
|
176
|
+
// naturally solana is 32 bytes, pad it anyway
|
|
177
|
+
return hexZeroPad(
|
|
178
|
+
addressParser(chainName).nativeToNormalized(nativeAddress) as unknown as HexString,
|
|
179
|
+
32,
|
|
180
|
+
);
|
|
181
|
+
},
|
|
182
|
+
nativeToBytes: (nativeAddress) => {
|
|
183
|
+
const address = getAddress(nativeAddress);
|
|
184
|
+
validateNative(address, chainName);
|
|
185
|
+
return bs58.decode(address);
|
|
186
|
+
},
|
|
187
|
+
nativeToBytes32: (nativeAddress) => {
|
|
188
|
+
return hexToBytes(addressParser(chainName).nativeToBytes32Hex(nativeAddress));
|
|
189
|
+
},
|
|
190
|
+
parseNative: (nativeAddress) => {
|
|
191
|
+
if (!validateNative(nativeAddress, chainName)) {
|
|
192
|
+
throw new Error('Invalid native address: ' + nativeAddress);
|
|
193
|
+
}
|
|
194
|
+
return addressParser(chainName).nativeToNormalized(nativeAddress);
|
|
195
|
+
},
|
|
196
|
+
parseNativeToHex: (nativeAddress) => {
|
|
197
|
+
return addressParser(chainName).parseNative(nativeAddress) as unknown as HexString;
|
|
198
|
+
},
|
|
199
|
+
encoding: AddressEncoding.BASE58,
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
export const hexAddressParser = (
|
|
204
|
+
chainName: ChainsByEncoding[HexString],
|
|
205
|
+
): AddressParser<ChainsByEncoding[HexString]> => {
|
|
206
|
+
const nativeByteLength = StaticChainConfigs.getAddressSizeInBytes(chainName as ChainName);
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
validateNative: (nativeAddress): nativeAddress is HexString => {
|
|
210
|
+
return isHexString(nativeAddress);
|
|
211
|
+
},
|
|
212
|
+
normalizedToNative: (address) => {
|
|
213
|
+
return {
|
|
214
|
+
// we could have EIP-55 here, but omitted for now
|
|
215
|
+
nativeAddress: hexZeroPad(address as unknown as HexString, nativeByteLength),
|
|
216
|
+
chainName,
|
|
217
|
+
};
|
|
218
|
+
},
|
|
219
|
+
normalizedToNativeString: (address) => {
|
|
220
|
+
return hexZeroPad(address as unknown as HexString, nativeByteLength);
|
|
221
|
+
},
|
|
222
|
+
nativeToNormalized: (nativeAddress) => {
|
|
223
|
+
const address = getAddress(nativeAddress);
|
|
224
|
+
validateNative(address, chainName);
|
|
225
|
+
return normalizeHex(address);
|
|
226
|
+
},
|
|
227
|
+
nativeToBytes: (nativeAddress) => {
|
|
228
|
+
const address = getAddress(nativeAddress);
|
|
229
|
+
validateNative(address, chainName);
|
|
230
|
+
return hexToBytes(address);
|
|
231
|
+
},
|
|
232
|
+
nativeToBytes32Hex: (nativeAddress) => {
|
|
233
|
+
const address = getAddress(nativeAddress);
|
|
234
|
+
validateNative(address, chainName);
|
|
235
|
+
return hexZeroPad(address, 32);
|
|
236
|
+
},
|
|
237
|
+
nativeToBytes32: (nativeAddress) => {
|
|
238
|
+
return hexToBytes(addressParser(chainName).nativeToBytes32Hex(nativeAddress));
|
|
239
|
+
},
|
|
240
|
+
parseNative: (nativeAddress) => {
|
|
241
|
+
// Specific case to make tron a little less flaky, handle the 41 prefix
|
|
242
|
+
if (chainName === ChainName.TRON) {
|
|
243
|
+
nativeAddress = nativeAddress.startsWith('41')
|
|
244
|
+
? `0x${nativeAddress.slice(2)}`
|
|
245
|
+
: nativeAddress;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (!validateNative(nativeAddress, chainName)) {
|
|
249
|
+
throw new Error('Invalid native address: ' + nativeAddress);
|
|
250
|
+
}
|
|
251
|
+
return addressParser(chainName).nativeToNormalized(nativeAddress);
|
|
252
|
+
},
|
|
253
|
+
parseNativeToHex: (nativeAddress) => {
|
|
254
|
+
return addressParser(chainName).parseNative(nativeAddress) as unknown as HexString;
|
|
255
|
+
},
|
|
256
|
+
encoding: AddressEncoding.HEX,
|
|
257
|
+
};
|
|
258
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './addressParser';
|
|
2
2
|
export * from './utils';
|
package/dist/223VIKVV.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils.ts"],"names":["getNetworkName","__name","chainName","environment","includes"],"mappings":";;;;;AAAO,IAAMA,cAAAA,mBAAiBC,mBAAA,CAAA,CAACC,SAAAA,EAAmBC,WAAAA,KAAAA;AAC9C,EAAA,OAAO;AAAC,IAAA,UAAA;AAAY,IAAA;IAAWC,QAAAA,CAASD,WAAAA,IAClC,CAAA,EAAGD,SAAAA,mBACH,CAAA,EAAGA,SAAAA,IAAaC,WAAAA,CAAAA,CAAAA;AAC1B,CAAA,EAJ8B,gBAAA","file":"223VIKVV.cjs","sourcesContent":["export const getNetworkName = (chainName: string, environment: string) => {\n return ['localnet', 'sandbox'].includes(environment)\n ? `${chainName}-sandbox-local`\n : `${chainName}-${environment}`;\n};\n"]}
|