gen-typescript-from-tolk-dev 0.1.0 → 0.2.1
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/README.md +33 -29
- package/dist/abi-types.d.ts +169 -0
- package/dist/abi-types.js +8 -0
- package/dist/abi.d.ts +54 -0
- package/dist/abi.js +13 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +83 -0
- package/dist/codegen-ctx.d.ts +66 -0
- package/dist/codegen-ctx.js +108 -0
- package/dist/emit-field-defs.d.ts +5 -0
- package/dist/emit-field-defs.js +61 -0
- package/dist/emit-pack-unpack.d.ts +9 -0
- package/dist/emit-pack-unpack.js +296 -0
- package/dist/emit-stack-rw.d.ts +4 -0
- package/dist/emit-stack-rw.js +232 -0
- package/dist/emit-ts-types.d.ts +6 -0
- package/dist/emit-ts-types.js +74 -0
- package/dist/formatting.d.ts +15 -0
- package/{src/formatting.ts → dist/formatting.js} +26 -28
- package/dist/generate-ts-wrappers.d.ts +7 -0
- package/dist/generate-ts-wrappers.js +444 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +11 -0
- package/dist/out-template.generated.d.ts +1 -0
- package/dist/out-template.generated.js +6 -0
- package/dist/types-kernel.d.ts +10 -0
- package/dist/types-kernel.js +212 -0
- package/dist/unsupported-errors.d.ts +28 -0
- package/{src/unsupported-errors.ts → dist/unsupported-errors.js} +33 -39
- package/package.json +56 -30
- package/bin/generator.js +0 -15
- package/src/abi-types.ts +0 -157
- package/src/abi.ts +0 -132
- package/src/cli-generate-from-abi-json.ts +0 -21
- package/src/codegen-ctx.ts +0 -115
- package/src/dynamic-ctx.ts +0 -55
- package/src/dynamic-debug-print.ts +0 -191
- package/src/dynamic-get-methods.ts +0 -454
- package/src/dynamic-serialization.ts +0 -430
- package/src/dynamic-validation.ts +0 -55
- package/src/emit-field-defs.ts +0 -60
- package/src/emit-pack-unpack.ts +0 -280
- package/src/emit-stack-rw.ts +0 -239
- package/src/emit-ts-types.ts +0 -66
- package/src/generate-from-abi-json.ts +0 -22
- package/src/generate-ts-wrappers.ts +0 -477
- package/src/out-template.ts +0 -514
- package/src/tolk-to-abi.ts +0 -5
- package/src/types-kernel.ts +0 -215
- package/tsconfig.json +0 -13
|
@@ -1,454 +0,0 @@
|
|
|
1
|
-
import * as c from '@ton/core'; // todo is it peer dependency?
|
|
2
|
-
import { DynamicCtx } from './dynamic-ctx';
|
|
3
|
-
import { CantCallGetMethodDynamic, NotSupportedTypeOnStack } from './unsupported-errors'
|
|
4
|
-
import { Ty } from './abi-types'
|
|
5
|
-
import { createTonCoreDictionaryKey, createTonCoreDictionaryValue, dynamicPack, dynamicUnpack } from './dynamic-serialization'
|
|
6
|
-
import { calcWidthOnStack, createLabelsForUnion, instantiateGenerics } from './types-kernel'
|
|
7
|
-
import { checkIsArray, checkIsBoolean, checkIsNumber, checkIsObject, checkIsObjectWithProperty, throwInvalidInput } from './dynamic-validation'
|
|
8
|
-
|
|
9
|
-
/*
|
|
10
|
-
Dynamic calling GET methods works without generating TypeScript wrappers.
|
|
11
|
-
Just given an ABI, pack any JS input to TVM stack (TupleItem[]), and unpack back.
|
|
12
|
-
Its purpose is orthogonal to wrappers:
|
|
13
|
-
- wrappers — for manual development
|
|
14
|
-
(write tests, deployment, and other manual interactions with your contract)
|
|
15
|
-
- dynamic contract getters — for tolk-js, explorers, etc.
|
|
16
|
-
(pass some data from auto-generated UI and invoke getters given its ABI)
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
type LoadCallback<T> = (s: c.Slice) => T
|
|
20
|
-
|
|
21
|
-
export class StackReader {
|
|
22
|
-
constructor(private tuple: c.TupleItem[]) {
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
static fromGetMethod(expectedN: number, getMethodResult: { stack: c.TupleReader }): StackReader {
|
|
26
|
-
let tuple = [] as c.TupleItem[];
|
|
27
|
-
while (getMethodResult.stack.remaining) {
|
|
28
|
-
tuple.push(getMethodResult.stack.pop());
|
|
29
|
-
}
|
|
30
|
-
if (tuple.length !== expectedN) {
|
|
31
|
-
throw new Error(`expected ${expectedN} stack width, got ${tuple.length}`);
|
|
32
|
-
}
|
|
33
|
-
return new StackReader(tuple);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
private popExpecting<ItemT>(itemType: string): ItemT {
|
|
37
|
-
const item = this.tuple.shift();
|
|
38
|
-
if (item?.type !== itemType) {
|
|
39
|
-
throw new Error(`not '${itemType}' on a stack`);
|
|
40
|
-
}
|
|
41
|
-
return item as ItemT;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
readBigInt(): bigint {
|
|
45
|
-
return this.popExpecting<c.TupleItemInt>('int').value;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
readBoolean(): boolean {
|
|
49
|
-
return this.popExpecting<c.TupleItemInt>('int').value !== 0n;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
readCell(): c.Cell {
|
|
53
|
-
return this.popExpecting<c.TupleItemCell>('cell').cell;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
readSlice(): c.Slice {
|
|
57
|
-
return this.popExpecting<c.TupleItemSlice>('slice').cell.beginParse();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
readBuilder(): c.Builder {
|
|
61
|
-
return c.beginCell().storeSlice(this.popExpecting<c.TupleItemBuilder>('builder').cell.beginParse());
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
readUnknown(): c.TupleItem {
|
|
65
|
-
// `unknown` from Tolk is left as a raw tuple item
|
|
66
|
-
return this.tuple.shift()!;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
readArrayOf<T>(readFn_T: (nestedReader: StackReader) => T): T[] {
|
|
70
|
-
const subItems = this.popExpecting<c.Tuple>('tuple').items;
|
|
71
|
-
const subReader = new StackReader(subItems);
|
|
72
|
-
// array len N => N subItems => N calls to readFn_T
|
|
73
|
-
return [...subItems].map(_ => readFn_T(subReader))
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
readLispListOf<T>(readFn_T: (nestedReader: StackReader) => T): T[] {
|
|
77
|
-
// read `[1 [2 [3 null]]]` to `[1 2 3]`
|
|
78
|
-
let pairReader: StackReader = this;
|
|
79
|
-
let outArr = [] as T[];
|
|
80
|
-
while (true) {
|
|
81
|
-
if (pairReader.tuple[0].type === 'null') {
|
|
82
|
-
pairReader.tuple.shift();
|
|
83
|
-
break;
|
|
84
|
-
}
|
|
85
|
-
let headAndTail = pairReader.popExpecting<c.Tuple>('tuple').items;
|
|
86
|
-
if (headAndTail.length !== 2) {
|
|
87
|
-
throw new Error(`malformed lisp_list, expected 2 stack width, got ${headAndTail.length}`);
|
|
88
|
-
}
|
|
89
|
-
pairReader = new StackReader(headAndTail);
|
|
90
|
-
outArr.push(readFn_T(pairReader));
|
|
91
|
-
}
|
|
92
|
-
return outArr;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
readSnakeString(): string {
|
|
96
|
-
return this.readCell().beginParse().loadStringTail();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
readTuple<T>(expectedN: number, readFn_T: (nestedReader: StackReader) => T): T {
|
|
100
|
-
const subItems = this.popExpecting<c.Tuple>('tuple').items;
|
|
101
|
-
if (subItems.length !== expectedN) {
|
|
102
|
-
throw new Error(`expected ${expectedN} items in a tuple, got ${subItems.length}`);
|
|
103
|
-
}
|
|
104
|
-
return readFn_T(new StackReader(subItems));
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
readNullLiteral(): null {
|
|
108
|
-
this.popExpecting<c.TupleItemNull>('null');
|
|
109
|
-
return null;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
readNullable<T>(readFn_T: (r: StackReader) => T): T | null {
|
|
113
|
-
if (this.tuple[0].type === 'null') {
|
|
114
|
-
this.tuple.shift();
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
return readFn_T(this);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
readWideNullable<T>(stackW: number, readFn_T: (r: StackReader) => T): T | null {
|
|
121
|
-
const slotTypeId = this.tuple[stackW - 1];
|
|
122
|
-
if (slotTypeId?.type !== 'int') {
|
|
123
|
-
throw new Error(`not 'int' on a stack`);
|
|
124
|
-
}
|
|
125
|
-
if (slotTypeId.value === 0n) {
|
|
126
|
-
this.tuple = this.tuple.slice(stackW);
|
|
127
|
-
return null;
|
|
128
|
-
}
|
|
129
|
-
const valueT = readFn_T(this);
|
|
130
|
-
this.tuple.shift();
|
|
131
|
-
return valueT;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
readUnionType<T>(stackW: number, infoForTypeId: Record<number, [number, string | null, (r: StackReader) => any]>): T {
|
|
135
|
-
const slotTypeId = this.tuple[stackW - 1];
|
|
136
|
-
if (slotTypeId?.type !== 'int') {
|
|
137
|
-
throw new Error(`not 'int' on a stack`);
|
|
138
|
-
}
|
|
139
|
-
const info = infoForTypeId[Number(slotTypeId.value)]; // [stackWidth, label, readFn_T{i}]
|
|
140
|
-
if (info == null) {
|
|
141
|
-
throw new Error(`unexpected UTag=${slotTypeId.value}`);
|
|
142
|
-
}
|
|
143
|
-
const label = info[1];
|
|
144
|
-
this.tuple = this.tuple.slice(stackW - 1 - info[0]);
|
|
145
|
-
const valueT = info[2](this);
|
|
146
|
-
this.tuple.shift();
|
|
147
|
-
return label == null ? valueT : { $: label, value: valueT } as T;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
readCellRef<T>(loadFn_T: LoadCallback<T>): { ref: T } {
|
|
151
|
-
return { ref: loadFn_T(this.readCell().beginParse()) };
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
readDictionary<K extends c.DictionaryKeyTypes, V>(keySerializer: c.DictionaryKey<K>, valueSerializer: c.DictionaryValue<V>): c.Dictionary<K, V> {
|
|
155
|
-
if (this.tuple[0].type === 'null') {
|
|
156
|
-
this.tuple.shift();
|
|
157
|
-
return c.Dictionary.empty<K, V>(keySerializer, valueSerializer);
|
|
158
|
-
}
|
|
159
|
-
return c.Dictionary.loadDirect<K, V>(keySerializer, valueSerializer, this.readCell());
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// When constructing a TVM tuple (when calling a get method), we often need to make cells.
|
|
164
|
-
// For example, given an address, we should result in { type: 'slice', cell: (serialized address) }
|
|
165
|
-
function makeCell(ctx: DynamicCtx, fieldPath: string, ty: Ty, v: any): c.Cell {
|
|
166
|
-
let b = c.beginCell();
|
|
167
|
-
dynamicPack(ctx, fieldPath, ty, v, b); // does validation, throws if invalid, e.g. number instead of address
|
|
168
|
-
return b.endCell();
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Pack value `v` of type `ty` to a TVM tuple, as an argument of a get method.
|
|
172
|
-
// Parameter `fieldPath` is used for error messages only, e.g. when provided invalid input.
|
|
173
|
-
function dynamicConstruct(ctx: DynamicCtx, fieldPath: string, ty: Ty, v: any, tupleIfW: boolean = false): c.TupleItem[] {
|
|
174
|
-
if (tupleIfW) { // inside `array<T>` or `[T, ...]`, if T is non-primitive, it's a sub-tuple
|
|
175
|
-
if (calcWidthOnStack(ctx.symbols, ty) === 1) {
|
|
176
|
-
return dynamicConstruct(ctx, fieldPath, ty, v, false);
|
|
177
|
-
}
|
|
178
|
-
return [{ type: 'tuple', items: dynamicConstruct(ctx, fieldPath, ty, v, false) }];
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
switch (ty.kind) {
|
|
182
|
-
case 'int':
|
|
183
|
-
case 'intN':
|
|
184
|
-
case 'uintN':
|
|
185
|
-
case 'varintN':
|
|
186
|
-
case 'varuintN':
|
|
187
|
-
case 'coins': {
|
|
188
|
-
checkIsNumber(fieldPath, ty, v);
|
|
189
|
-
return [{ type: 'int', value: v }];
|
|
190
|
-
}
|
|
191
|
-
case 'bool': {
|
|
192
|
-
checkIsBoolean(fieldPath, ty, v);
|
|
193
|
-
return [{ type: 'int', value: (v ? -1n : 0n) }];
|
|
194
|
-
}
|
|
195
|
-
case 'cell': {
|
|
196
|
-
checkIsObject(fieldPath, ty, v);
|
|
197
|
-
return [{ type: 'cell', cell: v }];
|
|
198
|
-
}
|
|
199
|
-
case 'builder': {
|
|
200
|
-
// the call to `makeCell()`, automatically does validation of input (of v)
|
|
201
|
-
return [{ type: 'builder', cell: makeCell(ctx, fieldPath, ty, v) }];
|
|
202
|
-
}
|
|
203
|
-
case 'slice':
|
|
204
|
-
case 'remaining':
|
|
205
|
-
case 'address':
|
|
206
|
-
case 'addressExt':
|
|
207
|
-
case 'addressAny':
|
|
208
|
-
case 'bitsN': {
|
|
209
|
-
return [{ type: 'slice', cell: makeCell(ctx, fieldPath, ty, v) }];
|
|
210
|
-
}
|
|
211
|
-
case 'string': {
|
|
212
|
-
return [{ type: 'cell', cell: makeCell(ctx, fieldPath, ty, v) }];
|
|
213
|
-
}
|
|
214
|
-
case 'addressOpt': {
|
|
215
|
-
if (v === null) {
|
|
216
|
-
return [{ type: 'null' }];
|
|
217
|
-
}
|
|
218
|
-
return [{ type: 'slice', cell: makeCell(ctx, fieldPath, ty, v) }];
|
|
219
|
-
}
|
|
220
|
-
case 'nullLiteral': {
|
|
221
|
-
return [{ type: 'null' }];
|
|
222
|
-
}
|
|
223
|
-
case 'callable': {
|
|
224
|
-
throw new NotSupportedTypeOnStack(ty, fieldPath);
|
|
225
|
-
}
|
|
226
|
-
case 'void': {
|
|
227
|
-
return []
|
|
228
|
-
}
|
|
229
|
-
case 'unknown': {
|
|
230
|
-
checkIsObjectWithProperty(fieldPath, ty, v, 'type'); // c.TupleItem has 'type'
|
|
231
|
-
return [v as c.TupleItem];
|
|
232
|
-
}
|
|
233
|
-
case 'nullable': {
|
|
234
|
-
if (ty.stackTypeId) {
|
|
235
|
-
let result = [] as c.TupleItem[];
|
|
236
|
-
if (v === null) {
|
|
237
|
-
for (let i = 0; i < ty.stackWidth! - 1; ++i) {
|
|
238
|
-
result.push({ type: 'null' });
|
|
239
|
-
}
|
|
240
|
-
result.push({ type: 'int', value: 0n });
|
|
241
|
-
} else {
|
|
242
|
-
result = dynamicConstruct(ctx, fieldPath, ty.inner, v);
|
|
243
|
-
result.push({ type: 'int', value: BigInt(ty.stackTypeId) });
|
|
244
|
-
}
|
|
245
|
-
return result;
|
|
246
|
-
}
|
|
247
|
-
if (v === null) {
|
|
248
|
-
return [{ type: 'null' }];
|
|
249
|
-
}
|
|
250
|
-
return dynamicConstruct(ctx, fieldPath, ty.inner, v);
|
|
251
|
-
}
|
|
252
|
-
case 'cellOf': {
|
|
253
|
-
checkIsObjectWithProperty(fieldPath, ty, v, 'ref');
|
|
254
|
-
return [{ type: 'cell', cell: makeCell(ctx, fieldPath, ty.inner, v.ref) }];
|
|
255
|
-
}
|
|
256
|
-
case 'arrayOf': {
|
|
257
|
-
checkIsArray(fieldPath, ty, v);
|
|
258
|
-
return [{ type: 'tuple', items: v.map((ith: any) => dynamicConstruct(ctx, 'ith', ty.inner, ith, true)[0]) }];
|
|
259
|
-
}
|
|
260
|
-
case 'lispListOf': {
|
|
261
|
-
checkIsArray(fieldPath, ty, v);
|
|
262
|
-
return [v.reduceRight((tail: c.TupleItem, head: any) => (
|
|
263
|
-
{ type: 'tuple', items: [dynamicConstruct(ctx, 'head', ty.inner, head, true)[0], tail] }
|
|
264
|
-
), { type: 'null' })];
|
|
265
|
-
}
|
|
266
|
-
case 'tensor': {
|
|
267
|
-
checkIsArray(fieldPath, ty, v, ty.items.length);
|
|
268
|
-
return v.flatMap((item: any, idx: number) => dynamicConstruct(ctx, `${fieldPath}[${idx}]`, ty.items[idx], item));
|
|
269
|
-
}
|
|
270
|
-
case 'shapedTuple': {
|
|
271
|
-
checkIsArray(fieldPath, ty, v, ty.items.length);
|
|
272
|
-
return [{ type: 'tuple', items: v.map((ith: any, idx: number) => dynamicConstruct(ctx, `${fieldPath}[${idx}]`, ty.items[idx], ith, true)[0]) }];
|
|
273
|
-
}
|
|
274
|
-
case 'mapKV': {
|
|
275
|
-
checkIsObject(fieldPath, ty, v);
|
|
276
|
-
if (v.size === 0) {
|
|
277
|
-
return [{ type: 'null' }];
|
|
278
|
-
}
|
|
279
|
-
let dictKey = createTonCoreDictionaryKey(fieldPath, ty.k);
|
|
280
|
-
let dictValue = createTonCoreDictionaryValue(ctx, fieldPath, ty.v);
|
|
281
|
-
return [{ type: 'cell', cell: c.beginCell().storeDictDirect(v, dictKey, dictValue).endCell() }];
|
|
282
|
-
}
|
|
283
|
-
case 'EnumRef': {
|
|
284
|
-
checkIsNumber(fieldPath, ty, v);
|
|
285
|
-
return [{ type: 'int', value: v }];
|
|
286
|
-
}
|
|
287
|
-
case 'StructRef': {
|
|
288
|
-
checkIsObject(fieldPath, ty, v);
|
|
289
|
-
let structRef = ctx.symbols.getStruct(ty.structName);
|
|
290
|
-
return structRef.fields.flatMap(f => {
|
|
291
|
-
const fTy = ty.typeArgs ? instantiateGenerics(f.ty, structRef.typeParams, ty.typeArgs) : f.ty;
|
|
292
|
-
return dynamicConstruct(ctx, `${fieldPath}.${f.name}`, fTy, v[f.name]);
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
case 'AliasRef': {
|
|
296
|
-
let aliasRef = ctx.symbols.getAlias(ty.aliasName);
|
|
297
|
-
const targetTy = ty.typeArgs ? instantiateGenerics(aliasRef.targetTy, aliasRef.typeParams, ty.typeArgs) : aliasRef.targetTy;
|
|
298
|
-
return dynamicConstruct(ctx, fieldPath, targetTy, v);
|
|
299
|
-
}
|
|
300
|
-
case 'union': {
|
|
301
|
-
const variants = createLabelsForUnion(ctx.symbols, ty.variants);
|
|
302
|
-
const hasNull = variants.find(v => v.variantTy.kind === 'nullLiteral');
|
|
303
|
-
let result = [] as c.TupleItem[];
|
|
304
|
-
if (hasNull && v === null) {
|
|
305
|
-
for (let i = 0; i < ty.stackWidth - 1; ++i) {
|
|
306
|
-
result.push({ type: 'null' });
|
|
307
|
-
}
|
|
308
|
-
result.push({ type: 'int', value: 0n });
|
|
309
|
-
} else {
|
|
310
|
-
checkIsObjectWithProperty(fieldPath, ty, v, '$');
|
|
311
|
-
|
|
312
|
-
const activeVariant = variants.find(variant => v.$ === variant.labelStr);
|
|
313
|
-
if (!activeVariant) {
|
|
314
|
-
throwInvalidInput(fieldPath, ty, `non-existing union variant for $ = '${v.$}'`);
|
|
315
|
-
}
|
|
316
|
-
if (activeVariant.hasValueField && !v.hasOwnProperty('value')) {
|
|
317
|
-
throwInvalidInput(fieldPath, ty, `expected {$,value} but field 'value' not provided`);
|
|
318
|
-
}
|
|
319
|
-
for (let i = 0; i < ty.stackWidth - 1 - activeVariant.stackWidth; ++i) {
|
|
320
|
-
result.push({ type: 'null' });
|
|
321
|
-
}
|
|
322
|
-
let actualValue = activeVariant.hasValueField ? v.value : v;
|
|
323
|
-
result.push(...dynamicConstruct(ctx, `${fieldPath}#${activeVariant.labelStr}`, activeVariant.variantTy, actualValue));
|
|
324
|
-
result.push({ type: 'int', value: BigInt(activeVariant.stackTypeId) });
|
|
325
|
-
}
|
|
326
|
-
return result;
|
|
327
|
-
}
|
|
328
|
-
case 'genericT': throw new Error(`unexpected genericT=${ty.nameT} at ${fieldPath}`);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// Parse `ty` from a TVM tuple on a stack, returned as a result of a get method invocation.
|
|
333
|
-
// Parameter `fieldPath` is used for error messages only, e.g. when can't deserialize CellRef<T>.
|
|
334
|
-
function dynamicParse(ctx: DynamicCtx, r: StackReader, fieldPath: string, ty: Ty, unTupleIfW = false): any {
|
|
335
|
-
if (unTupleIfW) { // inside `array<T>` or `[T, ...]`, if T is non-primitive, it's a sub-tuple
|
|
336
|
-
let wOnStack = calcWidthOnStack(ctx.symbols, ty);
|
|
337
|
-
if (wOnStack !== 1) {
|
|
338
|
-
return r.readTuple(wOnStack, (r) => dynamicParse(ctx, r, fieldPath, ty, false));
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
switch (ty.kind) {
|
|
343
|
-
case 'int':
|
|
344
|
-
case 'intN':
|
|
345
|
-
case 'uintN':
|
|
346
|
-
case 'varintN':
|
|
347
|
-
case 'varuintN':
|
|
348
|
-
case 'coins': return r.readBigInt();
|
|
349
|
-
case 'bool': return r.readBoolean();
|
|
350
|
-
case 'cell': return r.readCell();
|
|
351
|
-
case 'builder': return r.readBuilder();
|
|
352
|
-
case 'slice': return r.readSlice();
|
|
353
|
-
case 'string': return r.readSnakeString();
|
|
354
|
-
case 'remaining': return r.readSlice();
|
|
355
|
-
case 'address': return r.readSlice().loadAddress();
|
|
356
|
-
case 'addressOpt': return dynamicParse(ctx, r, fieldPath, { kind: 'nullable', inner: { kind: 'address' } });
|
|
357
|
-
case 'addressExt': return r.readSlice().loadExternalAddress();
|
|
358
|
-
case 'addressAny': return dynamicUnpack(ctx, fieldPath, ty, r.readSlice());
|
|
359
|
-
case 'bitsN': return r.readSlice();
|
|
360
|
-
case 'nullLiteral': return r.readNullLiteral();
|
|
361
|
-
case 'callable': throw new NotSupportedTypeOnStack(ty, fieldPath);
|
|
362
|
-
case 'void': return void 0;
|
|
363
|
-
case 'unknown': return r.readUnknown();
|
|
364
|
-
case 'nullable': {
|
|
365
|
-
if (ty.stackTypeId) {
|
|
366
|
-
return r.readWideNullable(ty.stackWidth!, (r) => dynamicParse(ctx, r, fieldPath, ty.inner));
|
|
367
|
-
}
|
|
368
|
-
return r.readNullable((r) => dynamicParse(ctx, r, fieldPath, ty.inner));
|
|
369
|
-
}
|
|
370
|
-
case 'cellOf': return r.readCellRef((s) => dynamicUnpack(ctx, fieldPath, ty.inner, s));
|
|
371
|
-
case 'arrayOf': return r.readArrayOf((r) => dynamicParse(ctx, r, fieldPath, ty.inner, true));
|
|
372
|
-
case 'lispListOf': return r.readLispListOf((r) => dynamicParse(ctx, r, fieldPath, ty.inner, true));
|
|
373
|
-
case 'tensor': {
|
|
374
|
-
let result = [];
|
|
375
|
-
for (let i = 0; i < ty.items.length; ++i) {
|
|
376
|
-
result.push(dynamicParse(ctx, r, `${fieldPath}[${i}]`, ty.items[i]));
|
|
377
|
-
}
|
|
378
|
-
return result;
|
|
379
|
-
}
|
|
380
|
-
case 'shapedTuple': {
|
|
381
|
-
return r.readTuple(ty.items.length, (r) => {
|
|
382
|
-
let result = [];
|
|
383
|
-
for (let i = 0; i < ty.items.length; ++i) {
|
|
384
|
-
result.push(dynamicParse(ctx, r, `${fieldPath}[${i}]`, ty.items[i], true));
|
|
385
|
-
}
|
|
386
|
-
return result;
|
|
387
|
-
});
|
|
388
|
-
}
|
|
389
|
-
case 'mapKV': {
|
|
390
|
-
let dictKey = createTonCoreDictionaryKey(fieldPath, ty.k);
|
|
391
|
-
let dictValue = createTonCoreDictionaryValue(ctx, fieldPath, ty.v);
|
|
392
|
-
return r.readDictionary(dictKey, dictValue);
|
|
393
|
-
}
|
|
394
|
-
case 'EnumRef': return r.readBigInt();
|
|
395
|
-
case 'StructRef': {
|
|
396
|
-
const structRef = ctx.symbols.getStruct(ty.structName);
|
|
397
|
-
let result = { $: ty.structName } as Record<string, any>;
|
|
398
|
-
for (let f of structRef.fields) {
|
|
399
|
-
const fTy = ty.typeArgs ? instantiateGenerics(f.ty, structRef.typeParams, ty.typeArgs) : f.ty;
|
|
400
|
-
result[f.name] = dynamicParse(ctx, r, `${fieldPath}.${f.name}`, fTy);
|
|
401
|
-
}
|
|
402
|
-
return result;
|
|
403
|
-
}
|
|
404
|
-
case 'AliasRef': {
|
|
405
|
-
const aliasRef = ctx.symbols.getAlias(ty.aliasName);
|
|
406
|
-
const targetTy = ty.typeArgs ? instantiateGenerics(aliasRef.targetTy, aliasRef.typeParams, ty.typeArgs) : aliasRef.targetTy;
|
|
407
|
-
return dynamicParse(ctx, r, fieldPath, targetTy);
|
|
408
|
-
}
|
|
409
|
-
case 'genericT': throw new Error(`unexpected genericT=${ty.nameT} at ${fieldPath}`);
|
|
410
|
-
case 'union': {
|
|
411
|
-
const variants = createLabelsForUnion(ctx.symbols, ty.variants);
|
|
412
|
-
const infoForTypeId = {} as Record<number, [number, string | null, (r: StackReader) => any]>;
|
|
413
|
-
for (let v of variants) {
|
|
414
|
-
infoForTypeId[v.stackTypeId] = [v.stackWidth, v.hasValueField ? v.labelStr : null,
|
|
415
|
-
(r: StackReader) => dynamicParse(ctx, r, `${fieldPath}#${v.labelStr}`, v.variantTy)
|
|
416
|
-
];
|
|
417
|
-
}
|
|
418
|
-
return r.readUnionType(ty.stackWidth, infoForTypeId);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
/**
|
|
425
|
-
* Pack any `value` of type `ty` to a TVM tuple.
|
|
426
|
-
* This tuple can be used as a get method argument or debug-printed as human-readable.
|
|
427
|
-
*/
|
|
428
|
-
export function makeTvmTupleDynamic(ctx: DynamicCtx, ty: Ty, value: any): c.TupleItem[] {
|
|
429
|
-
return dynamicConstruct(ctx, 'value', ty, value);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* Invoke any get method taking plain JS variables as arguments and interpreting the resulting TVM tuple according to ABI.
|
|
434
|
-
* Example: `get fun intAndPoint(i: int, p: Point): Point`.
|
|
435
|
-
* Call: `callGetMethodDynamic(provider, ctx, 'intAndPoint', [num, {x: num, y: num}])` returns `{x: num, y: num}`.
|
|
436
|
-
* When input is incorrect (e.g. missing property in a JS object), throws InvalidDynamicInput.
|
|
437
|
-
*/
|
|
438
|
-
export async function callGetMethodDynamic(provider: c.ContractProvider, ctx: DynamicCtx, getMethodName: string, args: any[]): Promise<any> {
|
|
439
|
-
const getM = ctx.findGetMethod(getMethodName);
|
|
440
|
-
if (getM == null) {
|
|
441
|
-
throw new CantCallGetMethodDynamic(getMethodName, `method not found in contract ${ctx.contractName}`);
|
|
442
|
-
}
|
|
443
|
-
if (getM.parameters.length !== args.length) { // default parameters not supported, dynamic invocation should provide all
|
|
444
|
-
throw new CantCallGetMethodDynamic(getMethodName, `expected ${getM.parameters.length} arguments, got ${args.length}`);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
const stackIn: c.TupleItem[] = [];
|
|
448
|
-
for (let i = 0; i < args.length; ++i) {
|
|
449
|
-
stackIn.push(...dynamicConstruct(ctx, getM.parameters[i].name, getM.parameters[i].ty, args[i]));
|
|
450
|
-
}
|
|
451
|
-
const expectedSlotsOut = calcWidthOnStack(ctx.symbols, getM.returnTy);
|
|
452
|
-
const r = StackReader.fromGetMethod(expectedSlotsOut, await provider.get(getMethodName, stackIn));
|
|
453
|
-
return dynamicParse(ctx, r, 'result', getM.returnTy);
|
|
454
|
-
}
|