@alephium/web3 1.4.0 → 1.5.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.
Files changed (106) hide show
  1. package/dist/alephium-web3.min.js +1 -1
  2. package/dist/alephium-web3.min.js.map +1 -1
  3. package/dist/src/address/address.js +5 -5
  4. package/dist/src/api/api-alephium.d.ts +1 -1
  5. package/dist/src/api/api-alephium.js +1 -1
  6. package/dist/src/codec/array-codec.d.ts +4 -12
  7. package/dist/src/codec/array-codec.js +15 -28
  8. package/dist/src/codec/asset-output-codec.d.ts +6 -11
  9. package/dist/src/codec/asset-output-codec.js +32 -71
  10. package/dist/src/codec/bigint-codec.d.ts +2 -1
  11. package/dist/src/codec/bigint-codec.js +14 -2
  12. package/dist/src/codec/bytestring-codec.d.ts +6 -11
  13. package/dist/src/codec/bytestring-codec.js +9 -23
  14. package/dist/src/codec/codec.d.ts +54 -5
  15. package/dist/src/codec/codec.js +112 -14
  16. package/dist/src/codec/compact-int-codec.d.ts +65 -44
  17. package/dist/src/codec/compact-int-codec.js +222 -204
  18. package/dist/src/codec/contract-codec.d.ts +5 -8
  19. package/dist/src/codec/contract-codec.js +15 -29
  20. package/dist/src/codec/contract-output-codec.d.ts +4 -10
  21. package/dist/src/codec/contract-output-codec.js +20 -40
  22. package/dist/src/codec/contract-output-ref-codec.d.ts +2 -8
  23. package/dist/src/codec/contract-output-ref-codec.js +7 -17
  24. package/dist/src/codec/either-codec.d.ts +8 -15
  25. package/dist/src/codec/either-codec.js +5 -46
  26. package/dist/src/codec/index.d.ts +4 -3
  27. package/dist/src/codec/index.js +7 -4
  28. package/dist/src/codec/input-codec.d.ts +4 -10
  29. package/dist/src/codec/input-codec.js +11 -46
  30. package/dist/src/codec/instr-codec.d.ts +633 -40
  31. package/dist/src/codec/instr-codec.js +1040 -434
  32. package/dist/src/codec/int-as-4bytes-codec.d.ts +7 -0
  33. package/dist/src/codec/{signed-int-codec.js → int-as-4bytes-codec.js} +6 -12
  34. package/dist/src/codec/lockup-script-codec.d.ts +23 -26
  35. package/dist/src/codec/lockup-script-codec.js +12 -58
  36. package/dist/src/codec/method-codec.d.ts +6 -18
  37. package/dist/src/codec/method-codec.js +20 -48
  38. package/dist/src/codec/option-codec.d.ts +8 -13
  39. package/dist/src/codec/option-codec.js +14 -32
  40. package/dist/src/codec/output-codec.d.ts +2 -2
  41. package/dist/src/codec/output-codec.js +1 -1
  42. package/dist/src/codec/reader.d.ts +8 -0
  43. package/dist/src/codec/reader.js +48 -0
  44. package/dist/src/codec/script-codec.d.ts +6 -14
  45. package/dist/src/codec/script-codec.js +6 -22
  46. package/dist/src/codec/signature-codec.d.ts +4 -12
  47. package/dist/src/codec/signature-codec.js +3 -15
  48. package/dist/src/codec/timestamp-codec.d.ts +8 -0
  49. package/dist/src/codec/timestamp-codec.js +39 -0
  50. package/dist/src/codec/token-codec.d.ts +3 -10
  51. package/dist/src/codec/token-codec.js +6 -24
  52. package/dist/src/codec/transaction-codec.d.ts +6 -11
  53. package/dist/src/codec/transaction-codec.js +24 -49
  54. package/dist/src/codec/unlock-script-codec.d.ts +25 -36
  55. package/dist/src/codec/unlock-script-codec.js +26 -147
  56. package/dist/src/codec/unsigned-tx-codec.d.ts +8 -14
  57. package/dist/src/codec/unsigned-tx-codec.js +24 -66
  58. package/dist/src/codec/val.d.ts +27 -0
  59. package/dist/src/codec/val.js +33 -0
  60. package/dist/src/contract/contract.js +6 -6
  61. package/dist/src/contract/index.d.ts +1 -0
  62. package/dist/src/contract/index.js +1 -0
  63. package/dist/src/contract/ralph.d.ts +0 -4
  64. package/dist/src/contract/ralph.js +50 -179
  65. package/dist/src/contract/script-simulator.d.ts +27 -0
  66. package/dist/src/contract/script-simulator.js +757 -0
  67. package/dist/src/exchange/exchange.js +1 -1
  68. package/package.json +3 -4
  69. package/src/address/address.ts +8 -8
  70. package/src/api/api-alephium.ts +1 -1
  71. package/src/codec/array-codec.ts +16 -34
  72. package/src/codec/asset-output-codec.ts +38 -83
  73. package/src/codec/bigint-codec.ts +16 -2
  74. package/src/codec/bytestring-codec.ts +10 -28
  75. package/src/codec/codec.ts +121 -15
  76. package/src/codec/compact-int-codec.ts +230 -207
  77. package/src/codec/contract-codec.ts +20 -33
  78. package/src/codec/contract-output-codec.ts +22 -48
  79. package/src/codec/contract-output-ref-codec.ts +6 -17
  80. package/src/codec/either-codec.ts +4 -53
  81. package/src/codec/index.ts +4 -3
  82. package/src/codec/input-codec.ts +14 -36
  83. package/src/codec/instr-codec.ts +1229 -455
  84. package/src/codec/{signed-int-codec.ts → int-as-4bytes-codec.ts} +6 -10
  85. package/src/codec/lockup-script-codec.ts +28 -76
  86. package/src/codec/method-codec.ts +23 -61
  87. package/src/codec/option-codec.ts +13 -36
  88. package/src/codec/output-codec.ts +2 -2
  89. package/src/codec/reader.ts +56 -0
  90. package/src/codec/script-codec.ts +9 -31
  91. package/src/codec/signature-codec.ts +3 -18
  92. package/src/codec/timestamp-codec.ts +42 -0
  93. package/src/codec/token-codec.ts +7 -26
  94. package/src/codec/transaction-codec.ts +29 -58
  95. package/src/codec/unlock-script-codec.ts +44 -171
  96. package/src/codec/unsigned-tx-codec.ts +34 -63
  97. package/src/codec/val.ts +40 -0
  98. package/src/contract/contract.ts +9 -13
  99. package/src/contract/index.ts +1 -0
  100. package/src/contract/ralph.ts +76 -172
  101. package/src/contract/script-simulator.ts +838 -0
  102. package/src/exchange/exchange.ts +1 -1
  103. package/dist/src/codec/long-codec.d.ts +0 -8
  104. package/dist/src/codec/long-codec.js +0 -55
  105. package/dist/src/codec/signed-int-codec.d.ts +0 -8
  106. package/src/codec/long-codec.ts +0 -58
@@ -0,0 +1,757 @@
1
+ "use strict";
2
+ /*
3
+ Copyright 2018 - 2022 The Alephium Authors
4
+ This file is part of the alephium project.
5
+
6
+ The library is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU Lesser General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ The library is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU Lesser General Public License for more details.
15
+
16
+ You should have received a copy of the GNU Lesser General Public License
17
+ along with the library. If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.ScriptSimulator = void 0;
21
+ const address_1 = require("../address");
22
+ const codec_1 = require("../codec");
23
+ const lockup_script_codec_1 = require("../codec/lockup-script-codec");
24
+ const constants_1 = require("../constants");
25
+ const utils_1 = require("../utils");
26
+ class ScriptSimulator {
27
+ // This function without errors is recommended for now as the simulator does not support all instructions
28
+ static extractContractCalls(unsignedTx) {
29
+ try {
30
+ return this.extractContractCallsWithErrors(unsignedTx);
31
+ }
32
+ catch (e) {
33
+ console.debug('Error extracting contract calls from script', e);
34
+ return [];
35
+ }
36
+ }
37
+ static extractContractCallsWithErrors(unsignedTx) {
38
+ const unsignedTxBytes = (0, utils_1.hexToBinUnsafe)(unsignedTx);
39
+ const decodedUnsignedTx = codec_1.unsignedTxCodec.decode(unsignedTxBytes);
40
+ const scriptOpt = decodedUnsignedTx.statefulScript;
41
+ switch (scriptOpt.kind) {
42
+ case 'Some': {
43
+ return this.extractContractCallsFromScript(scriptOpt.value);
44
+ }
45
+ case 'None': {
46
+ return [];
47
+ }
48
+ }
49
+ }
50
+ static extractContractCallsFromScript(script) {
51
+ const methods = script.methods;
52
+ if (methods.length === 0) {
53
+ return [];
54
+ }
55
+ const mainMethod = methods[0];
56
+ return this.extractContractCallsFromMainMethod(mainMethod);
57
+ }
58
+ static extractContractCallsFromMainMethod(mainMethod) {
59
+ const operandStack = new Stack();
60
+ const localVariables = new LocalVariables();
61
+ const contractCalls = [];
62
+ const callerAddress = {
63
+ kind: 'Address',
64
+ value: { kind: 'P2PKH', value: random32Bytes() }
65
+ };
66
+ const approved = new ApprovedAccumulator();
67
+ for (const instr of mainMethod.instrs) {
68
+ switch (instr.name) {
69
+ case 'ConstTrue':
70
+ operandStack.push({ kind: 'Bool', value: true });
71
+ break;
72
+ case 'ConstFalse':
73
+ operandStack.push({ kind: 'Bool', value: false });
74
+ break;
75
+ case 'I256Const0':
76
+ operandStack.push({ kind: 'I256', value: 0n });
77
+ break;
78
+ case 'I256Const1':
79
+ operandStack.push({ kind: 'I256', value: 1n });
80
+ break;
81
+ case 'I256Const2':
82
+ operandStack.push({ kind: 'I256', value: 2n });
83
+ break;
84
+ case 'I256Const3':
85
+ operandStack.push({ kind: 'I256', value: 3n });
86
+ break;
87
+ case 'I256Const4':
88
+ operandStack.push({ kind: 'I256', value: 4n });
89
+ break;
90
+ case 'I256Const5':
91
+ operandStack.push({ kind: 'I256', value: 5n });
92
+ break;
93
+ case 'I256ConstN1':
94
+ operandStack.push({ kind: 'I256', value: -1n });
95
+ break;
96
+ case 'I256Const':
97
+ operandStack.push({ kind: 'I256', value: instr.value });
98
+ break;
99
+ case 'U256Const0':
100
+ operandStack.push({ kind: 'U256', value: 0n });
101
+ break;
102
+ case 'U256Const1':
103
+ operandStack.push({ kind: 'U256', value: 1n });
104
+ break;
105
+ case 'U256Const2':
106
+ operandStack.push({ kind: 'U256', value: 2n });
107
+ break;
108
+ case 'U256Const3':
109
+ operandStack.push({ kind: 'U256', value: 3n });
110
+ break;
111
+ case 'U256Const4':
112
+ operandStack.push({ kind: 'U256', value: 4n });
113
+ break;
114
+ case 'U256Const5':
115
+ operandStack.push({ kind: 'U256', value: 5n });
116
+ break;
117
+ case 'U256Const':
118
+ operandStack.push({ kind: 'U256', value: instr.value });
119
+ break;
120
+ case 'BytesConst':
121
+ operandStack.push({ kind: 'ByteVec', value: instr.value });
122
+ break;
123
+ case 'AddressConst':
124
+ operandStack.push({ kind: 'Address', value: instr.value });
125
+ break;
126
+ case 'LoadLocal':
127
+ operandStack.push(localVariables.get(instr.index));
128
+ break;
129
+ case 'StoreLocal':
130
+ localVariables.set(instr.index, operandStack.pop());
131
+ break;
132
+ case 'Pop':
133
+ operandStack.pop();
134
+ break;
135
+ case 'Dup':
136
+ const val = operandStack.pop();
137
+ operandStack.push(val);
138
+ operandStack.push(val);
139
+ break;
140
+ case 'Swap':
141
+ const val1 = operandStack.pop();
142
+ const val2 = operandStack.pop();
143
+ operandStack.push(val1);
144
+ operandStack.push(val2);
145
+ break;
146
+ case 'BoolNot':
147
+ const bool = operandStack.popBool();
148
+ const result = unaryOp(bool, (x) => !x);
149
+ operandStack.push(result);
150
+ case 'BoolAnd': {
151
+ const bool1 = operandStack.popBool();
152
+ const bool2 = operandStack.popBool();
153
+ binaryOp(bool1, bool2, (x, y) => x && y, operandStack.push);
154
+ break;
155
+ }
156
+ case 'BoolOr': {
157
+ const bool1 = operandStack.popBool();
158
+ const bool2 = operandStack.popBool();
159
+ binaryOp(bool1, bool2, (x, y) => x || y, operandStack.push);
160
+ break;
161
+ }
162
+ case 'BoolEq': {
163
+ const bool1 = operandStack.popBool();
164
+ const bool2 = operandStack.popBool();
165
+ binaryOp(bool1, bool2, (x, y) => x === y, operandStack.push);
166
+ break;
167
+ }
168
+ case 'BoolNeq': {
169
+ const bool1 = operandStack.popBool();
170
+ const bool2 = operandStack.popBool();
171
+ binaryOp(bool1, bool2, (x, y) => x !== y, operandStack.push);
172
+ break;
173
+ }
174
+ case 'BoolToByteVec': {
175
+ const bool = operandStack.popBool();
176
+ if (bool.kind === 'Symbol-Bool') {
177
+ operandStack.push(bool);
178
+ }
179
+ else {
180
+ operandStack.push({ kind: 'ByteVec', value: codec_1.boolCodec.encode(bool.value) });
181
+ }
182
+ break;
183
+ }
184
+ case 'I256Add': {
185
+ // unsafe
186
+ const i256_2 = operandStack.popI256();
187
+ const i256_1 = operandStack.popI256();
188
+ binaryOp(i256_1, i256_2, (x, y) => x + y, operandStack.push);
189
+ break;
190
+ }
191
+ case 'I256Sub': {
192
+ // unsafe
193
+ const i256_2 = operandStack.popI256();
194
+ const i256_1 = operandStack.popI256();
195
+ binaryOp(i256_1, i256_2, (x, y) => x - y, operandStack.push);
196
+ break;
197
+ }
198
+ case 'I256Mul': {
199
+ // unsafe
200
+ const i256_2 = operandStack.popI256();
201
+ const i256_1 = operandStack.popI256();
202
+ binaryOp(i256_1, i256_2, (x, y) => x * y, operandStack.push);
203
+ break;
204
+ }
205
+ case 'I256Div': {
206
+ // unsafe
207
+ const i256_2 = operandStack.popI256();
208
+ const i256_1 = operandStack.popI256();
209
+ binaryOp(i256_1, i256_2, (x, y) => x / y, operandStack.push);
210
+ break;
211
+ }
212
+ case 'I256Eq': {
213
+ // unsafe
214
+ const i256_2 = operandStack.popI256();
215
+ const i256_1 = operandStack.popI256();
216
+ comparisonOp(i256_1, i256_2, (x, y) => x === y, operandStack.push);
217
+ break;
218
+ }
219
+ case 'I256Neq': {
220
+ // unsafe
221
+ const i256_2 = operandStack.popI256();
222
+ const i256_1 = operandStack.popI256();
223
+ comparisonOp(i256_1, i256_2, (x, y) => x !== y, operandStack.push);
224
+ break;
225
+ }
226
+ case 'I256Lt': {
227
+ // unsafe
228
+ const i256_2 = operandStack.popI256();
229
+ const i256_1 = operandStack.popI256();
230
+ comparisonOp(i256_1, i256_2, (x, y) => x < y, operandStack.push);
231
+ break;
232
+ }
233
+ case 'I256Le': {
234
+ // unsafe
235
+ const i256_2 = operandStack.popI256();
236
+ const i256_1 = operandStack.popI256();
237
+ comparisonOp(i256_1, i256_2, (x, y) => x <= y, operandStack.push);
238
+ break;
239
+ }
240
+ case 'I256Gt': {
241
+ // unsafe
242
+ const i256_2 = operandStack.popI256();
243
+ const i256_1 = operandStack.popI256();
244
+ comparisonOp(i256_1, i256_2, (x, y) => x > y, operandStack.push);
245
+ break;
246
+ }
247
+ case 'I256Ge': {
248
+ // unsafe
249
+ const i256_2 = operandStack.popI256();
250
+ const i256_1 = operandStack.popI256();
251
+ comparisonOp(i256_1, i256_2, (x, y) => x >= y, operandStack.push);
252
+ break;
253
+ }
254
+ case 'U256Add': {
255
+ // unsafe
256
+ const u256_2 = operandStack.popU256();
257
+ const u256_1 = operandStack.popU256();
258
+ binaryOp(u256_1, u256_2, (x, y) => x + y, operandStack.push);
259
+ break;
260
+ }
261
+ case 'U256Sub': {
262
+ // unsafe
263
+ const u256_2 = operandStack.popU256();
264
+ const u256_1 = operandStack.popU256();
265
+ binaryOp(u256_1, u256_2, (x, y) => x - y, operandStack.push);
266
+ break;
267
+ }
268
+ case 'U256Mul': {
269
+ // unsafe
270
+ const u256_2 = operandStack.popU256();
271
+ const u256_1 = operandStack.popU256();
272
+ binaryOp(u256_1, u256_2, (x, y) => x * y, operandStack.push);
273
+ break;
274
+ }
275
+ case 'U256Div': {
276
+ // unsafe
277
+ const u256_2 = operandStack.popU256();
278
+ const u256_1 = operandStack.popU256();
279
+ binaryOp(u256_1, u256_2, (x, y) => x / y, operandStack.push);
280
+ break;
281
+ }
282
+ case 'U256Eq': {
283
+ // unsafe
284
+ const u256_2 = operandStack.popU256();
285
+ const u256_1 = operandStack.popU256();
286
+ comparisonOp(u256_1, u256_2, (x, y) => x === y, operandStack.push);
287
+ break;
288
+ }
289
+ case 'U256Neq': {
290
+ // unsafe
291
+ const u256_2 = operandStack.popU256();
292
+ const u256_1 = operandStack.popU256();
293
+ comparisonOp(u256_1, u256_2, (x, y) => x !== y, operandStack.push);
294
+ break;
295
+ }
296
+ case 'U256Lt': {
297
+ // unsafe
298
+ const u256_2 = operandStack.popU256();
299
+ const u256_1 = operandStack.popU256();
300
+ comparisonOp(u256_1, u256_2, (x, y) => x < y, operandStack.push);
301
+ break;
302
+ }
303
+ case 'U256Le': {
304
+ // unsafe
305
+ const u256_2 = operandStack.popU256();
306
+ const u256_1 = operandStack.popU256();
307
+ comparisonOp(u256_1, u256_2, (x, y) => x <= y, operandStack.push);
308
+ break;
309
+ }
310
+ case 'U256Gt': {
311
+ // unsafe
312
+ const u256_2 = operandStack.popU256();
313
+ const u256_1 = operandStack.popU256();
314
+ comparisonOp(u256_1, u256_2, (x, y) => x > y, operandStack.push);
315
+ break;
316
+ }
317
+ case 'U256Ge': {
318
+ // unsafe
319
+ const u256_2 = operandStack.popU256();
320
+ const u256_1 = operandStack.popU256();
321
+ comparisonOp(u256_1, u256_2, (x, y) => x >= y, operandStack.push);
322
+ break;
323
+ }
324
+ case 'ByteVecEq': {
325
+ const byteVec1 = operandStack.popByteVec();
326
+ const byteVec2 = operandStack.popByteVec();
327
+ comparisonOp(byteVec1, byteVec2, (x, y) => arrayEquals(x, y), operandStack.push);
328
+ break;
329
+ }
330
+ case 'ByteVecNeq': {
331
+ const byteVec1 = operandStack.popByteVec();
332
+ const byteVec2 = operandStack.popByteVec();
333
+ comparisonOp(byteVec1, byteVec2, (x, y) => !arrayEquals(x, y), operandStack.push);
334
+ break;
335
+ }
336
+ case 'ByteVecSize': {
337
+ const byteVec = operandStack.popByteVec();
338
+ if (byteVec.kind === 'Symbol-ByteVec') {
339
+ operandStack.push({ kind: 'Symbol-U256', value: undefined });
340
+ }
341
+ else {
342
+ operandStack.push({ kind: 'U256', value: BigInt(byteVec.value.length) });
343
+ }
344
+ break;
345
+ }
346
+ case 'ByteVecConcat': {
347
+ const byteVec2 = operandStack.popByteVec();
348
+ const byteVec1 = operandStack.popByteVec();
349
+ binaryOp(byteVec1, byteVec2, (x, y) => new Uint8Array([...x, ...y]), operandStack.push);
350
+ break;
351
+ }
352
+ case 'ByteVecSlice': {
353
+ const end = operandStack.popU256();
354
+ const start = operandStack.popU256();
355
+ const byteVec = operandStack.popByteVec();
356
+ if (byteVec.kind === 'Symbol-ByteVec' || start.kind === 'Symbol-U256' || end.kind === 'Symbol-U256') {
357
+ operandStack.push({ kind: 'Symbol-ByteVec', value: undefined });
358
+ }
359
+ else {
360
+ operandStack.push({
361
+ kind: 'ByteVec',
362
+ value: byteVec.value.slice(Number(start.value), Number(end.value))
363
+ });
364
+ }
365
+ break;
366
+ }
367
+ case 'AddressEq': {
368
+ const address1 = operandStack.popAddress();
369
+ const address2 = operandStack.popAddress();
370
+ comparisonOp(address1, address2, (x, y) => arrayEquals(lockup_script_codec_1.lockupScriptCodec.encode(x), lockup_script_codec_1.lockupScriptCodec.encode(y)), operandStack.push);
371
+ break;
372
+ }
373
+ case 'AddressNeq': {
374
+ const address1 = operandStack.popAddress();
375
+ const address2 = operandStack.popAddress();
376
+ comparisonOp(address1, address2, (x, y) => !arrayEquals(lockup_script_codec_1.lockupScriptCodec.encode(x), lockup_script_codec_1.lockupScriptCodec.encode(y)), operandStack.push);
377
+ break;
378
+ }
379
+ case 'AddressToByteVec': {
380
+ const address = operandStack.popAddress();
381
+ if (address.kind === 'Symbol-Address') {
382
+ operandStack.push({ kind: 'Symbol-ByteVec', value: undefined });
383
+ }
384
+ else {
385
+ operandStack.push({ kind: 'ByteVec', value: lockup_script_codec_1.lockupScriptCodec.encode(address.value) });
386
+ }
387
+ break;
388
+ }
389
+ case 'Assert': {
390
+ const bool = operandStack.popBool();
391
+ if (!bool) {
392
+ throw new Error('Assertion failed');
393
+ }
394
+ break;
395
+ }
396
+ case 'Blake2b':
397
+ case 'Sha256':
398
+ case 'Sha3':
399
+ case 'Keccak256': {
400
+ dummyImplementation(instr.name);
401
+ operandStack.popByteVec();
402
+ operandStack.push({ kind: 'ByteVec', value: new Uint8Array(32) });
403
+ break;
404
+ }
405
+ case 'ByteVecToAddress': {
406
+ const byteVec = operandStack.popByteVec();
407
+ if (byteVec.kind === 'Symbol-ByteVec') {
408
+ operandStack.push({ kind: 'Symbol-Address', value: undefined });
409
+ }
410
+ else {
411
+ operandStack.push({ kind: 'Address', value: lockup_script_codec_1.lockupScriptCodec.decode(byteVec.value) });
412
+ }
413
+ break;
414
+ }
415
+ case 'Zeros': {
416
+ const size = operandStack.popU256();
417
+ if (size.kind === 'Symbol-U256') {
418
+ operandStack.push({ kind: 'Symbol-ByteVec', value: undefined });
419
+ }
420
+ else {
421
+ if (size.value > 4096) {
422
+ throw new Error('Zeros size is too large');
423
+ }
424
+ operandStack.push({ kind: 'ByteVec', value: new Uint8Array(Number(size.value)) });
425
+ }
426
+ break;
427
+ }
428
+ case 'U256To1Byte':
429
+ case 'U256To2Byte':
430
+ case 'U256To4Byte':
431
+ case 'U256To8Byte':
432
+ case 'U256To16Byte':
433
+ case 'U256To32Byte': {
434
+ dummyImplementation(instr.name);
435
+ operandStack.popU256();
436
+ operandStack.push({ kind: 'Symbol-ByteVec', value: undefined });
437
+ break;
438
+ }
439
+ case 'U256From1Byte':
440
+ case 'U256From2Byte':
441
+ case 'U256From4Byte':
442
+ case 'U256From8Byte':
443
+ case 'U256From16Byte':
444
+ case 'U256From32Byte': {
445
+ dummyImplementation(instr.name);
446
+ operandStack.popByteVec();
447
+ operandStack.push({ kind: 'Symbol-U256', value: undefined });
448
+ break;
449
+ }
450
+ case 'CallExternal':
451
+ case 'CallExternalBySelector': {
452
+ const contractId = operandStack.popByteVec();
453
+ const returnLength = operandStack.popU256(); // method return length
454
+ operandStack.popU256(); // method args length
455
+ if (contractId.kind !== 'Symbol-ByteVec') {
456
+ contractCalls.push({
457
+ contractAddress: (0, address_1.addressFromContractId)((0, utils_1.binToHex)(contractId.value)),
458
+ approvedAttoAlphAmount: approved.getApprovedAttoAlph(),
459
+ approvedTokens: approved.getApprovedTokens()
460
+ });
461
+ }
462
+ approved.reset();
463
+ if (returnLength.kind !== 'Symbol-U256') {
464
+ for (let i = 0; i < returnLength.value; i++) {
465
+ operandStack.push({ kind: 'Symbol-Any', value: undefined });
466
+ }
467
+ }
468
+ break;
469
+ }
470
+ case 'ContractIdToAddress': {
471
+ const contractId = operandStack.popByteVec();
472
+ if (contractId.kind === 'Symbol-ByteVec') {
473
+ operandStack.push({ kind: 'Symbol-Address', value: undefined });
474
+ }
475
+ else {
476
+ operandStack.push({ kind: 'Address', value: { kind: 'P2C', value: contractId.value } });
477
+ }
478
+ break;
479
+ }
480
+ case 'LoadLocalByIndex': {
481
+ const index = operandStack.popU256();
482
+ if (index.kind === 'Symbol-U256') {
483
+ throw new Error('LoadLocalByIndex index is a symbol');
484
+ }
485
+ else {
486
+ operandStack.push(localVariables.get(Number(index.value)));
487
+ }
488
+ break;
489
+ }
490
+ case 'StoreLocalByIndex': {
491
+ const index = operandStack.popU256();
492
+ if (index.kind === 'Symbol-U256') {
493
+ throw new Error('StoreLocalByIndex index is a symbol');
494
+ }
495
+ else {
496
+ localVariables.set(Number(index.value), operandStack.pop());
497
+ }
498
+ break;
499
+ }
500
+ case 'CallerAddress': {
501
+ operandStack.push(callerAddress);
502
+ break;
503
+ }
504
+ case 'ApproveAlph': {
505
+ const amount = operandStack.popU256(); // amount
506
+ const spender = operandStack.popAddress(); // spender
507
+ if (spender.kind.startsWith('Symbol')) {
508
+ approved.setUnknown(); // The spender might be the caller
509
+ }
510
+ else if (spender === callerAddress) {
511
+ approved.addApprovedAttoAlph(amount);
512
+ }
513
+ break;
514
+ }
515
+ case 'ApproveToken': {
516
+ const amount = operandStack.popU256(); // amount
517
+ const tokenId = operandStack.popByteVec(); // token
518
+ const spender = operandStack.popAddress(); // spender
519
+ if (spender.kind.startsWith('Symbol')) {
520
+ approved.setUnknown(); // The spender might be the caller
521
+ }
522
+ else if (spender === callerAddress) {
523
+ approved.addApprovedToken(tokenId, amount);
524
+ }
525
+ break;
526
+ }
527
+ case 'CreateContractAndTransferToken': {
528
+ operandStack.popAddress(); // token owner
529
+ }
530
+ case 'CreateContractWithToken': {
531
+ operandStack.popU256(); // token amount
532
+ }
533
+ case 'CreateContract': {
534
+ operandStack.popByteVec(); // mutable fields
535
+ operandStack.popByteVec(); // immutable fields
536
+ operandStack.popByteVec(); // contract code
537
+ operandStack.push({ kind: 'Symbol-ByteVec', value: undefined }); // new contract id
538
+ break;
539
+ }
540
+ case 'TransferAlph': {
541
+ operandStack.popU256(); // amount
542
+ operandStack.popAddress(); // recipient
543
+ operandStack.popAddress(); // sender
544
+ break;
545
+ }
546
+ case 'TransferToken': {
547
+ operandStack.popU256(); // amount
548
+ operandStack.popByteVec(); // token
549
+ operandStack.popAddress(); // recipient
550
+ operandStack.popAddress(); // sender
551
+ break;
552
+ }
553
+ default:
554
+ unimplemented(instr.name);
555
+ break;
556
+ }
557
+ }
558
+ return contractCalls;
559
+ }
560
+ }
561
+ exports.ScriptSimulator = ScriptSimulator;
562
+ function unaryOp(x, op) {
563
+ if (x.kind.startsWith('Symbol')) {
564
+ return x;
565
+ }
566
+ else {
567
+ return { kind: x.kind, value: op(x.value) };
568
+ }
569
+ }
570
+ function binaryOp(x, y, op, push) {
571
+ const result = x.kind.startsWith('Symbol')
572
+ ? x
573
+ : y.kind.startsWith('Symbol')
574
+ ? y
575
+ : { kind: x.kind, value: op(x.value, y.value) };
576
+ push(result);
577
+ }
578
+ function comparisonOp(x, y, op, push) {
579
+ const result = x.kind.startsWith('Symbol') || y.kind.startsWith('Symbol')
580
+ ? { kind: 'Symbol-Bool', value: undefined }
581
+ : { kind: 'Bool', value: op(x.value, y.value) };
582
+ push(result);
583
+ }
584
+ // implement arrayEquals
585
+ function arrayEquals(x, y) {
586
+ return x.length === y.length && x.every((value, index) => value === y[`${index}`]);
587
+ }
588
+ // generate 32 bytes array with random numbers
589
+ function random32Bytes() {
590
+ const result = new Uint8Array(32);
591
+ for (let i = 0; i < 32; i++) {
592
+ result[`${i}`] = Math.floor(Math.random() * 256);
593
+ }
594
+ return result;
595
+ }
596
+ class Stack {
597
+ constructor() {
598
+ this.stack = [];
599
+ this.push = (val) => {
600
+ this.stack.push(val);
601
+ };
602
+ // TODO
603
+ }
604
+ pop() {
605
+ const result = this.stack.pop();
606
+ if (result === undefined) {
607
+ throw new Error('Stack is empty');
608
+ }
609
+ return result;
610
+ }
611
+ size() {
612
+ return this.stack.length;
613
+ }
614
+ checkedResult(result, expected) {
615
+ if (result.kind.startsWith('Symbol')) {
616
+ if (result.kind !== `Symbol-${expected}`) {
617
+ throw new Error(`Expected a ${expected} value on the stack`);
618
+ }
619
+ return result;
620
+ }
621
+ if (result.kind !== expected) {
622
+ throw new Error(`Expected a ${expected} value on the stack`);
623
+ }
624
+ return result;
625
+ }
626
+ popBool() {
627
+ const result = this.pop();
628
+ return this.checkedResult(result, 'Bool');
629
+ }
630
+ popI256() {
631
+ const result = this.pop();
632
+ return this.checkedResult(result, 'I256');
633
+ }
634
+ popU256() {
635
+ const result = this.pop();
636
+ return this.checkedResult(result, 'U256');
637
+ }
638
+ popByteVec() {
639
+ const result = this.pop();
640
+ return this.checkedResult(result, 'ByteVec');
641
+ }
642
+ popAddress() {
643
+ const result = this.pop();
644
+ return this.checkedResult(result, 'Address');
645
+ }
646
+ }
647
+ class LocalVariables {
648
+ constructor() {
649
+ this.locals = [];
650
+ // TODO
651
+ }
652
+ get(index) {
653
+ const result = this.locals[`${index}`];
654
+ if (result === undefined) {
655
+ throw new Error(`Local variable at index ${index} is not set`);
656
+ }
657
+ return result;
658
+ }
659
+ set(index, val) {
660
+ this.locals[`${index}`] = val;
661
+ }
662
+ checkedResult(result, index, expected) {
663
+ if (result.kind.startsWith('Symbol')) {
664
+ if (result.kind !== `Symbol-${expected}`) {
665
+ throw new Error(`Local variable at index ${index} is not a ${expected}`);
666
+ }
667
+ return result;
668
+ }
669
+ if (result.kind !== expected) {
670
+ throw new Error(`Local variable at index ${index} is not a ${expected}`);
671
+ }
672
+ return result;
673
+ }
674
+ getBool(index) {
675
+ const result = this.get(index);
676
+ return this.checkedResult(result, index, 'Bool');
677
+ }
678
+ getI256(index) {
679
+ const result = this.get(index);
680
+ return this.checkedResult(result, index, 'I256');
681
+ }
682
+ getU256(index) {
683
+ const result = this.get(index);
684
+ return this.checkedResult(result, index, 'U256');
685
+ }
686
+ getByteVec(index) {
687
+ const result = this.get(index);
688
+ return this.checkedResult(result, index, 'ByteVec');
689
+ }
690
+ getAddress(index) {
691
+ const result = this.get(index);
692
+ return this.checkedResult(result, index, 'Address');
693
+ }
694
+ }
695
+ function unimplemented(instrName) {
696
+ throw new Error(`Unimplemented instruction: ${instrName}`);
697
+ }
698
+ function dummyImplementation(instrName) {
699
+ console.debug(`Dummy implementation for instruction: ${instrName}`);
700
+ }
701
+ class ApprovedAccumulator {
702
+ constructor() {
703
+ this.approvedTokens = [];
704
+ this.reset();
705
+ }
706
+ reset() {
707
+ this.approvedTokens = [{ id: constants_1.ALPH_TOKEN_ID, amount: 0n }];
708
+ }
709
+ setUnknown() {
710
+ this.approvedTokens = 'unknown';
711
+ }
712
+ getApprovedAttoAlph() {
713
+ if (this.approvedTokens === 'unknown') {
714
+ return 'unknown';
715
+ }
716
+ const approvedAttoAlph = this.approvedTokens[0].amount;
717
+ return approvedAttoAlph === 'unknown' ? 'unknown' : approvedAttoAlph === 0n ? undefined : approvedAttoAlph;
718
+ }
719
+ getApprovedTokens() {
720
+ if (this.approvedTokens === 'unknown') {
721
+ return 'unknown';
722
+ }
723
+ const allTokens = this.approvedTokens.slice(1);
724
+ return allTokens.length === 0 ? undefined : allTokens;
725
+ }
726
+ addApprovedAttoAlph(amount) {
727
+ this.addApprovedToken({ kind: 'ByteVec', value: (0, utils_1.hexToBinUnsafe)(constants_1.ALPH_TOKEN_ID) }, amount);
728
+ }
729
+ addApprovedToken(tokenId, amount) {
730
+ if (this.approvedTokens === 'unknown') {
731
+ return;
732
+ }
733
+ if (tokenId.kind === 'Symbol-ByteVec') {
734
+ this.approvedTokens = 'unknown';
735
+ return;
736
+ }
737
+ const tokenIndex = this.approvedTokens.findIndex((token) => arrayEquals((0, utils_1.hexToBinUnsafe)(token.id), tokenId.value));
738
+ if (tokenIndex === -1) {
739
+ this.approvedTokens.push({
740
+ id: (0, utils_1.binToHex)(tokenId.value),
741
+ amount: amount.kind === 'Symbol-U256' ? 'unknown' : amount.value
742
+ });
743
+ }
744
+ else {
745
+ const approved = this.approvedTokens[`${tokenIndex}`];
746
+ if (approved.amount === 'unknown') {
747
+ return;
748
+ }
749
+ if (amount.kind === 'Symbol-U256') {
750
+ approved.amount = 'unknown';
751
+ }
752
+ else {
753
+ approved.amount += amount.value;
754
+ }
755
+ }
756
+ }
757
+ }