@subsquid/evm-codec 0.3.0 → 1.0.0
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/lib/codec.d.ts +57 -12
- package/lib/codec.d.ts.map +1 -1
- package/lib/codec.js.map +1 -1
- package/lib/codecs/array.d.ts +1 -3
- package/lib/codecs/array.d.ts.map +1 -1
- package/lib/codecs/array.js +13 -9
- package/lib/codecs/array.js.map +1 -1
- package/lib/codecs/primitives.d.ts +2 -17
- package/lib/codecs/primitives.d.ts.map +1 -1
- package/lib/codecs/primitives.js +46 -152
- package/lib/codecs/primitives.js.map +1 -1
- package/lib/codecs/struct.d.ts +16 -9
- package/lib/codecs/struct.d.ts.map +1 -1
- package/lib/codecs/struct.js +53 -40
- package/lib/codecs/struct.js.map +1 -1
- package/lib/dsl.d.ts +11 -0
- package/lib/dsl.d.ts.map +1 -0
- package/lib/dsl.js +33 -0
- package/lib/dsl.js.map +1 -0
- package/lib/index.d.ts +7 -4
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +7 -6
- package/lib/index.js.map +1 -1
- package/lib/sink/bounds.d.ts +21 -0
- package/lib/sink/bounds.d.ts.map +1 -0
- package/lib/sink/bounds.js +24 -0
- package/lib/sink/bounds.js.map +1 -0
- package/lib/sink/bytes.d.ts +41 -0
- package/lib/sink/bytes.d.ts.map +1 -0
- package/lib/sink/bytes.js +261 -0
- package/lib/sink/bytes.js.map +1 -0
- package/lib/sink/hex.d.ts +33 -0
- package/lib/sink/hex.d.ts.map +1 -0
- package/lib/sink/hex.js +289 -0
- package/lib/sink/hex.js.map +1 -0
- package/lib/{src.d.ts → src/bytes.d.ts} +7 -5
- package/lib/src/bytes.d.ts.map +1 -0
- package/lib/src/bytes.js +161 -0
- package/lib/src/bytes.js.map +1 -0
- package/lib/src/hex.d.ts +33 -0
- package/lib/src/hex.d.ts.map +1 -0
- package/lib/src/hex.js +164 -0
- package/lib/src/hex.js.map +1 -0
- package/lib/util.d.ts +6 -0
- package/lib/util.d.ts.map +1 -0
- package/lib/util.js +20 -0
- package/lib/util.js.map +1 -0
- package/package.json +6 -8
- package/src/codec.ts +65 -19
- package/src/codecs/array.test.ts +87 -0
- package/src/codecs/array.ts +6 -11
- package/src/codecs/primitives.test.ts +27 -0
- package/src/codecs/primitives.ts +87 -208
- package/src/codecs/struct.test.ts +69 -0
- package/src/codecs/struct.ts +80 -61
- package/src/dsl.ts +16 -0
- package/src/index.ts +7 -4
- package/src/sink/bounds.ts +26 -0
- package/src/sink/bytes.test.ts +92 -0
- package/src/sink/bytes.ts +290 -0
- package/src/sink/hex.ts +311 -0
- package/src/src/bytes.test.ts +114 -0
- package/src/src/bytes.ts +187 -0
- package/src/src/hex.ts +191 -0
- package/src/util.ts +19 -0
- package/lib/safeToNumber.d.ts +0 -2
- package/lib/safeToNumber.d.ts.map +0 -1
- package/lib/safeToNumber.js +0 -11
- package/lib/safeToNumber.js.map +0 -1
- package/lib/sink.d.ts +0 -43
- package/lib/sink.d.ts.map +0 -1
- package/lib/sink.js +0 -215
- package/lib/sink.js.map +0 -1
- package/lib/src.d.ts.map +0 -1
- package/lib/src.js +0 -141
- package/lib/src.js.map +0 -1
- package/src/safeToNumber.ts +0 -6
- package/src/sink.ts +0 -241
- package/src/src.ts +0 -158
package/lib/src/hex.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HexSrc = void 0;
|
|
4
|
+
const codec_1 = require("../codec");
|
|
5
|
+
const HEX_BYTE = 2;
|
|
6
|
+
const WORD_HEX = codec_1.WORD_SIZE * HEX_BYTE;
|
|
7
|
+
const I64_SIGN_BIT = 1n << 63n;
|
|
8
|
+
const I64_RANGE = 1n << 64n;
|
|
9
|
+
const I128_SIGN_BIT = 1n << 127n;
|
|
10
|
+
const I128_RANGE = 1n << 128n;
|
|
11
|
+
const I256_SIGN_BIT = 1n << 255n;
|
|
12
|
+
const I256_RANGE = 1n << 256n;
|
|
13
|
+
const TEXT_DECODER = new TextDecoder('utf-8');
|
|
14
|
+
class HexSrc {
|
|
15
|
+
buf;
|
|
16
|
+
base;
|
|
17
|
+
endChar;
|
|
18
|
+
pos;
|
|
19
|
+
oldPos;
|
|
20
|
+
constructor(hex, strOffset = 2, strEnd = hex.length) {
|
|
21
|
+
this.buf = hex;
|
|
22
|
+
this.base = strOffset;
|
|
23
|
+
this.endChar = strEnd;
|
|
24
|
+
this.pos = strOffset;
|
|
25
|
+
this.oldPos = strOffset;
|
|
26
|
+
}
|
|
27
|
+
slice(start, end) {
|
|
28
|
+
const s = this.base + HEX_BYTE * start;
|
|
29
|
+
const e = end == null ? this.endChar : this.base + HEX_BYTE * end;
|
|
30
|
+
return new HexSrc(this.buf, s, e);
|
|
31
|
+
}
|
|
32
|
+
u8() {
|
|
33
|
+
const start = this.pos + WORD_HEX - 2;
|
|
34
|
+
const val = Number.parseInt(this.buf.slice(start, start + 2), 16);
|
|
35
|
+
this.pos += WORD_HEX;
|
|
36
|
+
return val;
|
|
37
|
+
}
|
|
38
|
+
i8() {
|
|
39
|
+
return Number(this.i256());
|
|
40
|
+
}
|
|
41
|
+
u16() {
|
|
42
|
+
const start = this.pos + WORD_HEX - 4;
|
|
43
|
+
const val = Number.parseInt(this.buf.slice(start, start + 4), 16);
|
|
44
|
+
this.pos += WORD_HEX;
|
|
45
|
+
return val;
|
|
46
|
+
}
|
|
47
|
+
i16() {
|
|
48
|
+
return Number(this.i256());
|
|
49
|
+
}
|
|
50
|
+
u32() {
|
|
51
|
+
const start = this.pos + WORD_HEX - 8;
|
|
52
|
+
const val = Number.parseInt(this.buf.slice(start, start + 8), 16);
|
|
53
|
+
this.pos += WORD_HEX;
|
|
54
|
+
return val;
|
|
55
|
+
}
|
|
56
|
+
i32() {
|
|
57
|
+
return Number(this.i256());
|
|
58
|
+
}
|
|
59
|
+
u64() {
|
|
60
|
+
const start = this.pos + WORD_HEX - 16;
|
|
61
|
+
const val = BigInt(`0x${this.buf.slice(start, start + 16)}`);
|
|
62
|
+
this.pos += WORD_HEX;
|
|
63
|
+
return val;
|
|
64
|
+
}
|
|
65
|
+
i64() {
|
|
66
|
+
const raw = this.u64();
|
|
67
|
+
return raw < I64_SIGN_BIT ? raw : raw - I64_RANGE;
|
|
68
|
+
}
|
|
69
|
+
u128() {
|
|
70
|
+
const start = this.pos + WORD_HEX - 32;
|
|
71
|
+
const val = BigInt(`0x${this.buf.slice(start, start + 32)}`);
|
|
72
|
+
this.pos += WORD_HEX;
|
|
73
|
+
return val;
|
|
74
|
+
}
|
|
75
|
+
i128() {
|
|
76
|
+
const raw = this.u128();
|
|
77
|
+
return raw < I128_SIGN_BIT ? raw : raw - I128_RANGE;
|
|
78
|
+
}
|
|
79
|
+
u256() {
|
|
80
|
+
const val = BigInt(`0x${this.buf.slice(this.pos, this.pos + WORD_HEX)}`);
|
|
81
|
+
this.pos += WORD_HEX;
|
|
82
|
+
return val;
|
|
83
|
+
}
|
|
84
|
+
i256() {
|
|
85
|
+
const raw = this.u256();
|
|
86
|
+
return raw < I256_SIGN_BIT ? raw : raw - I256_RANGE;
|
|
87
|
+
}
|
|
88
|
+
address() {
|
|
89
|
+
const start = this.pos + WORD_HEX - 40;
|
|
90
|
+
const val = `0x${this.buf.slice(start, start + 40)}`;
|
|
91
|
+
this.pos += WORD_HEX;
|
|
92
|
+
return val;
|
|
93
|
+
}
|
|
94
|
+
bytes() {
|
|
95
|
+
const ptr = this.u32();
|
|
96
|
+
this.jump(ptr);
|
|
97
|
+
const len = Number(this.u256());
|
|
98
|
+
this.#assertLength(len, 'bytes');
|
|
99
|
+
const sub = this.buf.slice(this.pos, this.pos + HEX_BYTE * len);
|
|
100
|
+
const val = Buffer.from(sub, 'hex');
|
|
101
|
+
this.jumpBack();
|
|
102
|
+
return val;
|
|
103
|
+
}
|
|
104
|
+
bytesHex() {
|
|
105
|
+
const ptr = this.u32();
|
|
106
|
+
this.jump(ptr);
|
|
107
|
+
const len = Number(this.u256());
|
|
108
|
+
this.#assertLength(len, 'bytes');
|
|
109
|
+
const val = `0x${this.buf.slice(this.pos, this.pos + HEX_BYTE * len)}`;
|
|
110
|
+
this.jumpBack();
|
|
111
|
+
return val;
|
|
112
|
+
}
|
|
113
|
+
staticBytes(len) {
|
|
114
|
+
if (len > 32) {
|
|
115
|
+
throw new Error(`bytes${len} is not a valid type`);
|
|
116
|
+
}
|
|
117
|
+
const sub = this.buf.slice(this.pos, this.pos + HEX_BYTE * len);
|
|
118
|
+
this.pos += WORD_HEX;
|
|
119
|
+
return Buffer.from(sub, 'hex');
|
|
120
|
+
}
|
|
121
|
+
staticBytesHex(len) {
|
|
122
|
+
if (len > 32) {
|
|
123
|
+
throw new Error(`bytes${len} is not a valid type`);
|
|
124
|
+
}
|
|
125
|
+
const val = `0x${this.buf.slice(this.pos, this.pos + HEX_BYTE * len)}`;
|
|
126
|
+
this.pos += WORD_HEX;
|
|
127
|
+
return val;
|
|
128
|
+
}
|
|
129
|
+
string() {
|
|
130
|
+
const ptr = this.u32();
|
|
131
|
+
this.jump(ptr, 'string');
|
|
132
|
+
const len = Number(this.u256());
|
|
133
|
+
this.#assertLength(len, 'string');
|
|
134
|
+
const sub = this.buf.slice(this.pos, this.pos + HEX_BYTE * len);
|
|
135
|
+
const val = TEXT_DECODER.decode(Buffer.from(sub, 'hex'));
|
|
136
|
+
this.jumpBack();
|
|
137
|
+
return val;
|
|
138
|
+
}
|
|
139
|
+
bool() {
|
|
140
|
+
const a = this.buf.charCodeAt(this.pos + WORD_HEX - 2);
|
|
141
|
+
const b = this.buf.charCodeAt(this.pos + WORD_HEX - 1);
|
|
142
|
+
this.pos += WORD_HEX;
|
|
143
|
+
return a !== 48 /* '0' */ || b !== 48;
|
|
144
|
+
}
|
|
145
|
+
#assertLength(len, typeName) {
|
|
146
|
+
if (this.endChar - this.pos < HEX_BYTE * len) {
|
|
147
|
+
throw new RangeError(`Unexpected end of input. Attempting to read ${typeName} of length ${len} from 0x${this.buf.slice(this.base, this.endChar)}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
jump(pos, typeName) {
|
|
151
|
+
const target = this.base + HEX_BYTE * pos;
|
|
152
|
+
if (pos < 0 || target >= this.endChar) {
|
|
153
|
+
const what = typeName ? `${typeName} ` : '';
|
|
154
|
+
throw new RangeError(`Unexpected pointer location: 0x${pos.toString(16)}. Attempting to read ${what}from 0x${this.buf.slice(this.base, this.endChar)}`);
|
|
155
|
+
}
|
|
156
|
+
this.oldPos = this.pos;
|
|
157
|
+
this.pos = target;
|
|
158
|
+
}
|
|
159
|
+
jumpBack() {
|
|
160
|
+
this.pos = this.oldPos;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
exports.HexSrc = HexSrc;
|
|
164
|
+
//# sourceMappingURL=hex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hex.js","sourceRoot":"","sources":["../../src/src/hex.ts"],"names":[],"mappings":"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"}
|
package/lib/util.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI;KAAE,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAC,GAAG,OAAO,CAAA;AAExD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK7C;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK/C"}
|
package/lib/util.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.propName = propName;
|
|
4
|
+
exports.propAccess = propAccess;
|
|
5
|
+
function propName(prop) {
|
|
6
|
+
if (isValidProperty(prop)) {
|
|
7
|
+
return prop;
|
|
8
|
+
}
|
|
9
|
+
return `[${JSON.stringify(prop)}]`;
|
|
10
|
+
}
|
|
11
|
+
function propAccess(prop) {
|
|
12
|
+
if (isValidProperty(prop)) {
|
|
13
|
+
return `.${prop}`;
|
|
14
|
+
}
|
|
15
|
+
return `[${JSON.stringify(prop)}]`;
|
|
16
|
+
}
|
|
17
|
+
function isValidProperty(s) {
|
|
18
|
+
return /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(s);
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=util.js.map
|
package/lib/util.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;AAEA,4BAKC;AAED,gCAKC;AAZD,SAAgB,QAAQ,CAAC,IAAY;IACjC,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,IAAI,CAAA;IACf,CAAC;IACD,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAA;AACtC,CAAC;AAED,SAAgB,UAAU,CAAC,IAAY;IACnC,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,IAAI,IAAI,EAAE,CAAA;IACrB,CAAC;IACD,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAA;AACtC,CAAC;AAED,SAAS,eAAe,CAAC,CAAS;IAC9B,OAAO,4BAA4B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AAC/C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@subsquid/evm-codec",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "EVM encoder/decoder tools",
|
|
5
5
|
"license": "GPL-3.0-or-later",
|
|
6
|
-
"repository": "git@github.com:subsquid/squid.git",
|
|
6
|
+
"repository": "git@github.com:subsquid/squid-sdk.git",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
9
9
|
},
|
|
@@ -13,14 +13,12 @@
|
|
|
13
13
|
"src"
|
|
14
14
|
],
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@subsquid/util-internal-hex": "^1.2.
|
|
16
|
+
"@subsquid/util-internal-hex": "^1.2.3"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@types/node": "^
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"viem": "^2.8.14",
|
|
23
|
-
"vitest": "^1.4.0"
|
|
19
|
+
"@types/node": "^24.0.0",
|
|
20
|
+
"typescript": "5.5.4",
|
|
21
|
+
"vitest": "4.1.5"
|
|
24
22
|
},
|
|
25
23
|
"scripts": {
|
|
26
24
|
"build": "rm -rf lib && tsc -p tsconfig.build.json",
|
package/src/codec.ts
CHANGED
|
@@ -1,28 +1,74 @@
|
|
|
1
|
-
import type { Sink } from './sink'
|
|
2
|
-
import type { Src } from './src'
|
|
3
|
-
|
|
4
1
|
export const WORD_SIZE = 32
|
|
5
2
|
|
|
6
3
|
export type BaseType = 'int' | 'address' | 'bool' | 'bytes' | 'string' | 'array' | 'struct'
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
/** ABI encoder backend — writes one 32-byte word per call, manages the head/tail structure. */
|
|
6
|
+
export interface Sink {
|
|
7
|
+
u8(val: number): void
|
|
8
|
+
i8(val: number): void
|
|
9
|
+
u16(val: number): void
|
|
10
|
+
i16(val: number): void
|
|
11
|
+
u32(val: number): void
|
|
12
|
+
i32(val: number): void
|
|
13
|
+
u64(val: bigint): void
|
|
14
|
+
i64(val: bigint): void
|
|
15
|
+
u128(val: bigint): void
|
|
16
|
+
i128(val: bigint): void
|
|
17
|
+
u256(val: bigint): void
|
|
18
|
+
i256(val: bigint): void
|
|
19
|
+
bool(val: boolean): void
|
|
20
|
+
bytes(val: Uint8Array | string): void
|
|
21
|
+
staticBytes(len: number, val: Uint8Array | string): void
|
|
22
|
+
address(val: string): void
|
|
23
|
+
string(val: string): void
|
|
24
|
+
/** Begin the tail of a dynamic type (writes the head offset, enters tail context). */
|
|
25
|
+
openTail(slotsCount?: number): void
|
|
26
|
+
/** Begin the tail of a dynamic array (writes offset + element count, enters tail context). */
|
|
27
|
+
openArray(count: number): void
|
|
28
|
+
/** End the current tail, propagate its size to the parent context. */
|
|
29
|
+
closeTail(): void
|
|
30
|
+
toString(): string
|
|
14
31
|
}
|
|
15
32
|
|
|
16
|
-
|
|
17
|
-
|
|
33
|
+
/** ABI decoder backend — reads one 32-byte word per call, follows offset pointers. */
|
|
34
|
+
export interface Src {
|
|
35
|
+
u8(): number
|
|
36
|
+
i8(): number
|
|
37
|
+
u16(): number
|
|
38
|
+
i16(): number
|
|
39
|
+
u32(): number
|
|
40
|
+
i32(): number
|
|
41
|
+
u64(): bigint
|
|
42
|
+
i64(): bigint
|
|
43
|
+
u128(): bigint
|
|
44
|
+
i128(): bigint
|
|
45
|
+
u256(): bigint
|
|
46
|
+
i256(): bigint
|
|
47
|
+
bool(): boolean
|
|
48
|
+
bytes(): Uint8Array
|
|
49
|
+
/** Decode a dynamic `bytes` value as a `0x`-prefixed hex string. */
|
|
50
|
+
bytesHex(): string
|
|
51
|
+
staticBytes(len: number): Uint8Array
|
|
52
|
+
/** Decode a `bytes<N>` value as a `0x`-prefixed hex string. */
|
|
53
|
+
staticBytesHex(len: number): string
|
|
54
|
+
address(): string
|
|
55
|
+
string(): string
|
|
56
|
+
/** Create a sub-view of this source starting at byte offset `start`. */
|
|
57
|
+
slice(start: number, end?: number): Src
|
|
58
|
+
/** Follow an offset pointer: save the current position and jump to `pos`. */
|
|
59
|
+
jump(pos: number, typeName?: string): void
|
|
60
|
+
/** Return to the position saved by the last `jump`. */
|
|
61
|
+
jumpBack(): void
|
|
18
62
|
}
|
|
19
63
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
64
|
+
export interface Codec<TIn, TOut = TIn> {
|
|
65
|
+
encode(sink: Sink, val: TIn): void
|
|
66
|
+
decode(src: Src): TOut
|
|
67
|
+
isDynamic: boolean
|
|
68
|
+
slotsCount?: number
|
|
69
|
+
baseType: BaseType
|
|
70
|
+
}
|
|
25
71
|
|
|
26
|
-
export type
|
|
27
|
-
|
|
28
|
-
}
|
|
72
|
+
export type Struct = {
|
|
73
|
+
[key: string]: Codec<any>
|
|
74
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {describe, expect, it} from 'vitest'
|
|
2
|
+
import {address, array, bytes, fixedSizeArray, int8, BytesSink, BytesSrc, string, uint256} from '..'
|
|
3
|
+
|
|
4
|
+
function roundtrip<T>(codec: {encode: (s: BytesSink, v: T) => void; decode: (s: BytesSrc) => T; slotsCount?: number}, value: T) {
|
|
5
|
+
const sink = new BytesSink(codec.slotsCount ?? 1)
|
|
6
|
+
codec.encode(sink, value)
|
|
7
|
+
expect(codec.decode(new BytesSrc(sink.result()))).toStrictEqual(value)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
describe('fixed size array', () => {
|
|
11
|
+
it('static types', () => {
|
|
12
|
+
roundtrip(fixedSizeArray(int8, 5), [1, 2, -3, 4, 5])
|
|
13
|
+
roundtrip(fixedSizeArray(int8, 5), [1, 2, -3, -4, 5])
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('dynamic types', () => {
|
|
17
|
+
const arr = fixedSizeArray(string, 3)
|
|
18
|
+
roundtrip(arr, [
|
|
19
|
+
'aaa',
|
|
20
|
+
'a relatively long string to test what happens when the string is long, longer than 32 bytes or even better, longer than 64 bytes!!!',
|
|
21
|
+
'dasdas',
|
|
22
|
+
])
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('deep nested arrays', () => {
|
|
26
|
+
const arr = fixedSizeArray(fixedSizeArray(string, 3), 2)
|
|
27
|
+
const data = [
|
|
28
|
+
'aaa',
|
|
29
|
+
'a relatively long string to test what happens when the string is long, longer than 32 bytes or even better, longer than 64 bytes!!!',
|
|
30
|
+
'dasdas',
|
|
31
|
+
]
|
|
32
|
+
roundtrip(arr, [data, [...data].reverse()])
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
describe('dynamic size array', () => {
|
|
37
|
+
it('static types', () => {
|
|
38
|
+
roundtrip(array(int8), [1, 2, -3, 4, 5])
|
|
39
|
+
roundtrip(array(int8), [1, 2, -3, -4, 5])
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('array of arrays', () => {
|
|
43
|
+
roundtrip(array(array(int8)), [
|
|
44
|
+
[1, 2, -3, -4, 5],
|
|
45
|
+
[1, 2, -3, -4, 5],
|
|
46
|
+
])
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('dynamic types', () => {
|
|
50
|
+
roundtrip(array(string), [
|
|
51
|
+
'aaa',
|
|
52
|
+
'a relatively long string to test what happens when the string is long, longer than 32 bytes or even better, longer than 64 bytes!!!',
|
|
53
|
+
'dasdas',
|
|
54
|
+
])
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('hardcore dynamic types', () => {
|
|
58
|
+
const sink = new BytesSink(5)
|
|
59
|
+
const arr1 = array(array(fixedSizeArray(string, 3)))
|
|
60
|
+
const arr2 = array(array(uint256))
|
|
61
|
+
const arr3 = array(fixedSizeArray(bytes, 2))
|
|
62
|
+
const data1 = [
|
|
63
|
+
[
|
|
64
|
+
['aaa', 'bbb', 'ccc'],
|
|
65
|
+
['ddd', 'eee', 'fff'],
|
|
66
|
+
],
|
|
67
|
+
[['ggg', 'hhh', 'iii']],
|
|
68
|
+
]
|
|
69
|
+
const data2 = [[1n, 2n, 3n], [], [4n]]
|
|
70
|
+
const data3 = [
|
|
71
|
+
['0x1234', '0x5678'],
|
|
72
|
+
['0xdead', '0xbeef'],
|
|
73
|
+
]
|
|
74
|
+
arr1.encode(sink, data1)
|
|
75
|
+
address.encode(sink, '0x1234567890123456789012345678901234567890')
|
|
76
|
+
arr3.encode(sink, data3)
|
|
77
|
+
arr2.encode(sink, data2)
|
|
78
|
+
uint256.encode(sink, 123n)
|
|
79
|
+
|
|
80
|
+
const src = new BytesSrc(sink.result())
|
|
81
|
+
expect(arr1.decode(src)).toStrictEqual(data1)
|
|
82
|
+
expect(address.decode(src)).toBe('0x1234567890123456789012345678901234567890')
|
|
83
|
+
expect(arr3.decode(src)).toStrictEqual(data3)
|
|
84
|
+
expect(arr2.decode(src)).toStrictEqual(data2)
|
|
85
|
+
expect(uint256.decode(src)).toBe(123n)
|
|
86
|
+
})
|
|
87
|
+
})
|
package/src/codecs/array.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { Codec,
|
|
2
|
-
import { Sink } from '../sink'
|
|
3
|
-
import { Src } from '../src'
|
|
1
|
+
import { WORD_SIZE, type Codec, type Sink, type Src } from '../codec'
|
|
4
2
|
|
|
5
3
|
export class ArrayCodec<const TIn, const TOut> implements Codec<readonly TIn[], readonly TOut[]> {
|
|
6
4
|
public readonly isDynamic = true
|
|
@@ -8,20 +6,17 @@ export class ArrayCodec<const TIn, const TOut> implements Codec<readonly TIn[],
|
|
|
8
6
|
constructor(public readonly item: Codec<TIn, TOut>) {}
|
|
9
7
|
|
|
10
8
|
encode(sink: Sink, val: TIn[]) {
|
|
11
|
-
sink.
|
|
9
|
+
sink.openArray(val.length)
|
|
12
10
|
for (let i = 0; i < val.length; i++) {
|
|
13
11
|
this.item.encode(sink, val[i])
|
|
14
12
|
}
|
|
15
|
-
sink.
|
|
16
|
-
sink.endCurrentDataArea()
|
|
13
|
+
sink.closeTail()
|
|
17
14
|
}
|
|
18
15
|
|
|
19
16
|
decode(src: Src): TOut[] {
|
|
20
17
|
const offset = src.u32()
|
|
21
|
-
|
|
22
|
-
src.safeJump(offset, 'array')
|
|
18
|
+
src.jump(offset)
|
|
23
19
|
const len = src.u32()
|
|
24
|
-
|
|
25
20
|
const tmpSrc = src.slice(offset + WORD_SIZE)
|
|
26
21
|
const val = new Array(len)
|
|
27
22
|
for (let i = 0; i < val.length; i++) {
|
|
@@ -55,11 +50,11 @@ export class FixedSizeArrayCodec<const TIn, const TOut> implements Codec<readonl
|
|
|
55
50
|
}
|
|
56
51
|
|
|
57
52
|
private encodeDynamic(sink: Sink, val: TIn[]) {
|
|
58
|
-
sink.
|
|
53
|
+
sink.openTail(this.size)
|
|
59
54
|
for (let i = 0; i < val.length; i++) {
|
|
60
55
|
this.item.encode(sink, val[i])
|
|
61
56
|
}
|
|
62
|
-
sink.
|
|
57
|
+
sink.closeTail()
|
|
63
58
|
}
|
|
64
59
|
|
|
65
60
|
decode(src: Src): TOut[] {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {describe, expect, it} from "vitest";
|
|
2
|
+
import {bytes32, BytesSink, BytesSrc, string, uint256} from "..";
|
|
3
|
+
|
|
4
|
+
describe('Strings', () => {
|
|
5
|
+
it('should encode and decode strings', async () => {
|
|
6
|
+
const sink = new BytesSink(1)
|
|
7
|
+
string.encode(sink, 'hello')
|
|
8
|
+
expect(sink.toString()).toEqual('0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000')
|
|
9
|
+
expect(string.decode(new BytesSrc(sink.result()))).toEqual('hello');
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should encode and decode empty string', async () => {
|
|
13
|
+
const sink = new BytesSink(1)
|
|
14
|
+
string.encode(sink, '')
|
|
15
|
+
expect(sink.toString()).toEqual('0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000')
|
|
16
|
+
expect(string.decode(new BytesSrc(sink.result()))).toEqual('');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should fail on decoding invalid data', async () => {
|
|
20
|
+
let sink = new BytesSink(1)
|
|
21
|
+
uint256.encode(sink, 1337)
|
|
22
|
+
expect(() => string.decode(new BytesSrc(sink.result()))).toThrow('Unexpected pointer location: 0x539. Attempting to read string from 0x0000000000000000000000000000000000000000000000000000000000000539')
|
|
23
|
+
sink = new BytesSink(1)
|
|
24
|
+
bytes32.encode(sink, '0x4b45590000000000000000000000000000000000000000000000000000000000')
|
|
25
|
+
expect(() => string.decode(new BytesSrc(sink.result()))).toThrow('Unexpected end of input. Attempting to read string of length 3.404599034663955e+76 from 0x4b45590000000000000000000000000000000000000000000000000000000000')
|
|
26
|
+
});
|
|
27
|
+
});
|