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