aboutsummaryrefslogtreecommitdiffstats
path: root/packages/utils/test/abi_encoder/optimizer_test.ts
blob: c0640583d188f5187d1463bb6c64f64ff3924fad (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
import * as chai from 'chai';
import 'mocha';

import { AbiEncoder, BigNumber } from '../../src/';
import { chaiSetup } from '../utils/chai_setup';

import * as OptimizedAbis from './abi_samples/optimizer_abis';

chaiSetup.configure();
const expect = chai.expect;

describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
    const encodingRules: AbiEncoder.EncodingRules = { shouldOptimize: true };
    it('Duplicate Dynamic Arrays with Static Elements', async () => {
        // Generate calldata
        const method = new AbiEncoder.Method(OptimizedAbis.duplicateDynamicArraysWithStaticElements);
        const array1 = [new BigNumber(100), new BigNumber(150)];
        const array2 = array1;
        const args = [array1, array2];
        // Validata calldata
        const optimizedCalldata = method.encode(args, encodingRules);
        const expectedOptimizedCalldata =
            '0x7221063300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096';
        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
        // Validate decoding
        const decodedArgs = method.decode(optimizedCalldata, { structsAsObjects: false });
        expect(decodedArgs).to.be.deep.equal(args);
    });
    it('Duplicate Dynamic Arrays with Dynamic Elements', async () => {
        // Generate calldata
        const method = new AbiEncoder.Method(OptimizedAbis.duplicateDynamicArraysWithDynamicElements);
        const array1 = ['Hello', 'World'];
        const array2 = array1;
        const args = [array1, array2];
        // Validata calldata
        const optimizedCalldata = method.encode(args, encodingRules);
        const expectedOptimizedCalldata =
            '0xbb4f12e300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
        // Validate decoding
        const decodedArgs = method.decode(optimizedCalldata, { structsAsObjects: false });
        expect(decodedArgs).to.be.deep.equal(args);
    });
    it('Duplicate Static Arrays with Static Elements (should not optimize)', async () => {
        // Generate calldata
        const method = new AbiEncoder.Method(OptimizedAbis.duplicateStaticArraysWithStaticElements);
        const array1 = [new BigNumber(100), new BigNumber(150)];
        const array2 = array1;
        const args = [array1, array2];
        // Validata calldata
        const optimizedCalldata = method.encode(args, encodingRules);
        const expectedOptimizedCalldata =
            '0x7f8130430000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096';
        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
        const unoptimizedCalldata = method.encode(args);
        expect(optimizedCalldata).to.be.equal(unoptimizedCalldata);
        // Validate decoding
        const decodedArgs = method.decode(optimizedCalldata, { structsAsObjects: false });
        expect(decodedArgs).to.be.deep.equal(args);
    });
    it('Duplicate Static Arrays with Dynamic Elements', async () => {
        // Generate calldata
        const method = new AbiEncoder.Method(OptimizedAbis.duplicateStaticArraysWithDynamicElements);
        const array1 = ['Hello', 'World'];
        const array2 = array1;
        const args = [array1, array2];
        // Validata calldata
        const optimizedCalldata = method.encode(args, encodingRules);
        const expectedOptimizedCalldata =
            '0x9fe31f8e0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
        // Validate decoding
        const decodedArgs = method.decode(optimizedCalldata, { structsAsObjects: false });
        expect(decodedArgs).to.be.deep.equal(args);
    });
    it('Duplicate Array Elements (should optimize)', async () => {
        // Generate calldata
        const method = new AbiEncoder.Method(OptimizedAbis.duplicateArrayElements);
        const strings = ['Hello', 'World', 'Hello', 'World'];
        const args = [strings];
        // Validate calldata
        const optimizedCalldata = method.encode(args, encodingRules);
        const expectedOptimizedCalldata =
            '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
        // Validate decoding
        const decodedArgs = method.decode(optimizedCalldata, { structsAsObjects: false });
        expect(decodedArgs).to.be.deep.equal(args);
    });
    it('Duplicate Tuple Fields', async () => {
        // Generate calldata
        const method = new AbiEncoder.Method(OptimizedAbis.duplicateTupleFields);
        const tuple = ['Hello', 'Hello'];
        const args = [tuple];
        // Validata calldata
        const optimizedCalldata = method.encode(args, encodingRules);
        const expectedOptimizedCalldata =
            '0x16780a5e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000';
        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
        // Validate decoding
        const decodedArgs = method.decode(optimizedCalldata, { structsAsObjects: false });
        expect(decodedArgs).to.be.deep.equal(args);
    });
    it('Duplicate Strings', async () => {
        // Description:
        //   Two dynamic arrays with the same values.
        //   In the optimized calldata, only one set of elements should be included.
        //   Both arrays should point to this set.
        // Generate calldata
        const method = new AbiEncoder.Method(OptimizedAbis.duplicateStrings);
        const args = ['Hello', 'Hello'];
        // Validata calldata
        const optimizedCalldata = method.encode(args, encodingRules);
        const expectedOptimizedCalldata =
            '0x07370bfa00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000';
        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
        // Validate decoding
        const decodedArgs = method.decode(optimizedCalldata, { structsAsObjects: false });
        expect(decodedArgs).to.be.deep.equal(args);
    });
    it('Duplicate Bytes', async () => {
        // Description:
        //   Two dynamic arrays with the same values.
        //   In the optimized calldata, only one set of elements should be included.
        //   Both arrays should point to this set.
        // Generate calldata
        const method = new AbiEncoder.Method(OptimizedAbis.duplicateBytes);
        const value = '0x01020304050607080910111213141516171819202122232425262728293031323334353637383940';
        const args = [value, value];
        // Validata calldata
        const optimizedCalldata = method.encode(args, encodingRules);
        const expectedOptimizedCalldata =
            '0x6045e42900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002801020304050607080910111213141516171819202122232425262728293031323334353637383940000000000000000000000000000000000000000000000000';
        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
        // Validate decoding
        const decodedArgs = method.decode(optimizedCalldata, { structsAsObjects: false });
        expect(decodedArgs).to.be.deep.equal(args);
    });
    it('Duplicate Tuples', async () => {
        // Generate calldata
        const method = new AbiEncoder.Method(OptimizedAbis.duplicateTuples);
        const tuple1 = ['Hello, World!', new BigNumber(424234)];
        const tuple2 = tuple1;
        const args = [tuple1, tuple2];
        // Validata calldata
        const optimizedCalldata = method.encode(args, encodingRules);
        const expectedOptimizedCalldata =
            '0x564f826d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000006792a000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c642100000000000000000000000000000000000000';
        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
        // Validate decoding
        const decodedArgs = method.decode(optimizedCalldata, { structsAsObjects: false });
        expect(decodedArgs).to.be.deep.equal(args);
    });
    it('Duplicate Fields Across Two Tuples', async () => {
        // Description:
        // Generate calldata
        const method = new AbiEncoder.Method(OptimizedAbis.duplicateTuples);
        const tuple1 = ['Hello, World!', new BigNumber(1)];
        const tuple2 = [tuple1[0], new BigNumber(2)];
        const args = [tuple1, tuple2];
        // Validata calldata
        const optimizedCalldata = method.encode(args, encodingRules);
        const expectedOptimizedCalldata =
            '0x564f826d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c642100000000000000000000000000000000000000';
        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
        // Validate decoding
        const decodedArgs = method.decode(optimizedCalldata, { structsAsObjects: false });
        expect(decodedArgs).to.be.deep.equal(args);
    });
    it('Duplicate Arrays, Nested in Separate Tuples', async () => {
        // Generate calldata
        const method = new AbiEncoder.Method(OptimizedAbis.duplicateArraysNestedInTuples);
        const array = [new BigNumber(100), new BigNumber(150), new BigNumber(200)];
        const tuple1 = [array];
        const tuple2 = [array, 'extra argument to prevent exactly matching the tuples'];
        const args = [tuple1, tuple2];
        // Validata calldata
        const optimizedCalldata = method.encode(args, encodingRules);
        const expectedOptimizedCalldata =
            '0x18970a9e000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000c80000000000000000000000000000000000000000000000000000000000000035657874726120617267756d656e7420746f2070726576656e742065786163746c79206d61746368696e6720746865207475706c65730000000000000000000000';
        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
        // Validate decoding
        const decodedArgs = method.decode(optimizedCalldata, { structsAsObjects: false });
        expect(decodedArgs).to.be.deep.equal(args);
    });
    it('Duplicate Tuples, Nested in Separate Tuples', async () => {
        // Generate calldata
        const method = new AbiEncoder.Method(OptimizedAbis.duplicateTuplesNestedInTuples);
        const nestedTuple = ['Hello, World!'];
        const tuple1 = [nestedTuple];
        const tuple2 = [nestedTuple, 'extra argument to prevent exactly matching the tuples'];
        const args = [tuple1, tuple2];
        // Validata calldata
        const optimizedCalldata = method.encode(args, encodingRules);
        const expectedOptimizedCalldata =
            '0x0b4d2e6a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035657874726120617267756d656e7420746f2070726576656e742065786163746c79206d61746368696e6720746865207475706c65730000000000000000000000';
        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
        // Validate decoding
        const decodedArgs = method.decode(optimizedCalldata, { structsAsObjects: false });
        expect(decodedArgs).to.be.deep.equal(args);
    });
    it('Duplicate Two-Dimensional Arrays', async () => {
        // Generate calldata
        const method = new AbiEncoder.Method(OptimizedAbis.duplicateTwoDimensionalArrays);
        const twoDimArray1 = [['Hello', 'World'], ['Foo', 'Bar', 'Zaa']];
        const twoDimArray2 = twoDimArray1;
        const args = [twoDimArray1, twoDimArray2];
        // Validata calldata
        const optimizedCalldata = method.encode(args, { shouldOptimize: false });
        const expectedOptimizedCalldata =
            '0x0d28c4f9000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003466f6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003426172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a61610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003466f6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003426172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a61610000000000000000000000000000000000000000000000000000000000';
        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
        // Validate decoding
        const decodedArgs = method.decode(optimizedCalldata, { structsAsObjects: false });
        expect(decodedArgs).to.be.deep.equal(args);
    });
    it('Duplicate Array, Nested within Separate Two-Dimensional Arrays', async () => {
        // Generate calldata
        const method = new AbiEncoder.Method(OptimizedAbis.duplicateTwoDimensionalArrays);
        const twoDimArray1 = [['Hello', 'World'], ['Foo']];
        const twoDimArray2 = [['Hello', 'World'], ['Bar']];
        const args = [twoDimArray1, twoDimArray2];
        // Validata calldata
        const optimizedCalldata = method.encode(args, encodingRules);
        const expectedOptimizedCalldata =
            '0x0d28c4f900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003466f6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000034261720000000000000000000000000000000000000000000000000000000000';
        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
        // Validate decoding
        const decodedArgs = method.decode(optimizedCalldata, { structsAsObjects: false });
        expect(decodedArgs).to.be.deep.equal(args);
    });
    it('Array Elements Duplicated as Tuple Fields', async () => {
        // Generate calldata
        const method = new AbiEncoder.Method(OptimizedAbis.arrayElementsDuplicatedAsTupleFields);
        // tslint:disable custom-no-magic-numbers
        const array = [100, 150, 200, 225];
        // tslint:enable custom-no-magic-numbers
        const tuple = [
            [new BigNumber(array[0])],
            [new BigNumber(array[1])],
            [new BigNumber(array[2])],
            [new BigNumber(array[3])],
        ];
        const args = [array, tuple];
        // Validata calldata
        const optimizedCalldata = method.encode(args, encodingRules);
        const expectedOptimizedCalldata =
            '0x5b5c78fd0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000e1';
        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
        // Validate decoding
        const decodedArgs = method.decode(optimizedCalldata, { structsAsObjects: false });
        expect(decodedArgs).to.be.deep.equal(args);
    });
    it('Array Elements Duplicated as Separate Parameter', async () => {
        // Generate calldata
        const method = new AbiEncoder.Method(OptimizedAbis.arrayElementsDuplicatedAsSeparateParameter);
        const array = ['Hello', 'Hello', 'Hello', 'World'];
        const str = 'Hello';
        const args = [array, str];
        // Validate calldata
        const optimizedCalldata = method.encode(args, encodingRules);
        const expectedOptimizedCalldata =
            '0xe0e0d34900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000';
        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
        // Validate decoding
        const decodedArgs = method.decode(optimizedCalldata, { structsAsObjects: false });
        expect(decodedArgs).to.be.deep.equal(args);
    });
});